Ramanlfc
Ramanlfc

Reputation: 8354

Generics type erasure in Java

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

Answers (5)

Ramanlfc
Ramanlfc

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

sdgfsdh
sdgfsdh

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

Peter Perh&#225;č
Peter Perh&#225;č

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

mezzodrinker
mezzodrinker

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

Elliott Frisch
Elliott Frisch

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

Related Questions