Java泛型限制还是错误使用?
我有一个类,它表示一对相同类型的两个值(类型可以是任何一组特定类型):Java泛型限制还是错误使用?,java,generics,Java,Generics,我有一个类,它表示一对相同类型的两个值(类型可以是任何一组特定类型): 即使我像上面那样做,我也会遇到一些问题,因为var1被声明为类型E,并且在尝试实例化SpecficType1并将结果对象分配给var1/var2时,我会得到一个类型不匹配错误。为了让它发挥作用,我必须向E: var1 = (E)new SpecificType1(); 但这破坏了编译时类型检查,因为我试图将特定类型强制转换为泛型类型 这是java中泛型的一个限制还是使用泛型的一个糟糕的场景 为了实例化变量,我应该
var1 = (E)new SpecificType1();
if(var1 instanceof SpecificType1){
var1 = new SpecificType1();
var2 = new SpecificType2();
}
此时var1
为null
,因此对于所有T
而言var1 instanceof T
为false
Java泛型的一个限制是泛型类型参数非常复杂,因此无法从零参数构造函数反映类型参数 调用方必须提供一些上下文来告诉您如何初始化
var1
和var2
,提供该上下文的典型方法是通过构造函数参数
您最好的选择可能是让
var1
和var2
启动null
,然后延迟初始化,直到您可以获得所需的上下文
或许
void init(Class<E> type) {
if (type.isAssignableFrom(ConcreteType1.class)) {
var1 = type.cast(new ConcreteType1(...));
var2 = type.cast(new ConcreteType1(...));
} else { /* other branches */ }
}
void init(类类型){
if(type.isAssignableFrom(ConcreteType1.class)){
var1=type.cast(新混凝土类型1(…);
var2=类型.cast(新混凝土类型1(…);
}else{/*其他分支*/}
}
这并不完美,因为您仍然无法将E extends List
与E extends List
区分开来,但对于您的情况,它可能已经足够好了,并且该方法将为您提供对E
的类型安全转换
或者,Guava、Guice和相关库提供类似于接口的东西,在
init
方法中可能会派上用场。您不能实例化泛型类型-例如,如果泛型类型是SomeAbstractClass
,会发生什么?将实例化什么?(这不是原因,只是直觉)
但是,您可以使用来实例化该对象,但是您需要为它指定特定的类对象
一个更优雅的选择是使用,将工厂对象传递给您的配对对象,并使用它来构造所需的对象
代码示例:
public class Pair<S> {
public final S var1;
public final S var2;
public Pair(Factory<S> builder) {
var1 = builder.build();
var2 = builder.build();
}
}
public interface Factory<S> {
public S build();
}
public class IntegerBuilder implements Factory<Integer> {
private int element = 5;
public Integer build() {
return new Integer(element++);
}
}
公共类对{
公开决赛S var1;
公开决赛S var2;
公共对(工厂建设者){
var1=builder.build();
var2=builder.build();
}
}
公共接口工厂{
公共建筑();
}
公共类IntegerBuilder实现工厂{
私有int元素=5;
公共整数生成(){
返回新的整数(element++);
}
}
如果一个框架要实例化它,它将作为一个原始类型来执行,这相当于没有类型参数的newpair()
我想您必须创建简单的单行程序类,如:
class SpecificType1Pair extends Pair<SpecificType1> {}
如果您必须在通用容器中使用
instanceOf
,那么您就有设计问题。您可以尝试通知询问者(因为编辑不会通知询问者):我添加了一个简单的代码示例,说明如何在您的案例中使用factory设计模式是的,这也是我的直觉。因此,限制更为严重!我也同意编辑。我有另一个构造函数,它使用2个E变量作为参数,但框架需要一个无参数构造函数。框架应该调用init,它肯定不会这样做。@Razvan,如果你不能将初始化分为两步,您可以尝试创建具有零参数的子类,这些子类通过传递参数来初始化它们的超类吗class StringPair扩展对{StringPair(){super(String.class);}}
和类似的class IntegerPair扩展对{IntegerPair(){super(Integer.class);}}
@Razvan,如果泛型允许收集基类中所有常见的参数类型不变行为,则只对特定于类型的子类进行初始化,然后,我认为通过使用泛型基类,您可以获得一些东西。@SuppressWarnings(“unchecked”)
可能在类clazz=(class)代码>行。@OldCurmudgeon:刚刚做了,可以理解吗?太好了。现在对于类
方法,只是为了完整性。@OldCurmudgeon:我添加了它作为一个选项-但我强烈建议不要这样做-因此我宁愿不使用工厂设计模式代码-更安全、更高效。
void init(Class<E> type) {
if (type.isAssignableFrom(ConcreteType1.class)) {
var1 = type.cast(new ConcreteType1(...));
var2 = type.cast(new ConcreteType1(...));
} else { /* other branches */ }
}
public class Pair<S> {
public final S var1;
public final S var2;
public Pair(Factory<S> builder) {
var1 = builder.build();
var2 = builder.build();
}
}
public interface Factory<S> {
public S build();
}
public class IntegerBuilder implements Factory<Integer> {
private int element = 5;
public Integer build() {
return new Integer(element++);
}
}
class SpecificType1Pair extends Pair<SpecificType1> {}
public abstract class Pair<E extends AClass> {
private E var1;
private E var2;
public Pair() {
ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass();
@SuppressWarnings("unchecked")
Class<E> clazz = (Class<E>) superclass.getActualTypeArguments()[0];
try {
var1 = clazz.newInstance();
var2 = clazz.newInstance();
} catch (InstantiationException e) {
handle(e);
} catch (IllegalAccessException e) {
handle(e);
}
}
}