Java 子类和超类方法

Java 子类和超类方法,java,inheritance,subclass,superclass,Java,Inheritance,Subclass,Superclass,我正在用不同类型的方块创造一个垄断游戏。 Square是超类,PropertySquare是子类 我已经创建了一个循环,可以滚动骰子并将玩家移动到另一个方块。正方形在数组列表中,我可以调用它们的超类方法。但是,即使将正方形设置为更具体的类型(square的子类),我也不能对它们调用子类方法 这就是我在board类中初始化正方形的方式 private static final ArrayList<Square> squares = new ArrayList<Square>

我正在用不同类型的方块创造一个垄断游戏。
Square
超类
PropertySquare
子类

我已经创建了一个循环,可以滚动骰子并将玩家移动到另一个方块。正方形在数组列表中,我可以调用它们的超类方法。但是,即使将正方形设置为更具体的类型(square的子类),我也不能对它们调用子类方法

这就是我在board类中初始化正方形的方式

private static final ArrayList<Square> squares = new ArrayList<Square>(40);
squares.add(1, new PropertySquare("Old Kent Road", 1, 60, "Brown"));
board.getSquare(pos).getName());
private static final ArrayList squares=新的ArrayList(40);
新增(1,新地产广场(“老肯特路”,1,60,“棕色”);
board.getSquare(pos.getName());
getName
是超类正方形中的一个方法。但是,即使square是属性类型,我也不能调用
PropertySquare
类中的方法,例如
getPrice()


我该如何更改此方法或调用子类方法?

我假设
board.getSquare()
返回一个
Square
,并且
Square
没有任何
getPrice()
方法,因此不能对声明为
Square
的对象调用
getPrice()
,即使实例实际上是一个
PropertySquare
(也称)。为此,您必须首先强制转换到特定的子类。例如:

final Square square = board.getSquare(pos);
if (square instanceof PropertySquare) {
    ((PropertySquare)square).getPrice();
}

注:我将以更一般的意义来回答这个问题,我意识到并不是所有的垄断广场都有价格。。。但问题本身,在代码中,可以通过两种方式解决

如果所有项目都有价格,那么您可能希望使用“抽象”基类

然后在超类中放入方法,如下所示

protected abstract int getPrice();
并在子类中实现它

所以你可以有一些子类,比如undevelopedSquare,propertySquare,gardenSquare等等

但是,在垄断的情况下,如果只有propertySquare实例具有getPrice,则应该使用

if (square instanceOf PropertySquare) {
    price = ((PropertySquare)square).getPrice();
}
NB2:你也有“公用事业广场”,比如自来水厂,除了价格之外还有不同的物业(即使你可以买,你也不能在公用事业上建酒店)

因此,在这种情况下,接口可能更合适,例如:

interface PlayableSquare -> Generic square things, you can land on one for instance

interface SaleableSquare -> has pricing etc

interface BuildableSquare -> can build hotels
然后让你的通用as

private static final ArrayList<? extends Square> squares
其中抽象类实现了“PlayableSquare”。虽然这可能是一个太远的步骤,因为它几乎只是一个标记接口


您可以使用instanceOf检查每个接口实现,即,如果实用程序具有您希望调用的不同方法。

您应该在ArrayList中使用泛型。 如果您的列表仅包含类型为
的PropertySquare
,请执行以下操作:

private static final ArrayList<PropertySquare> squares = new ArrayList<>(40);
squares.add(1, new PropertySquare("Old Kent Road", 1, 60, "Brown"));
private static final ArrayList<Square> squares = new ArrayList<>(40);
squares.add(1, new PropertySquare("Old Kent Road", 1, 60, "Brown"));
Square sq = squares.get(0);
if(sq instanceof PropertySquare){
    PropertySquare pSq = (PropertySquare) sq;
    //now you can use any method of PropertySquare
}

代码中的问题是,您的对象是Square类型,不知道任何子类的方法。因此,您必须进行类型转换。

您可以在一组ifs中处理着陆方块,如:

if (square instanceof PropertySquare) {
    ((PropertySquare)square).getPrice();
}else if(square instanceof PrisonSquare) {
//do nothing 
}//etc..

声明的
ArrayList
绑定到
Square
,这意味着您将拥有
Square
对象的集合,并在与任何项交互时拥有
Square
引用,尽管在运行时它是子类的实例。这就是所谓的多态性

由于引用的类型是
Square
,Java所知道的唯一方法是
Square
中声明的方法和任何其他继承的方法。为了能够调用子类的方法,您需要检查引用是否指向
PropertySquare
的实例,然后向下转换
PropertySquare
的引用。然后您会说,我知道它是
PropertySquare
的一个实例,所以我可以安全地调用
PropertySquare
中声明的
getPrice()
方法

if (square instanceof PropertySquare) {
    ((PropertySquare)square).getPrice();
}
或者,您可以查看实例类名:

square.getClass().getSimpleName();  // Would just give you PropertySquare
square.getClass().getCanonicalName(); // Would give you the fully qualified name e.g. com.foo.bar.PropertySquare
有关更多信息:


张贴
getSquare
的签名。如果您正在查看的正方形不是
PropertySquare
并且您尝试在其上调用
getPrice()
,该怎么办?您知道强制转换吗?这缺少子类型多态性的要点,请参阅:“使用指向基类的指针或引用的函数必须能够在不知情的情况下使用派生类的对象。“Liskov换句话说:如果你必须使用
instanceof
,那么使用子类就没有意义了,因为你也可以使用带有
列表的任意类。谢谢你,这对我帮助很大。我可能会改变一切并使用接口,但目前instanceof方法仍然有效。
square.getClass().getSimpleName();  // Would just give you PropertySquare
square.getClass().getCanonicalName(); // Would give you the fully qualified name e.g. com.foo.bar.PropertySquare