java – 泛型方法和泛型类中的类型推断

无法理解
Java中的泛型编程.

我读了一些关于它的教程,但仍然很困惑,特别是当事情变得复杂时.

谁能解释一下这个例子中发生了什么?

import java.util.Date;

public class Test1 {

    public static void main(String[] args) {
        P<Cls> p = new P<>();   //<1>   //I expect a ClassCastException here, but no. Why? //How does the type inference for class P<E> work? 
        System.out.println(p.name); //it prints
//      System.out.println(p.name.getClass());//but this line throws ClassCastException //why here? why not line <1>?

        test1(p);//it runs
//      test2(p);//throws ClassCastException//What is going on in method test1&test2? 
                //How does the type inference for generic methods work in this case?
        }


    public static<T> void test1(P<? extends T> k){
        System.out.println(k.name.getClass());
    }

    public static<T extends Cls> void test2(P<? extends T> k){
        System.out.println(k.name.getClass());
    }
}

class P<E>{
    E name = (E)new Date();//<2>
}

class Cls{}

最佳答案

P<Cls> p = new P<>();

请记住,Java通过擦除来实现泛型,这意味着P的构造函数实际上并不知道E在运行时是什么. Java中的泛型纯粹是为了在编译时帮助开发人员.

这意味着当你创建一个新的P<>()时,会创建一个新的Date(),但它实际上并没有转换为任何特定的类型,因为运行时对E没有任何了解.E不存在在运行时,就P< E>而言.上课而言. name只是一个内部有Date的Object引用.但是,每当您编写以运行时环境需要知道它是特定类型(在本例中为Cls)的方式使用name的代码时,编译器会在不告诉您的情况下将强制转换插入该类型.

> p.name.getClass()被编译为((Cls)p.name).getClass(),它将创建一个类强制转换异常.
> test2()指定非泛型的类型约束(扩展Cls).因此,它对p.name.getClass()的调用同样被转换为((Cls)p.name).getClass().

另一方面:

> System.out.println(p.name)实际上与System.out.println((Object)p.name)相同,因为println是一个采用对象的非泛型方法.
> test1(p.name)类似.因为运行时实际上并不知道T是什么类型,所以它在调用getClass()之前基本上将p.name强制转换为Object.

换句话说,这是你的代码,因为它实际上被编译:

class P{
    Object name = new Date();
}

public static void main(String[] args) {
    P p = new P();   
    System.out.println(p.name);
    System.out.println(((Cls)p.name).getClass());

    test1(p);
    test2(p);
}


public static void test1(P k){
    System.out.println(k.name.getClass());
}

public static void test2(P k){
    System.out.println(((Cls)k.name).getClass());
}
点赞