Reputation: 8354
Here's the code:
public class Main {
public static void main(String[] args) {
Gen<Integer> g = new Gen<Integer>(5);
System.out.println(g.getClass());
System.out.println(g.ob.getClass());
}
}
class Gen<T> {
T ob;
public Gen(T x) {
ob = x;
}
}
And here's the output
class Gen // This I understand
class java.lang.Integer // But if type erasure is happening, shouldn't this be java.lang.Object?
I get it that Type parameter T
is erased at runtime, but then why is the type parameter of ob
surviving at runtime?
Upvotes: 7
Views: 617
Reputation: 8354
Since my first exposure to generics was with C# , it took time get a hold of what type erasure is in java.
But after better understanding java generics , i realized that in my question i'm mixing 2 separate topics : Generics and Reflection.
The main question was , why did the second call here
System.out.println(g.getClass());
System.out.println(g.ob.getClass());
returned java.lang.Integer
instead of java.lang.Object
.
Looking at the docs for getClass()
, the answer becomes obvious
Returns the runtime class of this Object.
so, getClass()
doesn't return the type of reference but the actual object being referred to by the reference.
For ex :
Object o = "abc";
System.out.println(o.getClass());
The output wouldn't be the type of the reference java.lang.Object
but rather the actual type of the object java.lang.String
.
Upvotes: 0
Reputation: 37121
Nope!
Consider this:
Object x = new Integer(1);
System.out.println(x.toString());
You'll get 1
.
But shouldn't I get Object.toString()?
No. While x
is a reference of type Object
, the actual referent is an Integer
, so at run-time, the Integer
implementation of toString
is called.
It is the same for getClass
.
Upvotes: 4
Reputation: 20792
Because when compiled, class Gen has an Object ob; The generics disappear from the final product. The angle brackets only play a role at compile-time, during static type checking. It's something the compiler can do for you to give you better peace of mind, to assure you that you're using collections and other paramterized types correctly.
the actual object assigned to ob at runtime is an instance of the Integer class, and ob.getClass() serves the purpose to find out the actual class of the object referenced by the pointer -> hence you will see java.lang.Integer printed.
Remember, what comes out is effectively class Gen { Object ob; ... }
Upvotes: 2
Reputation: 988
No matter what type the variable has, the return value of getClass()
depends on the variable's contents. So, since you basically have a variable Object ob
which contains an Integer
(your int
was converted to it at the time you provided it as that constructor's parameter), the output of ob.getClass()
is class java.lang.Integer
.
Also, about your question as to why getClass()
remembers the type argument: it doesn't. All it does is determine the content's class. For example:
class Foo {
public Foo() {}
}
class Bar extends Foo {
public Bar() {}
}
class Baz<T> {
public T object;
public Baz(T object) { this.object = object; }
}
If you now run the following snippet...
public static void main(String... args) {
Baz<Foo> obj = new Baz(new Bar());
System.out.println(obj.object.getClass());
}
You will notice that the output is not class Foo
, it's class Bar
.
Upvotes: 2
Reputation: 201527
Type erasure is happening. Generics are a compile time type checking system. At run-time you still get the class (it is run-time type information). The linked Type erasure documentation says (in part)
Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
Your instance has a type, it's Object
. But an Object
reference can refer to any sub-class (which is every class) in Java. You get the type it refers to.
Upvotes: 2