创建在编译时未知的类的实例

时间:2014-02-07 16:30:37

标签: java design-patterns inheritance reflection

我有一个抽象类:

public abstract class Room {

}

和在编译时未知的继承类,如:

public class MagicRoom extends Room {

    public MagicRoom(){
        System.out.println("Creating a MagicRoom.");
    }

    public String magic = "";
}

或:

public class Dungeon extends Room {

    public Dungeon(){
        System.out.println("Creating a Dungeon");
    }

    public String keeper = "";
}

我有一个类,我将从以下位置创建这些类的实例:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class MazeGame {

    public static Room makeRoom(Class roomClass) 
        throws IllegalArgumentException, InstantiationException, 
            IllegalAccessException, InvocationTargetException, 
            SecurityException, NoSuchMethodException{

        Constructor c = roomClass.getConstructor();
        return c.newInstance();

    }

}

makeRoom是我尝试创建一个继承自Room的类,我在编译时不知道这个类,但是我不确定将什么作为其返回类型而不是Room。因为makeRoom返回一个Room,如果我尝试使用属于继承类的字段,我会得到一个异常:

import java.lang.reflect.InvocationTargetException;

public class FactoryTest {

    public static void main(String[] args) 
        throws IllegalArgumentException, SecurityException, 
            InstantiationException, IllegalAccessException, 
            InvocationTargetException, NoSuchMethodException{

        MazeGame game = new MazeGame();

        Room magicRoom = MazeGame.makeRoom(MagicRoom.class);

        /*
         * Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
         * magic cannot be resolved or is not a field
         */

        magicRoom.magic = "a"; 

    }
}

2 个答案:

答案 0 :(得分:5)

使该方法具有通用性:

public static <T extends Room> T makeRoom(Class<T> roomClass) 
    throws IllegalArgumentException, InstantiationException, 
        IllegalAccessException, InvocationTargetException, 
        SecurityException, NoSuchMethodException{

    // This is enough, if you have 0-arg constructor in all your subclasses
    return roomClass.newInstance();
}

然后调用它:

MagicRoom magicRoom = MazeGame.makeRoom(MagicRoom.class);  

答案 1 :(得分:2)

您必须将Room对象强制转换为MagicRoom。

MagicRoom magicRoom = (MagicRoom) MazeGame.makeRoom(MagicRoom.class);

另外,我知道这只是一个例子,但你应该将这些属性设为私有并使用accessor / mutator方法。

e.g。

public class MagicRoom extends Room {

  public MagicRoom(){
    System.out.println("Creating a MagicRoom.");
  }

  private String magic = "";

  public String getMagic() {
    return this.magic;
  }

  public void setMagic(String magic) {
    this.magic = magic;
  }

}