简体   繁体   English

将类传递给方法以实例化泛型

[英]Passing Class to a method to instantiate a generic

The following code doesn't work, because the marked line does not compile: 以下代码不起作用,因为标记的行无法编译:

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!!!
    }
}

I do NOT want MyClass to be a generic. 我不希望MyClass是泛型的。 Why? 为什么? Because the actual implementation of the method create is similar to the following: 因为创建方法的实际实现类似于以下内容:

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

Therefore, I cannot couple MyClass to any particular generics. 因此,我不能将MyClass耦合到任何特定的泛型。 Is there a way to instantiate my GenericClass with passed parameters? 有没有办法通过传递的参数实例化我的GenericClass? How? 怎么样?

Thanks 谢谢


Thank you for your answers. 谢谢您的回答。 I'll tell you the whole story. 我会告诉你整个故事。

I'm using Spring and I plan to use MongoDB . 我正在使用Spring,并且打算使用MongoDB

The class GenericClass is something like: 类GenericClass类似于:

 GenericClass<PersistetType1, Long> 

or 要么

 GenericClass<PersistentType2, Long>

where PersistentType1/2 are classes that I need to finally store in the DB, while, GenericClass is a sort of Proxy to access Mongo APIs. 其中PersistentType1 / 2是我最终需要存储在数据库中的类,而GenericClass是一种访问Mongo API的代理。 In fact, it looks like: 实际上,它看起来像:

  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);

Now, what? 怎么办? From Controllers (or Entity, if you are picky) I need to instantiate the repository and invoke any methods. 从控制器(或实体,如果您很挑剔),我需要实例化存储库并调用任何方法。 This causes the Controllers to be coupled with MongoDB, ie they explicitly have to instantiate such GenericClass, which is actually called MongoRepository and is strictly dependent on Mongo (in fact it is a generic with exactly two "degrees of freedom"). 这导致控制器与MongoDB耦合,也就是说,它们必须明确实例化此类GenericClass,该类实际上称为MongoRepository,并且严格依赖于Mongo(实际上,它是具有两个“自由度”的泛型)。

So, I decided to create MyClass, that is a further proxy that isolates Controllers. 因此,我决定创建MyClass,这是隔离Controllers的另一个代理。 In this way, Controller can get the single instance of MyClass and let it create a new instance of the appropriate repository. 通过这种方式,Controller可以获取MyClass的单​​个实例,并使其创建相应存储库的新实例。 In particular, when "somecondition" is true, it means that we want to use MongoRepository (when it is false, maybe, a need to instantiate a Hibernate proxy, ie HibernateRepository). 特别是,当“ somecondition”为true时,这意味着我们要使用MongoRepository(如果为false,则可能需要实例化一个Hibernate代理,即HibernateRepository)。 However, MongoRepository is generic, therefore it requires some form of instantiation, that I hoped to pass as a parameter. 但是,MongoRepository是通用的,因此它需要某种形式的实例化,我希望将其作为参数传递。

Unfortunately, generics are resolved at compile time, thus they don't work for me, I guess. 不幸的是,泛型在编译时已解决,因此我猜它们对我不起作用。

How can I fix that? 我该如何解决?

That doesn't make sense, especially in Java. 这没有意义,尤其是在Java中。

The whole point of generics is to specify at compile-time what the types are. 泛型的全部要点是在编译时指定类型是什么。

If you don't know what the types are until runtime, Java generics would be useless, due to type erasure. 如果您直到运行时都不知道类型是什么,由于类型擦除,Java泛型将毫无用处。 (in C#, you would need reflection) (在C#中,您需要进行反思)

Due to Type Erasure , a first implementation could consider only rawtypes implementation. 由于类型擦除 ,第一个实现只能考虑原始类型实现。

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

A cleaner alternative would be the following: 更加干净的替代方法如下:

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

Both implementations does exactly the same thing at runtime. 两种实现在运行时都做完全相同的事情。 The second is better since its signature depends on its arguments (while create returns a Map<?, ?> , the second may return a Map<String, Integer> ) 第二个更好,因为其签名取决于其参数(而create返回Map<?, ?> ,第二个可能返回Map<String, Integer>

There is no need to pass the Class objects in at runtime. 无需在运行时传递Class对象。 Generics are purely compile-time. 泛型纯粹是编译时。 Since (it seems like) you are returning a non-generic type, and so you are throwing away the generic parameters anyway (I don't know why you would do this; but since you are, I will go with that), it doesn't matter what you use as the parameter. 因为(看起来)您正在返回一个非泛型类型,所以无论如何您都将泛型参数丢弃(我不知道您为什么要这样做;但是既然如此,我将继续使用它)用作参数无关紧要。 Any type parameter that passes the type checker will be sufficient: 任何通过类型检查器的类型参数就足够了:

public NonGenericSuperClassOfGenericClass create() {
    if(someCondition)
         return new GenericClass<Object,Object>();
    else
         return new OtherGenericClass<Object>();
}

One thing to comes to mind is something along the lines of: 我想到的一件事是:

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>();
}

The way is to parametrize the generic with another generic: T1>. 方法是使用另一个泛型参数化泛型参数:T1>。 This way I get the coupling I need. 这样,我就可以获得所需的耦合。 The appropriate choice of AnotherClass gives the expected result. 适当选择AnotherClass可以得到预期的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM