【问题标题】:Factory method to instantiate instance of objects used in a generic class用于实例化泛型类中使用的对象实例的工厂方法
【发布时间】:2018-09-15 08:17:24
【问题描述】:

我有以下课程。

public abstract class AbstractClass {

      protected String value1;

      public void setValue1(String value1) {
           this.value1 = value1;
      }

}

public abstract class ConcreteClass1 extends AbstractClass{

}

public abstract class ConcreteClass2 extends AbstractClass {

}

public class FactoryOfAbstractClass {

   public AbstractClass newInstance(Class responseType) {
      if (responseType == ConcreteClass1.class) {
         return new ConcreteClass1();
      } else if (responseType == ConcreteClass2.class) {
         return new ConcreteClass2();
      }
      return null;

}

public abstract class ServiceClass<T extends AbstractClass> {

   public T method1 (String arg1, String arg2, Class responseType) {

      //Some operations resulting in a variable called value1
      String value1= someOp();
      T result = FactoryOfAbstractClass.newInstance(responseType);
      result.setValue1(value1);
      return result;

   }

}

T result = FactoryOfAbstractClass.newInstance(responseType); 行中,我收到一个编译错误,提示我需要将要获取的对象类型转换为 T。我不理解 编译错误,因为我的工厂方法正在返回一个实例抽象类和服务类的泛型T extends AbstractClass

一旦我将它转换为 T,编译问题就消失了。但我不明白为什么我们首先需要对它进行类型转换。为什么需要类型转换?

另一种选择是不使用工厂,而是使用responseType.newInstance()。但这在内部使用了反射,我想避免它们。 我还有其他方法可以解决这个问题吗?

【问题讨论】:

  • 不要使用原始类型:Class 应该是 Class&lt;? extends AbstractClass&gt;

标签: java generics factory generic-programming


【解决方案1】:

我不明白编译错误,因为我的工厂方法返回了一个抽象类的实例,而服务类的泛型 T 扩展了 AbstractClass

让我们将AbstractClass 替换为Car 以获得更易于理解的解释。假设一个程序员创建了一个ServiceClass&lt;Mercedes&gt;(梅赛德斯是一种汽车类型,对吧?)。 FactoryOfAbstractClass.newInstance() 的返回类型是 Car。所以编译器不知道这个方法返回的 Car 的具体类型。它可能是梅赛德斯,但也可能是福特、标致或大众汽车。但是您将结果分配给T(在本例中为Mercedes)。所以没有强制转换就无法编译。

坦率地说,这个工厂完全没有必要。由于调用者应该传递要使用的类,因此您可以只获取该类的实例而不是工厂,从而让调用者创建实例。或者您可以将Supplier&lt;AbstractClass&gt; 作为参数,调用者只需传递ConcreteClass1::new。这将使代码更简单、更安全、更可扩展(因为您不会仅限于两个已知的子类)。

【讨论】:

  • 这就是泛型类型擦除的全部内容,您可以在此处获得更多详细信息:docs.oracle.com/javase/tutorial/java/generics/genTypes.html
  • 不,与类型擦除无关。
  • 编译器必须用一些东西替换T。在这种情况下,public &lt;T extends AbstractClass&gt; T method1(...)T 仅受 AbsctractClass 限制,因此编译器时的 T 将替换为 AbstractClass。用某些东西替换 T 是类型擦除,不是吗?你的不同车型的例子就是这样。
  • 不,不是。如果类型没有被擦除,你会遇到同样的编译错误,因为无论 T 是否被擦除,工厂返回的 AbstractClass 实例可能是 T 以外的其他类型。
  • 之所以不能传递实例是因为在服务类内部的某些方法中,要求返回List而不是T。在示例中的这个方法中,是的你没错,可以传一个实例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-05
  • 2015-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多