Java泛型和反射:类加载

cyp*_*man 5 java generics reflection

我接受了一些我不知道的课程。其中一些显示为示例:

class Paper {}

class Bakery {}

class Cake extends Bakery {}

class ReflexiveBaker {

  /**
   * Create bakery of the provided class.
   * 
   * @param order class of bakery to create
   * @return bakery object
   */
  public Object bake(Class order) {
    // Add implementation here
  }

}
Run Code Online (Sandbox Code Playgroud)

任务是根据需要重新设计方法签名类型并添加实现。烘焙方法应符合以下要求:

  • 根据类参数创建 Bakery 类或其任何子类的对象
  • 如果订单参数不是 Bakery 或其任何子类(例如,如果它是 Paper 或 Object),则标记编译时错误

无论我尝试过什么,我都会收到一个错误: Main.java:: error: incompatible types: Object cannot be convert to Cake Cake cake = baker.bake(Cake.class);

我想出的最好的是:

public Object bake(Class<? extends Bakery> order) throws Exception {
        return order.getDeclaredConstructor().newInstance();
}
Run Code Online (Sandbox Code Playgroud)

我知道这是错误的,但我完全被困在这里。有人可以解释一下发生了什么吗?

Rav*_*ala 6

您的方法返回类型是java.lang.Object,编译器不能保证返回值是类型,Cake除非您通过添加这样的显式未经检查的强制转换来说服编译器。

Cake cake = (Cake) ReflexiveBaker.bake(Cake.class);
Run Code Online (Sandbox Code Playgroud)

这种未经检查的强制转换容易出错且笨拙。假设您有另一个名为 Bread 的类,它是 的子类型,Bakery并且您传递该类实例并期望 Cake 作为返回类型。上面的语句仍然可以编译,但ClassCastException在运行时抛出 a 。

更好的方法是使用有界类型参数来泛化该方法,这样它就只接受 的子类型Bakery并返回与提供的类对象的类型参数相同的类型。这是一个这样的尝试。

static class ReflexiveBaker {
    public static <T extends Bakery> T bake(Class<T> order) {
        try {
            return order.getDeclaredConstructor().newInstance();
        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException
                    | InvocationTargetException e) {
            throw new AssertionError("Class could not be instantiated.", e);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)