亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

選角時的曖昧行為

選角時的曖昧行為

慕蓋茨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 中進行強制轉換?!癷nt”基元類型導致無效的強制轉換


第三個代碼:


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 關注
  • 152 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號