Sibendu
Sibendu

Reputation: 49

Java generics and reflection(jenkov blog)

While going through some Jakov Jenkov blogs on java reflection and generics , I found the following paragraph:

When runtime inspecting a parameterizable type itself, like java.util.List, there is no way of knowing what type is has been parameterized to. This makes sense since the type can be parameterized to all kinds of types in the same application. But, when you inspect the method or field that declares the use of a parameterized type, you can see at runtime what type the paramerizable type was parameterized to.

Can anyone please elaborate on the paragraph?

I got confused by the statement "when runtime inspecting a parameterizable type itself"

Upvotes: 0

Views: 199

Answers (5)

Hoopje
Hoopje

Reputation: 12932

Consider the following small program:

import java.util.ArrayList;

class MyClass {
    ArrayList<String> stringList;

    public ArrayList<String> getStringList() {
        return stringList;
    }
}

public class Foo {
    public static void main(String... args) throws NoSuchMethodException {
        ArrayList<Integer> intList = new ArrayList<>();
        System.out.println(intList.getClass().toGenericString());  
        System.out.println(MyClass.class.getMethod("getStringList").toGenericString());
    }
}

The output of this program is:

public class java.util.ArrayList<E>
public java.util.ArrayList<java.lang.String> MyClass.getStringList()

As you see, the fact that intList is an ArrayList<Integer> is not known at run-time, but the fact that MyClass.getStringList() returns an ArrayList<String> is.

The reason is, that all ArrayList instances (some of which may be ArrayList<Integer>s and others ArrayList<String>s) share the same Class object:

ArrayList<String> stringList = new ArrayList<>();
ArrayList<Integer> intList = new ArrayList<>();
System.out.println(stringList.getClass() == intList.getClass());

would output true. So intList.getClass() cannot know anything about the type parameters of the object.

On the other hand, the object returned by MyClass.getStringList() is always a string list, and this information can be seen at run-time.

Upvotes: 3

Tagir Valeev
Tagir Valeev

Reputation: 100179

Consider that you have the following class:

public class ReflectionTest {
    List<Integer> list1 = new ArrayList<>();
    List<String> list2 = new ArrayList<>();
}

Inspecting the parameterized type itself means inspecting list1.getClass() or list2.getClass(). They are absolutely indistinguishable:

System.out.println(list1.getClass() == list2.getClass());
// prints true

All instances of ArrayList are instances of the same class regardless of parameterization, so having just list1.getClass() or list2.getClass() you have no way to determine whether it was parameterized with Integer or String.

However if you have direct access to the field, you can do it:

System.out.println(ReflectionTest.class.getDeclaredField("list1").getGenericType());
// prints java.util.List<java.lang.Integer>
System.out.println(ReflectionTest.class.getDeclaredField("list2").getGenericType());
// prints java.util.List<java.lang.String>

Because here you're accessing the field itself and actual parameterization is stored in the class file together with the field declaration. The same is possible if you inspect the method parameter or return value: it's actual generic signature is also stored in the class file along with erased signature.

Upvotes: 1

nukie
nukie

Reputation: 681

Please refer to those articles: this one and another one and one more.

They explain the "erasure mechanism".

Upvotes: 0

George T
George T

Reputation: 44

In simple words it just states that the list doesn't know what type of data it holds and doesn't care. Your program will find out what type it is at runtime when you invoke a method to it.

Upvotes: 0

Gosha U.
Gosha U.

Reputation: 623

The generics in java is a compile time thing. There are no ways to get any information of generics types in runtime, but the non-null objects contain information about their types.

So, if you have a method, that takes the List<T> and the list is not empty, you can make something like that:

if (list.get(0) instanceOf X) { // ... }

If you read some java code with generics, you'll found many methods like that:

<T> T getSomething(Class<T> aClass);

The reason, why some object, carrying the type is required, is that there is no such thing as generic types in runtime at all.

Upvotes: 0

Related Questions