0

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"

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
Sibendu
  • 49
  • 7

5 Answers5

3

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.

Hoopje
  • 12,677
  • 8
  • 34
  • 50
1

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.

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
0

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.

Gosha U.
  • 623
  • 1
  • 4
  • 16
  • Some generic information is available where the compiler would need it to check you code, e.g. field, method parameters, method return type, super classes and interfaces. It is not available via the object unless it is indirectly via one of the means mentioned. – Peter Lawrey Mar 15 '16 at 09:33
  • 1
    @PeterLawrey You are maybe right, but it's often hard to understand the applicability borders of that things anyway. Did you mean something like this? http://stackoverflow.com/a/3403976/1240328 – Gosha U. Mar 15 '16 at 10:05
  • Yes, information in code is available via reflection. However, there is no additional information in an instance. – Peter Lawrey Mar 15 '16 at 10:12
0

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.

George T
  • 44
  • 4
0

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

They explain the "erasure mechanism".

Community
  • 1
  • 1
nukie
  • 691
  • 7
  • 14