Java:创建类型为类型参数的对象

本文关键字:类型参数 对象 类型 创建 Java | 更新日期: 2023-09-27 18:01:25

我想编写与c#代码相当的Java代码。

我的c#代码如下:
public abstract class A<T> where T : A<T>, new()
{
    public static void Process()
    {
        Process(new T());
    }
    public static void Process(T t)
    {
        // Do Something...
    }
}
public class B : A<B>
{
}
public class C : A<C>
{
}

我的代码的Java版本是这样的

public abstract class A<T extends A<T>>
{
    public static <T extends A<T>> void process()
    {
        process(new T()); // Error: Cannot instantiate the type T 
    }
    public static <T extends A<T>> void process(T t)
    {
        // Do Something...
    }
    public class B extends A<B>
    {
    }
    public class C extends A<C>
    {
    }
}

这里,类声明中的"new()"语法强制派生类编写一个默认构造函数,使得从基类调用"new T()"成为可能。换句话说,当我编写基类时,我确信派生类将具有默认构造函数,以便我可以从基类实例化派生类对象。

我在Java中的问题是,我不能从超类实例化派生类对象。我得到"Cannot instantiate the type T"错误的"new T()"调用。在Java中是否有类似的c#方式,或者我应该使用原型模式和克隆之类的东西?

Java:创建类型为类型参数的对象

Java不支持具体化泛型,所以没有等价的" new T(); "。我解决这个问题的方法是对类型标记使用反射。类型标记指示泛型类型是什么。

public abstract class A<T> {
  private Class<T> typeToken;
  // constructor
  public A() {
        typeToken = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
  }
}

然后使用反射来实例化类。它是丑陋的,但它完成了工作。

你可以从这个链接中找到一些关于c#和Java泛型之间区别的解释-比较Java和c#泛型。

Java泛型是一个完全的编译时构造。对于以任何方式依赖于运行时信息的泛型类型参数,您都不能做任何事情。这包括:
    创建泛型类型的实例参数。
  • 创建泛型数组参数。
  • 查询类的运行时类泛型类型参数
  • 使用泛型instanceof参数。

您可以使用java.lang.reflect命名空间绕过此限制。例如,请参阅这个stackoverflow问题:泛型和Class.forName()

另外,如果您正在使用泛型,请注意这一点。

T[] someArray = new T[];

这是首选ArrayList而不是数组的原因之一。问题的原因在于可重构性和类型擦除。

使用bog标准抽象工厂模式。然后你得到额外的好处,你不需要绑定到一个特定的类型,实现类型不需要有一个特定的构造函数,实例可以有一些参数化,实例可以被缓存,等等。

看在上帝的份上,不要用反射

除了其他注释之外,我建议不要使用泛型。它们是不需要的——它们在编译时就会被剥离——如果你不太了解它们,你会试图让它们做它们不能做的事情。

一旦你的类正常工作,然后将它们重新添加进去。此时,您的IDE将给您提供许多有用且易于理解的建议,并且泛型将在您使用错误类的对象时警告您。

在我看来,这个类完成后可能根本不需要泛型。(我不知道这个类还能做什么,我也不明白静态方法的用法——它们永远不能访问单个实例的类型信息。)

实际上这在Java中不是问题。习惯用法是传递类

    public static <T extends A<T>> T process(Class<T> clazz) 
    {
        T o = clazz.newInstance();
        process( o ); 
        return o;
    }
    X x = process(X.class); // not too verbose

我添加了一个返回值来说明一般情况