Given a class with template parameters
Class a<t>
{
}
How do I get the type of T at run time?
In C #, this is simple, and the CLR's reflection mechanism is supported by the interpreter, presumably with the following code:
Namespace testreflect{ class program<t> {public Type Gettclass () { type type= this. GetType (); Type[] TTS = type. GetGenericArguments (); return tts[0];}}
In Java, however, the answer is no, there is no direct way to get t.class in Java. (At least JDK 1.7 was not possible before)
The root cause is that the Java language supports reflection, but the JVM does not support it because the JVM has the "type Erasure" attribute, which is "types erase".
But Java has no way to go, we can still use other methods to achieve our needs.
Method 1. The actual category is passed in through the constructor function. "Some people say that this method is not handsome, but it is undeniable that this method does not use reflection, but the most efficient, the reflection itself is not efficient." 】
public class a<t>{ private final class<t> clazz; Public a<t> (class<t> clazz) { this.clazz = clazz; } Use Clazz on here}
Method 2. By inheriting this class, pass in the actual class that the template T corresponds to: (defined as an abstract class)
Class a<t>{public class Gettclass (int index) { type gentype = GetClass (). Getgenericsuperclass (); &nbs P if (! ( Gentype instanceof Parameterizedtype) { return object.class; } <span style= "White-space:pre" ></span> type[] params = ((Parameterizedtype) gentype). Getactualtypearguments (); <span style= "White-space:pre" ></span> if (index >= params.length | | Index < 0) { <span style= "White-space:pre" ></span> <span style= "White-space:pre" ></span >throw new RuntimeException ("Index Out of Bounds") <span style= "White-space:pre" ></span>} <span style= "White-space:pre" ></span> if (! ( Params[index] instanceof Class)) { <span style= "White-space:pre" ></span> return object.class; <span style= "White-space:pre" ></span>} <span style= "white-sPace:pre "></span> return (Class) Params[index]; }}
Inheriting classes:
public class B extends a<string> {public static void main (string[] args) { b bb =new b (); Bb.gettclass ();//That is the answer}}
I believe a lot of people have used code like this, but not everyone really understands why it is possible to do so.
Just look at the code:
We can
Getgenericsuperclass ();
But not:
Getgenericclass ();
Why is it?
There is a foreigner on the StackOverflow said:in Java If a class inherits another class with a template parameter, the template parameter is not erased by type. In a single class, its generic parameters are erased.
The first explanation is that this assumption is wrong . I believe that JCP will not be baffled by this unreasonable rule. If this argument is true, it is equal to:
public class C<t> {}public class c1<t> extends C<t>{public C1 () {} public class Gettclass (int index) {
type Gentype = GetClass (). Getgenericsuperclass (); if (! ( Gentype instanceof Parameterizedtype) { return object.class; } Type[] params = ((Parameterizedtype) gentype). Getactualtypearguments (); if (Index >= params.length | | Index < 0) { throw new RuntimeException ("Index outof Bounds"); } if (! ( Params[index] instanceof Class) { return object.class; } Return (Class) Params[index]; }}
After you call C1 directly to create the entity:
public static void Main (String[]args) {c1<d> a= new c1<d> (); System.out.println (A.gettclass (0));}
Can output: D
But the reality is, there is no output d, and the output is Object.
It doesn't matter if this is a subclass of the parent class.
So what exactly is the cause, a generic class (a class that contains template parameters) that does not resemble getgenericarguments () in C # What about the Getgenericclass () function?
Then, review the category "Type Erase" in Java.
I define it in my own language (not necessarily accurate, but for the same reason):
All of the generic parameters in Java are erased at compile time in code other than the "class declaration area" (partition below).
public class/interface [class declaration area] classname{[class definition area]}
The following 2 classes:
public class E<t>{public static void Main (String []args) {list<string> a = new arraylist<string> (); System.out.println ("Done");}} Class Sube extends e<string>{}
The compiled class file code is: (by Java De-compiler)
public class e<t>{public static void Main (string[] args) { List a = new ArrayList ();//difference in this line Syst Em.out.println ("Done");} }
Class Sube extends e<string>{}
As you can see, my so-called "class declaration area" is identical to the Java file.
All of the generic parameters in the class definition area are removed.
So why is that?
This involves the Java language features, the JDK starting from 1.5 (should be) to support generics, but only the Java syntax Support generics, the JVM does not support generics, many people laugh to call it "false generics."
In fact, I personally think that this may be the Java language is all objects, and requires a high degree of polymorphism, highly oriented to abstract programming, the characteristics of the weak type foreshadowing.
For example list, since as a set, why should care about its specific elements are consistent, the first to put white, the second to put blacks, the third put yellow people ... This is better.
So when we use
List<string>, the compiler sees not a String, but an object (all types in Java inherit from object).
Once the generic parameter in the class definition area is erased. Then using this template class to create an instance, when run, the JVM reflection is unable to get the specific type of this template.
So
similar to GetGenericArguments () in C # The Getgenericclass () function is meaningless in Java.
The meaningless point here is based on the Java and JVM features described above. (If the JVM supports true generics, then all this will make sense)
Why does he mean nothing to disprove the law:
Assuming this function exists and makes sense, the following code can get T.class
Class A<t>{Public Class Gettclass () { return this.getgenericclasses () [0];//there is only one template parameter } Public static void main (String []args) { a<integer> a= new a<integer> (); System.out.print (A.gettclass ());} }
Such a piece of code will be compiled into:
Class A<t>{Public Class Gettclass () { return this.getgenericclasses () [0];//there is only one template parameter } Public static void main (String []args) { A a= new A (); System.out.print (A.gettclass ());} }
This is the problem, the JVM executes the. class file, not the. java file, and in the JVM's opinion, the class file doesn't say anything about T, and now you're asking me what I need to get you, T.class?
So
Getgenericclasses ()
This function always returns JAVA.LANG.OBJECT. Equals no return.
So there is no need for this function to exist.
To think back, the reason why
Getgenericsuperclass (); Effective, its essence lies in
The class declaration area in the subclass's Java file specifies the true class of T.
Such as:
public class B extends a<integer>{
//...
}
Such a small unsolved case is clear.
[Run-time Get template class type] Java reflection mechanism + type erase mechanism