Having trouble understanding generic programming in 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 . Generics in Java are purely there to help developers at compile-time.
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
. E
does not exist at runtime, as far as the P<E>
class is concerned. name
is just an Object
reference that has a Date
inside. 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.
p.name.getClass()
gets compiled as ((Cls)p.name).getClass()
, which will create a class cast exception. test2()
specifies a type constraint that is not generic ( extends Cls
). So its call to p.name.getClass()
likewise is translated to ((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
. test1(p.name)
is similar. Because the runtime doesn't actually know what type T
is, it basically casts p.name
as Object
before calling getClass()
on it. 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());
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.