2008-12-10 54 views
13

是否有可能在Java中反射性地实例化泛型类型?使用描述的技术here我收到错误,因为类令牌不能通用。以下面的例子。我想实例化实现Creator的Creator的一些子类。实际的类名称作为命令行参数传入。这个想法是能够在运行时指定Creator的实现。有没有另一种方法来完成我在这里要做的事情?可以反思性地实例化java中的泛型类型吗?

public interface Creator<T> { 
    T create(); 
} 
public class StringCreator implements Creator<String> { 
    public String create() { return new String(); } 
} 
public class FancyStringCreator implements Creator<String> { 
    public String create() { return new StringBuffer().toString(); } 
} 
public static void main(String[] args) throws Exception { 
    Class<?> someClass = Class.forName(args[0]); 
    /*ERROR*/Class<? extends Creator<String>> creatorClass = someClass.asSubclass(Creator.class); 
    Constructor<? extends Creator<String>> creatorCtor = creatorClass.getConstructor((Class<?>[]) null); 
    Creator<String> creator = creatorCtor.newInstance((Object[]) null); 
} 

编辑:我喜欢马库斯的方法,因为它是最简单实用的方法,没有规避整体的泛型。我可以在我的情况中使用它,因为我可以指定传递的类必须是StringCreator的子类。但是正如Ericson所指出的那样,通用信息仍然存在于类型级别,而不是在运行级别,所以仍然可以反思性地检查给定的类是否实现了正确的泛型类型。

回答

7

通用信息在运行时丢失。没有运行时等效的Creator < String> .class。你可以创建创造者和StringCreator之间的类型,修正了泛型类型:

public interface Creator<T> { 
     T create(); 
} 
public interface StringCreator extends Creator<String> { } 
public class StringCreatorImpl implements StringCreator { 
     public String create() { return new String(); } 
} 
public class FancyStringCreator implements StringCreator { 
     public String create() { return new StringBuffer().toString(); } 
} 
public static void main(String[] args) throws Exception { 
     Class<?> someClass = Class.forName(args[0]); 
     Class<? extends StringCreator> creatorClass = someClass.asSubclass(StringCreator.class); 
     Constructor<? extends StringCreator> creatorCtor = creatorClass.getConstructor((Class<?>[]) null); 
     Creator<String> creator = creatorCtor.newInstance((Object[]) null); 
} 

但是,当然,你失去了一点灵活性,因为你不能使用下面的创建者类:

public class AnotherCreator implements Creator<String> { 
    public String create() { return ""; } 
} 
+0

并非所有通用信息在运行时都会丢失;即使没有创建另一个界面,也有足够的时间检查必要的类型信息。只是没有足够的信息让编译器推断正确性。 – erickson 2008-12-10 19:48:48

3

你不需要那条线。你也不需要构造函数,因为你只是使用默认构造函数。只需直接实例化类:

public static void main(String[] args) throws Exception { 
     Class<?> someClass = Class.forName(args[0]); 
     Creator<String> creator = (Creator<String>) someClass.newInstance(); 
} 

如果你坚持,你将只能得到一半了:

public static void main(String[] args) throws Exception { 
    Class<?> someClass = Class.forName(args[0]); 
    Class<? extends Creator> creatorClass = someClass.asSubclass(Creator.class); 
    Constructor<? extends Creator> creatorCtor = creatorClass.getConstructor((Class<?>[]) null); 
    Creator<String> creator = (Creator<String>) creatorCtor.newInstance((Object[]) null); 
} 
+0

claz.newInstance ()和ctor.newInstance()在发生错误时的行为不完全相同。类的newInstance方法较旧,与其他反射式“方法”调用不一致。 – erickson 2008-12-10 16:33:34

-1

不明白为什么你在这里使用泛型。

使用反射建议的一般用途,但想必你会打电话给create在某些时候和结果分配给String对象的实例化,否则为什么要使用仿制药,以控制返回类型。

但是,如果你写了下面执行造物主的:

public class IntegerCreator implements Creator<Integer> 
{ 
    public Integer create() 
    { 
    ... 
    } 
} 

并通过它与调用create和分配结果的时候你会得到一个ClassCastException一个说法。

4

这将做你正在做的事情,同时提供类型安全。没有办法避免未经检查的警告,但这里完成的类型检查证明了它的抑制。

public static void main(String[] args) 
    throws Exception 
    { 
    Class<? extends Creator<String>> clz = load(argv[0], String.class); 
    Constructor<? extends Creator<String>> ctor = clz.getConstructor(); 
    Creator<String> creator = ctor.newInstance(); 
    System.out.println(creator.create()); 
    } 

    public static <T> Class<? extends Creator<T>> load(String fqcn, Class<T> type) 
    throws ClassNotFoundException 
    { 
    Class<?> any = Class.forName(fqcn); 
    for (Class<?> clz = any; clz != null; clz = clz.getSuperclass()) { 
     for (Object ifc : clz.getGenericInterfaces()) { 
     if (ifc instanceof ParameterizedType) { 
      ParameterizedType pType = (ParameterizedType) ifc; 
      if (Creator.class.equals(pType.getRawType())) { 
      if (!pType.getActualTypeArguments()[0].equals(type)) 
       throw new ClassCastException("Class implements " + pType); 
      /* We've done the necessary checks to show that this is safe. */ 
      @SuppressWarnings("unchecked") 
      Class<? extends Creator<T>> creator = (Class<? extends Creator<T>>) any; 
      return creator; 
      } 
     } 
     } 
    } 
    throw new ClassCastException(fqcn + " does not implement Creator<String>"); 
    } 

你要坚持的主要限制是,在分级中的类必须指定类型参数。例如class MyCreator implements Creator<String>。您不能与class GenericCreator<T> implements Creator<T>一起使用。

当前不处理,你创建一个新的接口interface StringCreatorIfc extends Creator<String>,并有一个类实现了有效的情况下。它可以被强化来做到这一点,但我会把它作为对那些倾向者的练习。