public static <E> void append(List<E> list) {
E elem = new E(); // compile-time error
list.add(elem);
}
public static <E> void append(List<E> list, Class<E> cls) throws Exception {
E elem = cls.newInstance(); // OK
list.add(elem);
}
List<String> ls = new ArrayList<>();
append(ls, String.class);
我想到了一个选项,它可能会有所帮助:
public static class Container<E> {
private Class<E> clazz;
public Container(Class<E> clazz) {
this.clazz = clazz;
}
public E createContents() throws Exception {
return clazz.newInstance();
}
}
编辑:您也可以使用此构造函数(但需要 E 的实例):
@SuppressWarnings("unchecked")
public Container(E instance) {
this.clazz = (Class<E>) instance.getClass();
}
如果您想在实例化时不需要像这样两次键入类名:
new SomeContainer<SomeType>(SomeType.class);
<E> SomeContainer<E> createContainer(Class<E> class);
比如:
public class Container<E> {
public static <E> Container<E> create(Class<E> c) {
return new Container<E>(c);
}
Class<E> c;
public Container(Class<E> c) {
super();
this.c = c;
}
public E createInstance()
throws InstantiationException,
IllegalAccessException {
return c.newInstance();
}
}
您可以使用:
Class.forName(String).getConstructor(arguments types).newInstance(arguments)
但是您需要提供准确的类名,包括包名,例如java.io.FileInputStream
。我用它来创建数学表达式解析器。
foo.getClass().getName()
。那个实例从哪里来的呢?目前我正在我现在工作的项目中将其传递给构造函数。 - Mark Storerprivate static class SomeContainer<E extends Object> {
E e;
E createContents() throws Exception{
return (E) e.getClass().getDeclaredConstructor().newInstance();
}
}
这是一个例子,我在其中无法传递参数。
public class SomeContainer<E extends Object> {
E object;
void resetObject throws Exception{
object = (E) object.getClass().getDeclaredConstructor().newInstance();
}
}
如果您将泛型类扩展为非对象类型,则使用反射创建运行时错误。将泛型类型扩展为对象可将此错误转换为编译时错误。
TypeToken<T>
类:public class MyClass<T> {
public T doSomething() {
return (T) new TypeToken<T>(){}.getRawType().newInstance();
}
}
(T) new TypeToken<T>(getClass()){}.getRawType().newInstance();
- Jacob van Lingenimport java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface SomeContainer<E> {
E createContents();
}
public class Main {
@SuppressWarnings("unchecked")
public static <E> SomeContainer<E> createSomeContainer() {
return (SomeContainer<E>) Proxy.newProxyInstance(Main.class.getClassLoader(),
new Class[]{ SomeContainer.class }, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class<?> returnType = method.getReturnType();
return returnType.newInstance();
}
});
}
public static void main(String[] args) {
SomeContainer<String> container = createSomeContainer();
[*] System.out.println("String created: [" +container.createContents()+"]");
}
}
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
at Main.main(Main.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
第26行是带有 [*]
的那一行。
唯一可行的解决方案是由 @JustinRudd 提供的。
@Noah的回答有所改进。
改动原因
a] 如果使用了多个通用类型并且更改了顺序,则更安全。
b] 类的通用类型签名不时更改,这样您就不会在运行时遇到无法解释的异常。
健壮代码
public abstract class Clazz<P extends Params, M extends Model> {
protected M model;
protected void createModel() {
Type[] typeArguments = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
for (Type type : typeArguments) {
if ((type instanceof Class) && (Model.class.isAssignableFrom((Class) type))) {
try {
model = ((Class<M>) type).newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
或者使用一行代码
一行代码
model = ((Class<M>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1]).newInstance();
private Class<E> entity;
public xyzservice(Class<E> entity) {
this.entity = entity;
}
public E getEntity(Class<E> entity) throws InstantiationException, IllegalAccessException {
return entity.newInstance();
}
获取实体变量 e = getEntity(entity);
E
表示的原始类的 createContents
实现:E createContents() throws Exception {
return TypeTools.resolveRawArgument(SomeContainer.class, getClass()).newInstance();
}
SomeContainer
被子类化,以便将E
的实际值捕获在类型定义中:class SomeStringContainer extends SomeContainer<String>
add(...)
和set(0,...)
以检查是否为空的通用列表编写断言时。 - Egor Hans