分享
三行代码  ›  专栏  ›  技术社区  ›  Changda Li

当类型参数用于铸造时,Java类型擦除是如何工作的? - How does Java type erasure work when the type parameter is used for casting?

  •  0
  • Changda Li  · 技术社区  · 4 周前

    我知道通常未绑定的类型参数被替换为 Object 在编译时。但是这段代码是如何工作的呢?

    <T> void call(List<T> list, Object o) {
        fun((T) o);
    }
    

    它会被编译成

    void call(List list, Object o) {
        fun((Object) o);
    }
    

    这似乎是个错误的案子,因为 o 是否应强制转换为与列表中的元素相同的类型?

    2 回复  |  直到 4 周前
        1
  •  1
  •   Andronicus Ismailawa    4 周前

    不,因为类型信息仅在运行时在Java中可用,因此它不会编译到比 Object . 另一种情况是,如果类型参数 T 已绑定,例如:

     <T extends Number> void call(List<T> list, Object o) {
         fun((T) o);
     }
    

    然后编译器在编译时不知道确切的类型,但它知道它是 Number ,所以如果方法 fun 消耗 作为参数,它将与第一个示例相反地编译。

    你可以找到更多的信息 here .

        2
  •  2
  •   prayagupd    4 周前

    因为类型擦除,即使您的类型是 A ,它将被视为 Object 在你的例子中,如你所料。也就是说如果你通过了除 ,它实际上将被铸造到 对象 .

    例子,

    import java.util.ArrayList;
    import java.util.List;
    
    public class TypeErasure {
    
        static <A> void call(List<A> list, Object elem) {
            A o1 = (A) elem;
            System.out.println(o1);
        }
    
        static void callV2(List list, Object elem) {
            System.out.println(elem);
        }
    
        //bounded type
        static <A extends Number> void callV3(List<A> list, Object elem) {
            A o1 = (A) elem;
            System.out.println(o1);
        }
    
        public static void main(String[] args) {
            call(new ArrayList<Integer>(), "trying to cast string to Integer");
            callV2(new ArrayList<Integer>(), "trying to cast string to Integer");
    
            //will be casted to Number
            callV3(new ArrayList<Integer>(), 1);
            callV3(new ArrayList<Double>(), 1.5);
            callV3(new ArrayList<Long>(), 1L);
    
            // following will fail at runtime with ClassCastException
            /* Exception in thread "main" java.lang.ClassCastException: 
               class java.lang.String cannot be cast to class java.lang.Number 
              (java.lang.String and java.lang.Number are in 
               module java.base of loader 'bootstrap')
            */
            callV3(new ArrayList<Integer>(), "trying to cast string to Integer");
        }
    
    }
    
        3
  •  0
  •   Andy Turner    4 周前

    它会被编译成

    不,如果绑定是 Object 因为一个演员 物体 总是成功的。

    如果类型变量是有界的,例如。 T extends Number 然后 checkcast 将插入说明以确保 o 是一个 Number ,相当于 (Number) o .

    您可能会注意到编译器在该行上生成一个未经检查的警告。未选中的警告意味着编译器无法插入字节码以确保 o T ,具体来说。


    还值得指出的是,类型变量是多余的。您可以使用以下内容,并且它将是等效的:

    void call(List<?> list, Object o) {
        fun(o);
    }
    

    这个演员没有必要,因为 fun 必须能够接受任何 物体 不管怎样。