C# Java:创建一个类型为类型参数的对象

C# Java:创建一个类型为类型参数的对象,c#,java,generics,inheritance,C#,Java,Generics,Inheritance,我想编写与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 cl

我想编写与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>
{
}
公共抽象类A,其中T:A,new()
{
公共静态无效进程()
{
过程(新T());
}
公共静态无效过程(T)
{
//做点什么。。。
}
}
B级:A级
{
}
公共C类:A
{
}
我的代码的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>
    {
    }
}
公共抽象类A
{
公共静态无效进程()
{
进程(new T());//错误:无法实例化类型T
}
公共静态无效过程(T)
{
//做点什么。。。
}
公共类B扩展了A
{
}
公共类C扩展了
{
}
}
在这里,类声明中的“new()”语法强制派生类编写默认构造函数,从而可以从基类调用“new T()”。换句话说,当我编写基类时,我确信派生类将有一个默认构造函数,这样我就可以从基类实例化派生类对象

我在Java中的问题是,我无法从超类实例化派生类对象。对于
“new T()”
调用,我得到
“无法实例化类型T”
错误Java中有没有类似的C?或者我应该使用原型模式和克隆之类的东西?

Java不支持,因此没有与“
new t();
”等价的东西。我解决这个问题的方法是对类型标记使用反射。类型标记指示泛型类型是什么

public abstract class A<T> {
  private Class<T> typeToken;
  // constructor
  public A() {
        typeToken = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
  }
}
公共抽象类A{
私有类类型令牌;
//建造师
公共A(){
typeToken=(类)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
}

然后使用反射来实例化该类。这很难看,但它完成了任务。

此外,如果使用泛型,请注意这一点

T[] someArray = new T[];

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

您可以从中找到C#和Java中泛型之间差异的一些解释

Java泛型是一种完全的编译时构造。您不能对以任何方式依赖于运行时信息的泛型类型参数执行任何操作。这包括:

  • 创建泛型类型的实例 参数
  • 创建泛型类型的数组 参数
  • 查询 泛型类型参数
  • 将instanceof与泛型类型一起使用 参数

您可以使用
java.lang.reflect
namepsace绕过此限制。例如,请参见此stackoverflow问题:

只需使用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
公共静态T进程(clazz类)
{
to=clazz.newInstance();
过程(o);
返回o;
}
X=进程(X.class);//不要太冗长

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

感谢您的快速回复。因为我试图在静态方法中创建一个新实例,所以无法进行getClass()调用。此外,由于编译时构造的原因,T.class不存在。所以,对我来说,反思似乎不是一个解决办法。或者我还找不到它(:这只在子类使用具体类型参数时有效。例如,如果子类是
public class B extensed a
,这将有完全相同的问题。我发现最好使用类型标记,但要求调用方将标记传递到构造函数或方法中。