【问题标题】:Create instance of a class not known at compile time创建编译时未知的类的实例
【发布时间】:2014-02-07 16:30:36
【问题描述】:

我有一个抽象类:

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"; 

    }
}

【问题讨论】:

  • 我不明白,这门课是MagicRoom?

标签: java design-patterns inheritance reflection


【解决方案1】:

使该方法通用:

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

【讨论】:

  • 测试并接受,不幸的是,我没有足够的声望点来支持答案。
  • 点击答案评分下方的勾号以接受答案。我认为任何人都可以投票?
【解决方案2】:

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

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

另外,我知道这只是一个示例,但您应该将这些属性设为私有并使用访问器/修改器方法。

例如

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

}

【讨论】:

  • Rohit 的回答实际上是我的更好的选择,但您仍然应该避免公开属性。
  • 感谢您的回答,您将属性公开是对的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-18
  • 1970-01-01
  • 1970-01-01
  • 2020-06-25
相关资源
最近更新 更多