简体   繁体   English

在泛型方法和泛型类中键入推断

[英]Type inference in generic method & generic class

Having trouble understanding generic programming in Java. 无法理解Java中的泛型编程。

I read some tutorial about it but still quite confused, especially when things get complicated. 我读了一些关于它的教程,但仍然很困惑,特别是当事情变得复杂时。

Can anyone explain what's happening in this example? 谁能解释一下这个例子中发生了什么?

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<>();

Remember that Java implements generics by erasure , meaning that the constructor for P doesn't really have any idea what E is at runtime . 请记住,Java通过擦除来实现泛型,这意味着P的构造函数实际上并不知道E在运行时是什么 Generics in Java are purely there to help developers at compile-time. Java中的泛型纯粹是为了在编译时帮助开发人员。

This means that when you create a new P<>() , a new Date() is created, but it isn't actually cast to any particular type, because the runtime doesn't know anything about E . 这意味着当您创建一个new P<>() ,会创建一个new Date()但它实际上并没有转换为任何特定类型,因为运行时对E没有任何了解 E does not exist at runtime, as far as the P<E> class is concerned. E在运行时不存在,只要P<E>类而言。 name is just an Object reference that has a Date inside. name只是一个内部有DateObject引用。 However, any time you write code that consumes name in a way where the runtime environment needs to know that it's of a particular type ( Cls in this case), the compiler inserts a cast to that type without telling you. 但是,每当您编写以运行时环境需要知道它是特定类型(在本例中为Cls )的方式使用name代码时,编译器会在不告诉您的情况下将强制转换插入该类型。

  • p.name.getClass() gets compiled as ((Cls)p.name).getClass() , which will create a class cast exception. p.name.getClass()被编译为((Cls)p.name).getClass() ,它将创建一个类((Cls)p.name).getClass()异常。
  • test2() specifies a type constraint that is not generic ( extends Cls ). test2()指定非泛型的类型约束( extends Cls )。 So its call to p.name.getClass() likewise is translated to ((Cls)p.name).getClass() . 因此,它对p.name.getClass()调用同样被转换为((Cls)p.name).getClass()

On the other hand: 另一方面:

  • System.out.println(p.name) is actually the same as System.out.println((Object)p.name) because println is a non-generic method that takes an object . System.out.println(p.name)实际上与System.out.println((Object)p.name)相同,因为println是一个采用object的非泛型方法。
  • test1(p.name) is similar. test1(p.name)类似。 Because the runtime doesn't actually know what type T is, it basically casts p.name as Object before calling getClass() on it. 因为运行时实际上并不知道T是什么类型,所以它在调用getClass()之前基本上将p.name强制转换为Object

In other words, here's your code as it actually gets compiled: 换句话说,这是你的代码,因为它实际上被编译:

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());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM