在Java中实例化泛型类

rip*_*234 148 java generics

我知道Java的泛型有点不如.Net.

我有一个泛型类Foo<T>的,我真的需要一个实例TFoo使用参数的构造函数.如何解决Java的局限?

Jon*_*eet 165

一种选择是传入Bar.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");
    }
}
Run Code Online (Sandbox Code Playgroud)

另一种选择是拥有一个"工厂"接口,并将工厂传递给泛型类的构造函数.这更灵活,您不必担心反射异常.

  • @fastcodejava,因为你需要传递Class类型.Foo和Class是不同的类型. (2认同)

Özg*_*gür 47

这是工厂实施,正如Jon Skeet建议的那样:

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());
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Constructor with Factory<T> parameter
Abubeee
Run Code Online (Sandbox Code Playgroud)

  • @scottb:您可能没有一个可以使用无参数构造函数创建的简单类。在这种情况下,工厂将是比反射类实例化更可靠的解决方案。 (2认同)

Gle*_*enn 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...");
    }
}
Run Code Online (Sandbox Code Playgroud)