cim*_*ine 128 java generics reflection
是否可以获得通用参数的类型?
一个例子:
public final class Voodoo {
public static void chill(List<?> aListWithTypeSpiderMan) {
// Here I'd like to get the Class-Object 'SpiderMan'
Class typeOfTheList = ???;
}
public static void main(String... args) {
chill(new ArrayList<SpiderMan>());
}
}
Run Code Online (Sandbox Code Playgroud)
Der*_*ike 149
一个构造,我曾经偶然发现,看起来像
Class<T> persistentClass = (Class<T>)
((ParameterizedType)getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
Run Code Online (Sandbox Code Playgroud)
所以似乎有一些反思 - 魔术,我不幸完全不理解......抱歉.
Mar*_*nna 127
我想试着打破@DerMike的答案来解释:
首先,类型擦除并不意味着JDK 在运行时消除了类型信息.它是一种允许编译时类型检查和运行时类型兼容性以同一种语言共存的方法.正如这段代码所暗示的那样,JDK保留了已删除的类型信息 - 它与被检查的强制转换和东西无关.
其次,这为通用类提供了通用类型信息,与通用类型参数的层次结构完全相同 - 即具有泛型类型参数的抽象父类可以找到与其类型参数对应的具体类型,以便具体实现自身即直接从它继承.如果这个类是非抽象的并且被实例化,或者具体的实现是两个级别,那么这将不起作用(虽然一点点jimmying可以使它适用于超过一个或最低级别的任何预定数量的级别使用X泛型类型参数,等等.
无论如何,关于解释.这里是代码,分为行以便于参考:
1# Class genericParameter0OfThisClass = 2# (Class) 3# ((ParameterizedType) 4# getClass() 5# .getGenericSuperclass()) 6# .getActualTypeArguments()[0];
让'us'成为包含此代码的泛型类型的抽象类.从内到外阅读:
......那就是它.因此,我们将类型信息从我们自己的具体实现推送回自己,并使用它来访问类句柄.我们可以加倍getGenericSuperclass()并进入两个级别,或者消除getGenericSuperclass()并为自己获取值作为具体类型(警告:我还没有测试过这些场景,它们还没有找到我).
如果你的具体孩子是一个任意数量的跳跃,或者你是具体的而不是最终的,如果你期望你的(可变深度)孩子有自己的仿制品,那就太麻烦了.但是你通常可以围绕这些考虑因素进行设计,因此这可以帮助你完成大部分工作.
希望这有助于某人!我认识到这篇文章很古老.我可能会剪断这个解释并保留其他问题.
And*_*nov 20
实际上我让这个工作.请考虑以下代码段:
Method m;
Type[] genericParameterTypes = m.getGenericParameterTypes();
for (int i = 0; i < genericParameterTypes.length; i++) {
if( genericParameterTypes[i] instanceof ParameterizedType ) {
Type[] parameters = ((ParameterizedType)genericParameterTypes[i]).getActualTypeArguments();
//parameters[0] contains java.lang.String for method like "method(List<String> value)"
}
}
Run Code Online (Sandbox Code Playgroud)
我正在使用jdk 1.6
Yan*_*euc 16
实际上有一个解决方案,通过应用"匿名类"技巧和超级类型标记的想法:
public final class Voodoo {
public static void chill(final List<?> aListWithSomeType) {
// Here I'd like to get the Class-Object 'SpiderMan'
System.out.println(aListWithSomeType.getClass().getGenericSuperclass());
System.out.println(((ParameterizedType) aListWithSomeType
.getClass()
.getGenericSuperclass()).getActualTypeArguments()[0]);
}
public static void main(String... args) {
chill(new ArrayList<SpiderMan>() {});
}
}
class SpiderMan {
}
Run Code Online (Sandbox Code Playgroud)
诀窍在于创建一个匿名类,new ArrayList<SpiderMan>() {}代替原始(简单)new ArrayList<SpiderMan>().使用anoymous类(如果可能)可确保编译器保留有关type参数SpiderMan的类型参数的信息List<?>.沃利亚!
由于类型擦除,知道列表类型的唯一方法是将类型作为参数传递给方法:
public class Main {
public static void main(String[] args) {
doStuff(new LinkedList<String>(), String.class);
}
public static <E> void doStuff(List<E> list, Class<E> clazz) {
}
}
Run Code Online (Sandbox Code Playgroud)
不,这是不可能的.由于向下兼容性问题,Java的泛型基于类型擦除,即在运行时,您拥有的只是非泛型List对象.在运行时有一些关于类型参数的信息,但它存在于类定义中(即,您可以询问" 该字段的定义使用哪种泛型类型? "),而不是在对象实例中.
@ DerMike的答案附录获取参数化接口的泛型参数(在Java-8默认方法中使用#getGenericInterfaces()方法以避免重复):
import java.lang.reflect.ParameterizedType;
public class ParametrizedStuff {
@SuppressWarnings("unchecked")
interface Awesomable<T> {
default Class<T> parameterizedType() {
return (Class<T>) ((ParameterizedType)
this.getClass().getGenericInterfaces()[0])
.getActualTypeArguments()[0];
}
}
static class Beer {};
static class EstrellaGalicia implements Awesomable<Beer> {};
public static void main(String[] args) {
System.out.println("Type is: " + new EstrellaGalicia().parameterizedType());
// --> Type is: ParameterizedStuff$Beer
}
Run Code Online (Sandbox Code Playgroud)
正如@bertolami指出的那样,我们不可能使用变量类型并获得其未来值(typeOfList变量的内容).
不过,您可以将类作为参数传递给它,如下所示:
public final class voodoo {
public static void chill(List<T> aListWithTypeSpiderMan, Class<T> clazz) {
// Here I'd like to get the Class-Object 'SpiderMan'
Class typeOfTheList = clazz;
}
public static void main(String... args) {
chill(new List<SpiderMan>(), Spiderman.class );
}
}
Run Code Online (Sandbox Code Playgroud)
当你必须将一个类变量传递给ActivityInstrumentationTestCase2的构造函数时,这或多或少都是Google所做的.
| 归档时间: |
|
| 查看次数: |
160457 次 |
| 最近记录: |