问题
我知道Java的泛型有点不如.Net。
我有一个泛型classFoo<T>
,我真的需要使用无参数构造函数实例化aT
inFoo
。如何解决Java的局限?
#1 热门回答(156 赞)
一种选择是传递inBar.class
(或你感兴趣的任何类型 - 以任何方式指定相应的Class<T>
参考)并将该值保存为字段:
public class Test
{
public static void main(String [] args)
throws Exception // Just for simplicity!
{
Generic<Bar> x = new Generic<Bar>(Bar.class);
Bar y = x.buildOne();
}
}
public class Generic<T>
{
private Class<T> clazz;
public Generic(Class<T> clazz)
{
this.clazz = clazz;
}
public T buildOne() throws InstantiationException,
IllegalAccessException
{
return clazz.newInstance();
}
}
public class Bar
{
public Bar()
{
System.out.println("Constructing");
}
}
另一种选择是拥有一个"工厂"接口,并将工厂传递给泛型类的构造函数。这更灵活,你不必担心反射异常。
#2 热门回答(45 赞)
这是Factory实现,asJon Skeet suggested:
interface Factory<T> {
T factory();
}
class Araba {
//static inner class for Factory<T> implementation
public static class ArabaFactory implements Factory<Araba> {
public Araba factory() {
return new Araba();
}
}
public String toString() { return "Abubeee"; }
}
class Generic<T> {
private T var;
Generic(Factory<T> fact) {
System.out.println("Constructor with Factory<T> parameter");
var = fact.factory();
}
Generic(T var) {
System.out.println("Constructor with T parameter");
this.var = var;
}
T get() { return var; }
}
public class Main {
public static void main(String[] string) {
Generic<Araba> gen = new Generic<Araba>(new Araba.ArabaFactory());
System.out.print(gen.get());
}
}
输出:
Constructor with Factory<T> parameter
Abubeee
#3 热门回答(7 赞)
在没有明确使用构造函数参数的情况下,这是一种相当人为的方法。你需要扩展参数化抽象类。
public class Test {
public static void main(String [] args) throws Exception {
Generic g = new Generic();
g.initParameter();
}
}
import java.lang.reflect.ParameterizedType;
public abstract class GenericAbstract<T extends Foo> {
protected T parameter;
@SuppressWarnings("unchecked")
void initParameter() throws Exception, ClassNotFoundException,
InstantiationException {
// Get the class name of this instance's type.
ParameterizedType pt
= (ParameterizedType) getClass().getGenericSuperclass();
// You may need this split or not, use logging to check
String parameterClassName
= pt.getActualTypeArguments()[0].toString().split("\\s")[1];
// Instantiate the Parameter and initialize it.
parameter = (T) Class.forName(parameterClassName).newInstance();
}
}
public class Generic extends GenericAbstract<Foo> {
}
public class Foo {
public Foo() {
System.out.println("Foo constructor...");
}
}