Java Generics限制或错误用法?

时间:2012-09-22 23:05:04

标签: java generics

我有一个类代表一对相同类型的两个值(类型可以是任何特定类型的集合):

  public class Pair<E extends AClass>{
      private E var1;
      private E var2; 
  }

这个类由框架使用,所以它需要一个无参构造函数,我必须在其中实例化2个变量(var1,var2):

  public class Pair<E extends AClass>{
      private E var1;
      private E var2; 

      public Pair(){
           var1 = invoke constructor of type E; 
           var2 = invoke constructor of type E 
      }
  }

这里显然有很多问题:

  1. 为了实例化变量,我应该以某种方式知道它的确切类型并调用该特定类型的构造函数;在最好的情况下,这意味着在构造函数中有一个非常大的if else语句,如:

     public Pair(){
           if(var1 instanceof SpecificType1){
              var1 = new SpecificType1(); 
              var2 = new SpecificType2();
           }
      }
    
  2. 即使我如上所述,我也会遇到一些问题,因为var1被声明为E类,我在尝试实例化SpecficType1并将结果对象分配给var1 / var2时会遇到类型不匹配错误。为了使它成功,我必须转向E:

       var1 = (E)new SpecificType1();
    
  3. 但是这会破坏编译时类型检查,因为我正在尝试将特定类型转换为泛型类型。

    这是Java中Generics的限制,还是使用Generics这个场景很糟糕?

2 个答案:

答案 0 :(得分:6)

  

为了实例化变量,我应该以某种方式知道它的确切类型并调用该特定类型的构造函数;在最好的情况下,这意味着在构造函数中有一个非常大的if else语句,如:

在此之前你会遇到问题。

   if(var1 instanceof SpecificType1){
      var1 = new SpecificType1(); 
      var2 = new SpecificType2();
   }
此时

var1null,因此对于所有var1 instanceof TfalseT


Java泛型的一个限制是泛型类型参数是erased,所以你无法从零参数构造函数中反映出类型参数。

调用者必须提供一些上下文来告诉您如何初始化var1var2,并且提供该上下文的典型方法是通过构造函数参数。


您最好的选择可能是让var1var2null开始,然后延迟初始化,直到您获得所需的上下文为止。

也许

void init(Class<E> type) {
  if (type.isAssignableFrom(ConcreteType1.class)) {
    var1 = type.cast(new ConcreteType1(...));
    var2 = type.cast(new ConcreteType1(...));
  } else { /* other branches */ }
}

这并不完美,因为您仍然无法将E extends List<String>E extends List<Number>区分开来,但对于您的情况可能已经足够了,.cast方法会为您提供类型 - 安全施放到E


或者,Guava,Guice和相关库提供Supplier<E>接口之类的东西,它可以在init方法中派上用场。

答案 1 :(得分:2)

您无法实例化泛型类型 - 例如,如果泛型类型为SomeAbstractClass会发生什么?什么将被实例化? (这不是原因,只是直觉)

但是,您可以使用 java reflection API 来实例化对象 - 但是您需要特定的类对象。

更优雅的选择是使用 abstract factory design pattern ,并将工厂对象传递给您的对,并使用它来构造所需的对象。


代码示例:

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++);
    }
}
相关问题