java - java创建泛型类型的实例?

  显示原文与译文双语对照的内容

在Java中创建泛型类型的实例有可能? 我想根据我看过答案是 no ( 由于类型擦除 ), 但我感兴趣的,如果任何人都可以看到我丢失的东西:


class SomeContainer<E>
{
 E createContents()
 {
 return what???
 }
}

编辑:原来超级类型标记可以用来解决我的问题,但它需要大量的reflection-based代码,如下的一些答案表示。

我将离开这一会儿,看看任何人开放提出了任何显著不同的伊恩•罗伯逊Artima文章

时间:

你是对的,你不能做"新建e"。 但是你可以把它改成


private static class SomeContainer<E>
{
 E createContents(Class<E> clazz)
 {
 return clazz.newInstance();
 }
}

这很痛苦,但它可以。 将它包装在工厂模式中可以让它更容易被接受。

不知道这是否有用,但是当你子类类型( 包括匿名) 时,类型信息可以通过反射获得。 例如,


public abstract class Foo<E> {

 public E instance; 

 public Foo() throws Exception {
 instance = ((Class)((ParameterizedType)this.getClass().
 getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
. . .
 }

}

因此,当你在子类中创建Foo时,你得到了 Bar e.g.的一个实例,


//notice that this in anonymous subclass of Foo
assert( new Foo<Bar>() {}.instance instanceof Bar );

但它有很多工作,只适用于子类。 虽然很方便。

你需要某种类型的抽象工厂,以便将buck传递给:


interface Factory<E> {
 E create();
}

class SomeContainer<E> {
 private final Factory<E> factory;
 SomeContainer(Factory<E> factory) {
 this.factory = factory;
 }
 E createContents() {
 return factory.create();
 }
}


package org.foo.com;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Basically the same answer as noah's.
 */
public class Home<E>
{

 @SuppressWarnings ("unchecked")
 public Class<E> getTypeParameterClass()
 {
 Type type = getClass().getGenericSuperclass();
 ParameterizedType paramType = (ParameterizedType) type;
 return (Class<E>) paramType.getActualTypeArguments()[0];
 }

 private static class StringHome extends Home<String>
 {
 }

 private static class StringBuilderHome extends Home<StringBuilder>
 {
 }

 private static class StringBufferHome extends Home<StringBuffer>
 {
 } 

/**
 * This prints"String","StringBuilder" and"StringBuffer"
 */
 public static void main(String[] args) throws InstantiationException, IllegalAccessException
 {
 Object object0 = new StringHome().getTypeParameterClass().newInstance();
 Object object1 = new StringBuilderHome().getTypeParameterClass().newInstance();
 Object object2 = new StringBufferHome().getTypeParameterClass().newInstance();
 System.out.println(object0.getClass().getSimpleName());
 System.out.println(object1.getClass().getSimpleName());
 System.out.println(object2.getClass().getSimpleName());
 }

}

你现在可以这么做,它不需要大量的反射代码 !


import com.google.common.reflect.TypeToken;

public class Q26289147
{
 public static void main(final String[] args) throws IllegalAccessException, InstantiationException
 {
 final StrawManParameterizedClass<String> smpc = new StrawManParameterizedClass<String>() {};
 final String string = (String) smpc.type.getRawType().newInstance();
 System.out.format("string = "%s"",string);
 }

 static abstract class StrawManParameterizedClass<T>
 {
 final TypeToken<T> type = new TypeToken<T>(getClass()) {};
 }
}

当然,如果你需要调用需要一些反射的构造函数,但这是非常好的文档,那么这个技巧就不是 !

这里的JavaDoc TypeToken

如果你不想在实例化过程中两次输入类名,例如:


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();
 }

}

Java教程- 对泛型的限制:

无法创建类型参数的实例

不能创建类型参数的实例。 例如以下代码导致compile-time错误:


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);
}

可以按如下方式调用append方法:


List<String> ls = new ArrayList<>();
append(ls, String.class);

当你正在与e在编译时你不关心实际的泛型类型"E"(你使用反射或使用泛型类型的基类)e的子类提供实例。


Abstract class SomeContainer<E>
{

 abstract protected E createContents();
 public doWork(){
 E obj = createContents();
//Do the work with E 

 }
}


**BlackContainer extends** SomeContainer<Black>{
 Black createContents() {
 return new Black();
 }
}

下面是我提出的一个选项,它可能有帮助:


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();
 }
}

编辑:你可以使用这里构造函数( 但它需要一个):


@SuppressWarnings("unchecked")
public Container(E instance) {
 this.clazz = (Class<E>) instance.getClass();
}

...