以下代码不起作用,因为标记的行不能编译:
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是通用的,因此它需要某种形式的实例化,我希望将其作为参数传递。
不幸的是,泛型在编译时得到解决,因此我认为它们对我不起作用。
我该如何解决?
答案 0 :(得分:6)
这没有意义,特别是在Java中。
泛型的全部意义是在编译时指定类型是什么。
如果在运行时之前不知道类型是什么,由于类型擦除,Java泛型将毫无用处。 (在C#中,你需要反思)
答案 1 :(得分: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返回Map<?, ?>
时,第二个可能返回Map<String, Integer>
)
答案 2 :(得分:1)
无需在运行时传递Class对象。泛型是纯粹的编译时间。因为(似乎)你正在返回一个非泛型类型,所以你无论如何都丢弃了泛型参数(我不知道你为什么会这样做;但既然你是,我会继续这样做),它你用什么作为参数并不重要。传递类型检查器的任何类型参数都已足够:
public NonGenericSuperClassOfGenericClass create() {
if(someCondition)
return new GenericClass<Object,Object>();
else
return new OtherGenericClass<Object>();
}
答案 3 :(得分: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>();
}
答案 4 :(得分:0)
方法是使用另一个通用参数化泛型:T1&gt;。这样我得到了我需要的耦合。适当选择AnotherClass会得到预期的结果。