I'm trying to get a class from a generic whose type was defined in the parent class and do it like this:

public class Generic<T> extends Generic1<T> { Object[] objects; int index; public void f1(int size) { this.objects = new Object[size]; Class<T> t = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; try { T value = t.newInstance(); System.out.printf("string " + value); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } System.out.println(t.toString()); } public static void main(String[] args) { Generic<String> g = new Generic<>(); g.f1(3); } } class Generic1<String> { } 

And it seems to me that everything should work. But it falls with the following exception:

Java.lang.ClassCastException in thread "main" Generic.java:26) at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodA.ph.e.ph.e.off.eferaImpl.java:62 at sun.reflect.DelegatingMethodA.ph.e. .lang.reflect.Method.invoke (Method.java:498) at com.intellij.rt.execution.application.AppMain.main (AppMain.java:147)

Help me figure out what I'm missing here? And why ClassCastException ? Help me fix the code to working condition.

  • 2
    You generally can not get it, type erasure. Specifically, in this case, you generally return TypeVariable, which obviously is not a concrete class. - etki
  • one
    Well, firstly, it is not listed here in the superclass. Secondly, you can get it only if the code is compiled with an explicit type indication, which immediately tells you that you can forget about this method, because you have no control over the compilation. This, if I do not change the churning, is possible if some class indicates a generic type affixed to parents (and this may be a lie), but it is possible and not necessary , and it will never cover all cases anyway. Thirdly, your idea of ​​calculating the type in runtime is doomed to failure in advance -> - etki
  • one
    because the type of erasure still shoots, and if you took the first element in the collection, and it has five types in the hierarchy, which one is a generic? - etki
  • one
    You have the parameter T there, not the type - etki
  • one
    @Pavel please give the link to the source code. - Mikhail Vaysman

1 answer 1

The fact was that in the parent class Generic1<T> no type was specified, there must be no class Generic<T> extends Generic1<T> but this is correct: class Generic<T> extends Generic1<String> . Then everything works. And I would like to note that the getActualTypeArguments() method returns an array of all types in the generic parent class, and if there was an example class Generic<T> extends Generic1<String, Integer> then by the zero index would be String and by the first Integer .

 public class Generic<T> extends Generic1<String> { Object[] objects; int index; public void f1(int size) { this.objects = new Object[size]; Class<T> t = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; try { T value = t.newInstance(); System.out.printf("string " + value); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } System.out.println(t.toString()); } public static void main(String[] args) { Generic<String> g = new Generic<>(); g.f1(3); } } class Generic1<String> { }