通用方法中的类型推断&泛类

时间:2014-10-11 12:26:52

标签: java generics

无法理解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{}

1 个答案:

答案 0 :(得分:2)

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

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

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

  • Cls被编译为p.name.getClass(),这将创建一个类强制转换异常。
  • ((Cls)p.name).getClass()指定非通用的类型约束(test2())。因此,对extends Cls的调用同样会转换为p.name.getClass()

另一方面:

  • ((Cls)p.name).getClass()实际上与System.out.println(p.name)相同,因为System.out.println((Object)p.name)是一种采用println的非泛型方法。
  • object类似。因为运行时实际上并不知道test1(p.name)是什么类型,所以它基本上将T强制转换为p.name,然后再调用Object

换句话说,这是你实际编译的代码:

getClass()