Java泛型限制还是错误使用?

Java泛型限制还是错误使用?,java,generics,Java,Generics,我有一个类,它表示一对相同类型的两个值(类型可以是任何一组特定类型): 即使我像上面那样做,我也会遇到一些问题,因为var1被声明为类型E,并且在尝试实例化SpecficType1并将结果对象分配给var1/var2时,我会得到一个类型不匹配错误。为了让它发挥作用,我必须向E: var1 = (E)new SpecificType1(); 但这破坏了编译时类型检查,因为我试图将特定类型强制转换为泛型类型 这是java中泛型的一个限制还是使用泛型的一个糟糕的场景 为了实例化变量,我应该

我有一个类,它表示一对相同类型的两个值(类型可以是任何一组特定类型):

  • 即使我像上面那样做,我也会遇到一些问题,因为var1被声明为类型E,并且在尝试实例化SpecficType1并将结果对象分配给var1/var2时,我会得到一个类型不匹配错误。为了让它发挥作用,我必须向E:

       var1 = (E)new SpecificType1();
    
  • 但这破坏了编译时类型检查,因为我试图将特定类型强制转换为泛型类型

    这是java中泛型的一个限制还是使用泛型的一个糟糕的场景

    为了实例化变量,我应该知道它的确切类型并调用特定类型的构造函数;在最好的情况下,这意味着构造函数中有一个相当大的if-else语句,类似于:

    在那之前你会遇到问题的

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