如何解决创建给定类的Collection的Class对象
是否可以人为地创建ParameterizedType
对象,该对象将是特定指定类型的集合的定义?如果我有一个命名的Collection字段,则可以有正确的定义,即。用于此类课程中的字段
public class MyContainerClass {
List<String> myElementsList;
}
public class GetGenericsTest {
public static class MyContainerClass {
List<String> myElementsList;
}
public static void main(String[] args) throws Exception {
Field field = MyContainerClass.class.getDeclaredField("myElementsList");
ParameterizedType pt = (ParameterizedType) field.getGenericType();
System.out.println("collection type: " + pt.getRawType().getTypeName());
System.out.println("elt type: " + ((Class<?>)pt.getActualTypeArguments()[0]).getName());
}
}
产生:
collection type: java.util.List
elt type: java.lang.String
但是我不知道如何仅通过反射创建这样的ParameterizedType
。
换句话说,我需要一个通用的解决方案,以便以下测试代码能够通过:
Class<?> elementClass = MyElement.class;
ParameterizedType parameterizedType = implementMe(elementClass,List.class);
Assertions.assertEquals(List.class.getName(),parameterizedType.getRawType().getTypeName());
Assertions.assertEquals(elementClass.getName(),((Class<?>)pt.getActualTypeArguments()[0]).getName());
解决方法
这里是implementMe
public class TypeImpl implements Type {
private final Class<?> clazz;
public TypeImpl(Class<?> clazz) {
this.clazz = clazz;
}
@Override
public String getTypeName() {
return clazz.getName();
}
}
public ParameterizedType implementMe(Class<?> elementClass,Class<?> collectionClass) {
return new ParameterizedType() {
@Override
public Type[] getActualTypeArguments() {
return new Type[] {
new TypeImpl(elementClass)
};
}
@Override
public Type getRawType() {
return new TypeImpl(collectionClass);
}
@Override
public Type getOwnerType() {
return null;
}
};
}
测试:
Class<?> elementClass = String.class;
ParameterizedType parameterizedType = implementMe(elementClass,List.class);
System.out.println(List.class.getName().equals(parameterizedType.getRawType().getTypeName()));//true
System.out.println(elementClass.getName().equals(((Class<?>)pt.getActualTypeArguments()[0]).getName()));//true
但是我不知道如何仅通过反射创建这样的
Class
。
您无法创建自己的Class
。这是最后一课,具有私有构造函数。
Class
的Javadoc说
类没有公共构造函数。取而代之的是,Java虚拟机会在加载类时以及通过调用类加载器中的defineClass方法自动构造Class对象。
How to extend a final class?(Reflection,Javassist)
How to extend a final class in Java
Is it possible to extend a final class in Java?
如果您尝试通过反射克服对Class
构造函数的私有访问,您将拥有SecurityException
Class<Class<?>> classClass = (Class<Class<?>>) (Object) Class.class;
Constructor<Class<?>> constructor = classClass.getDeclaredConstructor(ClassLoader.class);
constructor.setAccessible(true);//java.lang.SecurityException: Cannot make a java.lang.Class constructor accessible
Class<?> newClass = constructor.newInstance(this.getClass().getClassLoader());
还请注意,List<String>
和List<Integer>
这两种类型是不同的,但类是相同的List<?>
。因此,您已经有了collectionClass
。
您的问题没有道理。我认为您需要的是简短的泛型简介。
它们是经过编译器检查的注释。
仅此而已。编译器将使用它们生成警告,错误和无提示强制转换。然后,编译器将抛出该信息。一个例外是泛型以可能影响其他源文件中的代码编译的类型出现,因此,在签名中出现的任何类型(字段的类型,您拥有的任何extends
子句或(任何方法参数的类型或任何方法的返回类型)-但这是由编译器通过将此信息写到类文件中作为“注释”来处理的-JVM本身完全忽略了所有这些内容。不在乎一个iota。
您的建议暗示,在编译时,您无能为力。它是动态的。
但是泛型仅在编译时存在。
因此,您想要的东西将完全没有用。因此,问题的实际答案(即:您想要的是完全不可能的)-实际上不是问题。因为没有必要这样做。
一些其他问题:
containerClass.getGenericSuperclass();
这没有按照您的想法做。 java.lang.Class
变量无法保存泛型。自己尝试一下:
List<String> list1 = new ArrayList<String>();
List<Integer> list2 = new ArrayList<Integer>();
sysout(list1.getClass() == list2.getClass();
上面的代码显示'true',从而证明泛型部分不在类变量中。另外,Class<?> c = List<Integer>.class;
是编译器错误。
.getGenericSuperclass()
为您带来的好处是AbstractList<String>
:
public class MyClass extends AbstractList<String>
。
请注意,如果您在数组列表上尝试这种特技,则会得到ArrayList.java
:AbstractList<T>
的字面意思。
如果要使此方法可行:
public <T> List<T> makeListOf(T type) {
// .. stuff here
}
such that:
List<String> list = makeListOf(String.class);
assertEquals(list.getClass()
.getGenericSuperclass().toString(),"AbstractList<String>");
然后,唯一的方法是使用ASM或BCEL或其他字节码创建工具在运行时创建一个全新的类,并通过类加载器的defineClass加载它,从而永久耗尽进程的内存。这绝对没有任何用处,因此我非常怀疑您是否愿意这样做。这也很复杂。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。