这种对超类和子类的访问限制背后的原因是什么?

What's the reason behind this access restriction for superclass and subclass?

我正在尝试理解我的代码的最后一条语句在 Java 中是非法的原因。请参阅下面的评论。

public class Rectangle {

private int height;
private int width;

public Rectangle(int height, int width) {
    this.height = height;
    this.width = width;
  }

}

class ColoredRectangle extends Rectangle {
private String color;

public ColoredRectangle(int height, int width, String color) {
    super(height, width);
    this.color = color;
}

public String getColor() {
    return color;
}

public static void main(String[] args) {
    ColoredRectangle blueRectangle = new ColoredRectangle(2, 4, "blue");
    Rectangle sameObjectDifferentType = blueRectangle;
    ((ColoredRectangle) sameObjectDifferentType).getColor(); //Will compile
    sameObjectDifferentType.getColor();  //Won't compile 
  }
}

我知道我不应该使用这种设计,而是使用不同的构造函数。我知道 getColor() 是 "not defined in Rectangle." 尽管如此,我对这段代码的看法是:sameObjectDifferentType 是对既是 Rectangle 又是 ColoredRectangle 的对象的引用,因此我应该能够访问所有它的成员,无论我是将引用声明为 Rectangle 还是 ColoredRectangle。那么...为什么Java是这样设计的呢?

Rectangle sameObjectDifferentType = blueRectangle;

当您进行这样的声明时,您是在明确告诉编译器它应该被视为 Rectangle。虽然在这种情况下它可能是 ColoredRectangle,但该保证很快就会消失。

在这一行中,您声明 sameObjectDifferentType 属于 Rectangle

类型
Rectangle sameObjectDifferentType = blueRectangle;

在更多真实世界的示例中,这将允许您拥有几种不同的类型,您希望以相同的方式处理它们。 classic 示例是 CurrentAccountCheckingAccountSavingsAccount,它们都继承自 Account

假设您的银行应用程序具有用于查找帐户并找出帐户持有人的代码。该代码将只处理抽象 Account 类型。这意味着将来当你引入一个 StudentAccount 时,如果它继承自 Account 你可以在你当前处理 Account 的所有地方使用一个 StudentAccount 而无需更改代码。

假设您的示例中有 FilledRectangleWireFrameRegtangle。你可以有一个适用于所有矩形的 calculateArea(Rectangle rect) 方法。

但是,为了获得这种能力和灵活性而做出的一个折衷是,当您将一个对象声明为超类时,您将失去直接处理子类class属性的能力class 类型,所以

sameObjectDifferentType.getColor();  //Won't compile 

但是,Java 确实为您提供了一种返回子 class 的方法,正如您通过转换注意到的那样:

((ColoredRectangle) sameObjectDifferentType).getColor(); //Will compile

作为开发人员,您知道 sameObjectDifferentType 实际上是一个 ColoredRectangle,所以您可以放心地 cast.However 如果您这样做了

((FilledRectangle) sameObjectDifferentType).getFillPattern(); 

你最终会得到 运行 次 ClassCastException

希望这对您有所帮助。