簡體   English   中英

類型擦除如何在java中使用通配符?

[英]How type erasure works for wildcard in java?

如javadoc中所述,

如果類型參數是無界的,則將泛型類型中的所有類型參數替換為其邊界或對象。 因此,生成的字節碼僅包含普通的類,接口和方法。

如有必要,插入類型鑄件以保持類型安全。

我理解上面兩點使用javac處理類型參數,如T<K, V>

但對於以下方法中的外卡,

public static void printList(List<?> list) {
    for (Object elem: list)
        System.out.print(elem + " ");
    System.out.println();
}    

public void sumOfNumbers(List<? extends Number> numbers){
        double d = 0.0;
        for(Number n: numbers){
            d += n.doubleValue();
        }
        System.out.println(d);
    }

如果是外卡,

1)

javac如何處理這些通配符? 它取代了什么嗎?

2)

如何進行類型轉換?

? Object替換(因為它沒有綁定) - 沒有那么有用。
在構建時,編譯器將檢查您是否只調用Object的行為。

? extends Number ? extends Number被其綁定的Number替換。
在構建時,編譯器將檢查您是僅傳遞Number或其任何子類型作為參數。

鑄造 - 無鑄造。 在構建時,編譯器將檢查您是否只調用Number允許的行為。

T將替換為您為類的類型參數提供的任何類型。
在構建時,編譯器將檢查您是否僅傳遞類型T作為參數(在方法中使用T作為參數)。

? T有不同的用途。
想想T的泛型類型(類,接口)創建 - 然后可以在類型中的任何地方引用它。

? 作為一種限制類型的方法,您可以在編譯時合法地調用方法。

通配符僅在編譯時與命名類型參數不同,因為編譯器將嘗試使用相同的命名參數強制執行這些類型確實是相同的。

但是如果你看一下這個源代碼:

import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void foo(List<? extends Number> first, List<? extends Number> second) {
        Number n = first.get( 0 );
        Number m = second.get( 0 );
        List<Number> third = new ArrayList<Number>();
        third.add( n );
        third.add( m );
        System.out.println( third );
    }  

    public static <T extends Number> void bar(List<T> first, List<T> second) {
        T n = first.get( 0 );
        T m = second.get( 0 );
        List<T> third = new ArrayList<T>();
        third.add( n );
        third.add( m );
        System.out.println( third );
    }
}

...和反編譯的字節碼:

Compiled from "Test.java"
public class Test {
  public Test();
    Code:

  public static void foo(java.util.List<? extends java.lang.Number>, java.util.L
ist<? extends java.lang.Number>);
    Code:
       0: aload_0
       1: iconst_0
       2: invokeinterface #2,  2            // InterfaceMethod java/util/List.ge
t:(I)Ljava/lang/Object;
       7: checkcast     #3                  // class java/lang/Number
      10: astore_2
      11: aload_1
      12: iconst_0
      13: invokeinterface #2,  2            // InterfaceMethod java/util/List.ge
t:(I)Ljava/lang/Object;
      18: checkcast     #3                  // class java/lang/Number
      21: astore_3
      22: new           #4                  // class java/util/ArrayList
      25: dup
      26: invokespecial #5                  // Method java/util/ArrayList."<init
>":()V
      29: astore        4
      31: aload         4
      33: aload_2
      34: invokeinterface #6,  2            // InterfaceMethod java/util/List.ad
d:(Ljava/lang/Object;)Z
      39: pop
      40: aload         4
      42: aload_3
      43: invokeinterface #6,  2            // InterfaceMethod java/util/List.ad
d:(Ljava/lang/Object;)Z
      48: pop
      49: getstatic     #7                  // Field java/lang/System.out:Ljava/
io/PrintStream;
      52: aload         4
      54: invokevirtual #8                  // Method java/io/PrintStream.printl
n:(Ljava/lang/Object;)V
      57: return

  public static <T extends java.lang.Number> void bar(java.util.List<T>, java.ut
il.List<T>);
    Code:
       0: aload_0
       1: iconst_0
       2: invokeinterface #2,  2            // InterfaceMethod java/util/List.ge
t:(I)Ljava/lang/Object;
       7: checkcast     #3                  // class java/lang/Number
      10: astore_2
      11: aload_1
      12: iconst_0
      13: invokeinterface #2,  2            // InterfaceMethod java/util/List.ge
t:(I)Ljava/lang/Object;
      18: checkcast     #3                  // class java/lang/Number
      21: astore_3
      22: new           #4                  // class java/util/ArrayList
      25: dup
      26: invokespecial #5                  // Method java/util/ArrayList."<init
>":()V
      29: astore        4
      31: aload         4
      33: aload_2
      34: invokeinterface #6,  2            // InterfaceMethod java/util/List.ad
d:(Ljava/lang/Object;)Z
      39: pop
      40: aload         4
      42: aload_3
      43: invokeinterface #6,  2            // InterfaceMethod java/util/List.ad
d:(Ljava/lang/Object;)Z
      48: pop
      49: getstatic     #7                  // Field java/lang/System.out:Ljava/
io/PrintStream;
      52: aload         4
      54: invokevirtual #8                  // Method java/io/PrintStream.printl
n:(Ljava/lang/Object;)V
      57: return
}

...你可以看到在兩種方法中使用相同的checkcast #3操作碼,只檢查從列表中檢索的值是否可以checkcast #3Number ,但如果它們屬於同一類型則不能。

當你考慮它時,由於類型擦除,這種檢查通常是不可能的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM