在java中实例化genericstypes

重复:Javagenerics为什么这不起作用

重复:在Java中实例化一个generics类

我想在java中创build一个genericstypes的对象。 请build议我怎样才能达到相同的效果。

注意:这似乎是一个微不足道的generics问题。 但我敢打赌,这不是。 🙂

假设我有这样的类声明:

public class Abc<T> { public T getInstanceOfT() { // I want to create an instance of T and return the same. } } 
  public class Abc<T> { public T getInstanceOfT(Class<T> aClass) { return aClass.newInstance(); } } 

你将不得不添加exception处理。

您必须在运行时传递实际的types,因为它不是编译后的字节代码的一部分,所以没有明确提供它就无法知道它。

在你发布的代码中,不可能创build一个T的实例,因为你不知道是什么types:

 public class Abc<T> { public T getInstanceOfT() { // There is no way to create an instance of T here // since we don't know its type } } 

当然,如果你有一个对Class<T>的引用,并且T有一个默认的构造函数,可以在Class对象上调用newInstance()

如果你Abc<T>你甚至可以解决types擦除问题,而不必传递任何Class<T>引用:

 import java.lang.reflect.ParameterizedType; public class Abc<T> { T getInstanceOfT() { ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass(); Class<T> type = (Class<T>) superClass.getActualTypeArguments()[0]; try { return type.newInstance(); } catch (Exception e) { // Oops, no default constructor throw new RuntimeException(e); } } public static void main(String[] args) { String instance = new SubClass().getInstanceOfT(); System.out.println(instance.getClass()); } } class SubClass extends Abc<String> { } 

你写的东西没有任何意义,Java中的generics意味着将参数多态的function添加到对象中。

这是什么意思? 这意味着你想保留你的类的一些typesvariables未定,以便能够使用你的类与许多不同types。

但是你的typesvariables T是一个在运行时被parsing的属性,Java编译器会编译你的类的certificatetypes安全性,而不需要知道T是什么types的对象,所以它不可能让你使用一个typesvariables静态方法。 该types与对象的运行时实例相关联,而public void static main(..)与类定义相关联,并且在该范围内T不代表任何内容。

如果要在静态方法中使用typesvariables ,则必须将该方法声明为generics(因为模板类的typesvariables与其运行时实例相关 ),而不是类:

 class SandBox { public static <T> void myMethod() { T foobar; } } 

这有效,但当然不是main方法,因为没有办法以通用的方式调用它。

编辑 :问题是,因为types擦除只有一个generics类被编译并传递给JVM。 types检查器只是检查代码是否安全,然后由于它certificate了每种通用信息都被丢弃了。

为了实例化T你需要知道T的types,但是它可以同时是多个types,所以一个解决scheme只需要最less的reflection就是使用Class<T>来实例化新的对象:

 public class SandBox<T> { Class<T> reference; SandBox(Class<T> classRef) { reference = classRef; } public T getNewInstance() { try { return reference.newInstance(); } catch (Exception e) { e.printStackTrace(); } return null; } public static void main(String[] args) { SandBox<String> t = new SandBox<String>(String.class); System.out.println(t.getNewInstance().getClass().getName()); } } 

当然这意味着你想要实例化的types:

  • 不是一个原始types
  • 它有一个默认的构造函数

要用不同types的构造函数进行操作,必须深入思考。

您需要静态获取types信息。 尝试这个:

 public class Abc<T> { private Class<T> clazz; public Abc(Class<T> clazz) { this.clazz = clazz; } public T getInstanceOfT() throws InstantiationException, IllegalAccessException { return clazz.newInstance(); } } 

像这样使用它:

  Abc<String> abc = new Abc<String>(String.class); abc.getInstanceOfT(); 

根据你的需要,你可能想要使用Class<? extends T> Class<? extends T>而不是。

要使它工作的唯一方法是使用Reified Generics 。 这在Java中不被支持(但是它是为Java 7 计划的,但是已经被推迟了)。 例如在C#中,假设T有一个默认的构造函数。 您甚至可以通过typeof(T)获取运行时types,并通过Type.GetConstructor()获取构造函数。 我不做C#所以语法可能是无效的,但它大致是这样的:

 public class Foo<T> where T:new() { public void foo() { T t = new T(); } } 

Java中最好的“解决方法”是传递一个Class<T>作为方法的参数,而不是几个已经指出的答案。

首先,您不能在静态main方法中访问types参数T ,只能在非静态类成员(在这种情况下)中访问。

其次,你不能实例化T因为Java使用Type Erasure实现了generics。 几乎所有的通用信息都在编译时被删除。

基本上,你不能这样做:

 T member = new T(); 

这是一个很好的generics教程。

你似乎不了解generics如何工作。 你可能想看看http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html基本上你;可以做的是类似的东西

 public class Abc<T> { T someGenericThing; public Abc(){} public T getSomeGenericThing() { return someGenericThing; } public static void main(String[] args) { // create an instance of "Abc of String" Abc<String> stringAbc = new Abc<String>(); String test = stringAbc.getSomeGenericThing(); } } 

我正在使用以下方法实施相同的方法。

 public class Abc<T> { T myvar; public T getInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException { return clazz.newInstance(); } } 

我试图find一个更好的方式来实现相同的。

这不可能吗?

types擦除解决方法

受@ martin的回答启发,我写了一个帮助类,允许我解决types擦除问题。 使用这个类(和一个小丑的小窍门),我可以创build一个模板types的新实例:

 public abstract class C_TestClass<T > { T createTemplateInstance() { return C_GenericsHelper.createTemplateInstance( this, 0 ); } public static void main( String[] args ) { ArrayList<String > list = new C_TestClass<ArrayList<String > >(){}.createTemplateInstance(); } } 

这里的丑陋窍门是让类abstract这样类的用户就被强制子types化了。 这里我通过在构造函数调用之后附加{}来inheritance它。 这定义了一个新的匿名类并创build它的一个实例。

一旦generics类与具体模板types分类,我能够检索模板types。


 public class C_GenericsHelper { /** * @param object instance of a class that is a subclass of a generic class * @param index index of the generic type that should be instantiated * @return new instance of T (created by calling the default constructor) * @throws RuntimeException if T has no accessible default constructor */ @SuppressWarnings( "unchecked" ) public static <T> T createTemplateInstance( Object object, int index ) { ParameterizedType superClass = (ParameterizedType )object.getClass().getGenericSuperclass(); Type type = superClass.getActualTypeArguments()[ index ]; Class<T > instanceType; if( type instanceof ParameterizedType ) { instanceType = (Class<T > )( (ParameterizedType )type ).getRawType(); } else { instanceType = (Class<T > )type; } try { return instanceType.newInstance(); } catch( Exception e ) { throw new RuntimeException( e ); } } } 

它看起来像你正在试图创build一个类作为通用的应用程序的入口点,这将无法正常工作… JVM不知道什么types它应该使用时,它被实例化为你启动应用程序。

但是,如果这是更一般的情况下,那么类似的东西就是你要找的东西:

 public MyGeneric<MyChoiceOfType> getMeAGenericObject(){ return new MyGeneric<MyChoiceOfType>(); } 

也许:

 MyGeneric<String> objMyObject = new MyGeneric<String>(); 

当你真的必须这样做的时候,有一些很奇怪的办法。

下面是一个我发现非常有用的转换方法的例子。 并提供了一种确定generics的具体类的方法。

此方法接受一组对象作为input,并返回一个数组,其中每个元素是对input集合中每个对象调用字段getter的结果。 例如,假设你有一个List<People>并且你想要一个包含每个人姓氏的String[]

由getter返回的字段值的types由genericsE指定,我需要实例化一个E[]types的数组来存储返回值。

这个方法本身有点难看,但是你使用它的代码可以更清晰。

请注意,这种技术只有在input参数的某个地方存在一个types与返回types相匹配的对象时才有效,并且可以确定性地将其计算出来。 如果您的input参数(或其子对象)的具体类可以告诉你什么关于generics,那么这种技术将无法正常工作。

 public <E> E[] array (Collection c) { if (c == null) return null; if (c.isEmpty()) return (E[]) EMPTY_OBJECT_ARRAY; final List<E> collect = (List<E>) CollectionUtils.collect(c, this); final Class<E> elementType = (Class<E>) ReflectionUtil.getterType(c.iterator().next(), field); return collect.toArray((E[]) Array.newInstance(elementType, collect.size())); } 

完整的代码在这里: https : //github.com/cobbzilla/cobbzilla-utils/blob/master/src/main/java/org/cobbzilla/util/collection/FieldTransformer.java#L28

 Abc<String> abcInstance = new Abc<String> (); 

..例如