为了账号安全,请及时绑定邮箱和手机立即绑定

选角时的暧昧行为

选角时的暧昧行为

慕盖茨4494581 2023-07-19 16:07:40
我在教学生老式泛型时,遇到了一个看不见的问题!我在演讲时的行为!:(我有一个简单的课程public class ObjectUtility {  public static void main(String[] args) {    System.out.println(castToType(10,new HashMap<Integer,Integer>()));  }  private static <V,T> T castToType(V value, T type){    return (T) value;  }}这给出的输出为 10,没有任何错误!我期望这会给我一个 ClassCastException,并出现一些错误,例如 Integer Cannot be Cast to HashMap。好奇又愤怒,我尝试了getClass()返回值,如下所示System.out.println(castToType(10,new HashMap<Integer,Integer>()).getClass());正如我所料,它抛出了 ClassCastException 。另外,当我将同一个语句分成两部分时,就像Object o = castToType(10,new HashMap<Integer,Integer>());System.out.println(o.getClass());它不会抛出任何错误并打印class java.lang.Integer全部执行openjdk version "1.7.0_181"OpenJDK Runtime Environment (Zulu 7.23.0.1-macosx) (build 1.7.0_181-b01)OpenJDK 64-Bit Server VM (Zulu 7.23.0.1-macosx) (build 24.181-b01, mixed mode)有人能指出我为什么会发生这种行为的正确方向吗?
查看完整描述

2 回答

?
海绵宝宝撒

TA贡献1809条经验 获得超8个赞

T运行时不存在。它解析为约束的下限。在本例中,没有,因此解析为Object。一切都可以转换为Object,因此没有类转换异常。


如果您要将约束更改为此


private static <V,T extends Map<?,?>> T castToType(V value, T type){

    return (T) value;

}

然后转换为T转换为下界Map,这显然Integer不是,并且您会得到您期望的类转换异常。


另外,当我将同一个语句分成两部分时,就像


Object o = castToType(10,new HashMap<Integer,Integer>());

System.out.println(o.getClass());

它没有抛出任何错误


castToType(10,new HashMap<Integer,Integer>()).getClass() 

这会引发类转换异常,因为它静态链接到方法HashMap::getClass(not Object::getClass),因为签名表示期望HashMap作为返回值。这需要隐式转换,HashMap但会失败,因为在运行时castToType返回 an Integer。


当你第一次使用这个时


Object o = castToType(10,new HashMap<Integer,Integer>());

您现在静态链接,Object::getClass无论实际返回什么,都可以。


“未分割”版本相当于这个


final HashMap<Integer, Integer> map = castToType(10, new HashMap<>());

System.out.println(map.getClass());

希望能证明差异


查看完整回答
反对 回复 2023-07-19
?
catspeake

TA贡献1111条经验 获得超0个赞

您可以使用 javap 工具看到差异。


编译过程默认进行代码优化,将泛型类型更改为原始类型


第一个代码:


public class ObjectUtility {


  public static void main(String[] args) {

    System.out.println(castToType(10,new java.util.HashMap<Integer,Integer>()));

  }


  private static <V,T> T castToType(V value, T type){

    return (T) value;

  }


}

真正的伪代码:


Compiled from "ObjectUtility.java"

public class ObjectUtility {

  public ObjectUtility();

    descriptor: ()V

    Code:

       0: aload_0

       1: invokespecial #1                  // Method java/lang/Object."<init>":()V

       4: return

    LineNumberTable:

      line 1: 0


  public static void main(java.lang.String[]);

    descriptor: ([Ljava/lang/String;)V

    Code:

       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;

       3: bipush        10

       5: invokestatic  #3                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

       8: new           #4                  // class java/util/HashMap

      11: dup

      12: invokespecial #5                  // Method java/util/HashMap."<init>":()V

      15: invokestatic  #6                  // Method castToType:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

      18: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V

      21: return

    LineNumberTable:

      line 4: 0

      line 5: 21


  private static <V, T> T castToType(V, T);

    descriptor: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

    Code:

       0: aload_0

       1: areturn

    LineNumberTable:

      line 8: 0

}

通用类型的调用更改为对象,并在系统输出中添加 Integer.valueOf。


第二个代码:


public class ObjectUtility {


  public static void main(String[] args) {

    System.out.println(castToType(10,new java.util.HashMap<Integer,Integer>()).getClass());

  }


  private static <V,T> T castToType(V value, T type){

    return (T) value;

  }


}

真正的伪代码:


Compiled from "ObjectUtility.java"

public class ObjectUtility {

  public ObjectUtility();

    descriptor: ()V

    Code:

       0: aload_0

       1: invokespecial #1                  // Method java/lang/Object."<init>":()V

       4: return

    LineNumberTable:

      line 1: 0


  public static void main(java.lang.String[]);

    descriptor: ([Ljava/lang/String;)V

    Code:

       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;

       3: bipush        10

       5: invokestatic  #3                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

       8: new           #4                  // class java/util/HashMap

      11: dup

      12: invokespecial #5                  // Method java/util/HashMap."<init>":()V

      15: invokestatic  #6                  // Method castToType:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

      18: checkcast     #4                  // class java/util/HashMap

      21: invokevirtual #7                  // Method java/lang/Object.getClass:()Ljava/lang/Class;

      24: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V

      27: return

    LineNumberTable:

      line 4: 0

      line 5: 27


  private static <V, T> T castToType(V, T);

    descriptor: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

    Code:

       0: aload_0

       1: areturn

    LineNumberTable:

      line 8: 0

}

checkcast 通过 HashMap 调用,但签名更改为 Object,返回值是 int,没有在castToType 中进行强制转换。“int”基元类型导致无效的强制转换


第三个代码:


public class ObjectUtility {


  public static void main(String[] args) {

    Object o = castToType(10,new java.util.HashMap<Integer,Integer>());

    System.out.println(o.getClass());

  }


  private static <V,T> T castToType(V value, T type){

    return (T) value;

  }


}

真正的伪代码:


Compiled from "ObjectUtility.java"

public class ObjectUtility {

  public ObjectUtility();

    descriptor: ()V

    Code:

       0: aload_0

       1: invokespecial #1                  // Method java/lang/Object."<init>":()V

       4: return

    LineNumberTable:

      line 1: 0


  public static void main(java.lang.String[]);

    descriptor: ([Ljava/lang/String;)V

    Code:

       0: bipush        10

       2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

       5: new           #3                  // class java/util/HashMap

       8: dup

       9: invokespecial #4                  // Method java/util/HashMap."<init>":()V

      12: invokestatic  #5                  // Method castToType:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

      15: astore_1

      16: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;

      19: aload_1

      20: invokevirtual #7                  // Method java/lang/Object.getClass:()Ljava/lang/Class;

      23: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V

      26: return

    LineNumberTable:

      line 4: 0

      line 5: 16

      line 6: 26


  private static <V, T> T castToType(V, T);

    descriptor: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

    Code:

       0: aload_0

       1: areturn

    LineNumberTable:

      line 9: 0

}

在这种情况下,方法与第一种类似。castToType 返回第一个参数而不做任何更改。


正如您所看到的,java 编译器进行了一些“性能”更改,这些更改在某些情况下可能会产生影响。泛型是源代码的“发明”,最终会转换为任何情况下所需的实际类型。


查看完整回答
反对 回复 2023-07-19
  • 2 回答
  • 0 关注
  • 106 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信