Java generics and reflection: class loading

cypherman :

I am given some classes that are unknown to me. Some of them are shown as an example:

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
  }

}

The task is to redesign method signature types if needed and to add implementation. The bake method should conform to the following:

  • Create objects of class Bakery or any subclass of it according to class argument
  • Flag compile-time error if order argument is not Bakery or any subclass of it (e.g. if it is Paper or Object)

Whatever I've tried I'm getting an error: Main.java:: error: incompatible types: Object cannot be converted to Cake Cake cake = baker.bake(Cake.class);

The best I've come up with is this:

public Object bake(Class order) throws Exception { return order.getDeclaredConstructor().newInstance();

I know that it's wrong but I'm completely stuck here. Could someone please explain what's going on?

Ravindra Ranwala :

Your methods return type is java.lang.Object and the compiler can't vouch that the return value is of type Cake unless you convince the compiler by adding an explicit unchecked cast like this.

Cake cake = (Cake) ReflexiveBaker.bake(Cake.class);

This unchecked cast is error prone and awkward. Say you have another class called Bread that is a subtype of Bakery and you pass that class instance expecting Cake as the return type. The above statement still compiles, but throws a ClassCastException at runtime.

A much better approach is to generify the method using a bounded type parameter such a way that it accepts only sub types of Bakery and returns the same type as the type parameter of the class object provided. Here's one such attempt.

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

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=414622&siteId=1