0

以下代码不起作用,因为标记的行无法编译:

MyClass {
    //singleton stuff
    private static MyClass instance;
    private MyClass () {}
    public static MyClass getInstance() {
        if(instance==null) {
            instance = new MyClass ();
        }
        return instance;
    }

    // method creating problems
    public NonGenericSuperClassOfGenericClass create(Class<?> c1, Class<?> c2) {
        return new GenericClass<c1,c2>; // DOES NOT COMPILE!!!
    }
}

我不希望 MyClass 是通用的。为什么?因为create方法的实际实现类似于下面这样:

    // method creating problems
    public NonGenericSuperClassOfGenericClass create(Class<?>... classes) {
        if(someCondition)
             return new GenericClass<classes[0],classes[1]>;
        else
             return new OtherGenericClass<classes[0]>;
}

因此,我不能将 MyClass 与任何特定的泛型结合起来。有没有办法用传递的参数实例化我的 GenericClass?如何?

谢谢


谢谢您的回答。我会告诉你整个故事。

我正在使用Spring并且我打算使用MongoDB

类 GenericClass 类似于:

 GenericClass<PersistetType1, Long> 

或者

 GenericClass<PersistentType2, Long>

其中 PersistentType1/2 是我最终需要存储在数据库中的类,而 GenericClass 是一种访问 Mongo API 的代理。事实上,它看起来像:

  public MongoTemplate getTemplate();
  public void save(T toInsert);
  public List<T> select(Query selectionQuery);
  public T selectById(ID id);
  public WriteResult update(Query selectionQuery, Update updatedAttributes);
  public void delete(T toRemove);
  public void delete(Query selectionQuery);

怎么办?从控制器(或实体,如果你很挑剔)我需要实例化存储库并调用任何方法。这导致控制器与 MongoDB 耦合,即它们必须显式实例化这样的 GenericClass,它实际上称为 MongoRepository 并且严格依赖于 Mongo(实际上它是一个具有恰好两个“自由度”的泛型)。

所以,我决定创建 MyClass,这是一个隔离控制器的进一步代理。这样,Controller 可以获取 MyClass 的单个实例,并让它创建相应存储库的新实例。特别是,当“somecondition”为真时,意味着我们要使用MongoRepository(当它为假时,可能需要实例化一个Hibernate代理,即HibernateRepository)。但是,MongoRepository 是通用的,因此它需要某种形式的实例化,我希望将其作为参数传递。

不幸的是,泛型是在编译时解决的,因此我猜它们对我不起作用。

我该如何解决?

4

5 回答 5

6

这没有意义,尤其是在 Java 中。

泛型的全部意义在于在编译时指定类型是什么。

如果您直到运行时才知道类型是什么,那么由于类型擦除,Java 泛型将毫无用处。(在 C# 中,你需要反射)

于 2012-06-29T03:01:57.673 回答
2

由于Type Erasure,第一个实现可以只考虑 rawtypes 实现。

// Similar to original method
@SuppressWarnings("rawtypes")
public Map<?, ?> create(Class<?> c1, Class<?> c2) {
    return new HashMap();
}

更清洁的替代方案如下:

// A more generic alternative
public <S, T> Map<S, T> create2(Class<? extends S> c1, Class<? extends T> c2) {
    return new HashMap<S, T>();
}

两种实现在运行时都做同样的事情。第二个更好,因为它的签名取决于它的参数(虽然 create 返回 a Map<?, ?>,第二个可能返回 a Map<String, Integer>

于 2012-06-29T11:56:52.693 回答
1

无需在运行时传入 Class 对象。泛型纯粹是编译时的。因为(看起来)你正在返回一个非泛型类型,所以无论如何你都扔掉了泛型参数(我不知道你为什么要这样做;但既然你是,我会去的),它使用什么作为参数并不重要。任何通过类型检查器的类型参数就足够了:

public NonGenericSuperClassOfGenericClass create() {
    if(someCondition)
         return new GenericClass<Object,Object>();
    else
         return new OtherGenericClass<Object>();
}
于 2012-06-29T17:48:23.930 回答
1

想到的一件事是:

public NonGenericSuperClassOfGenericClass create(Class<?>... classes) {
    if(someCondition)
         return new helper1(classes[0],classes[1]);
    else
         return new helper2(classes[0]);
}

public <R,T> GenericClass<R,T> helper1( Class<R> a, Class<T> b ){
    return new GenericClass<R,T>();
}

public <T> OtherGenericClass<T> helper2( Class<T> a ){
    return new OtherGenericClass<T>();
}
于 2012-06-30T05:47:43.230 回答
0

方法是用另一个泛型参数化泛型:T1>。这样我就得到了我需要的联轴器。The appropriate choice of AnotherClass gives the expected result.

于 2013-07-11T21:20:27.000 回答