为什么我们不能使用 super class 的引用变量来访问其 subclass 的方法(super class 中不可用的方法)?

why cant we use a reference variable of super class to access methods of its subclass(methods not available in super class)?

我知道,无论引用变量引用的实际对象是什么,我可以调用引用的方法取决于变量的声明类型(在代码的第 15 行)。我想知道为什么so.Why用户不能class使用Shape类型的引用变量s调用它的subclass方法drawCircle()?

    public class Shape{
            public void displayShape(){
               System.out.println("shape displayed");
                      }
    public class Circle extends Shape{
            public void drawCircle(){
                System.out.println("circle drawn");
                      }
    public class Test{
            p.s.v.main(String[] a){
            Circle c=new Circle();
            Shape s=new Shape();
            display(c);
            display(s);
            public void display(Shape myShape){
               myShape.displayShape();//possible for ref variable c and s
               myShape.drawCircle();//not possible for reference var s
               }
             }
         }

你能解释一下在对象级别发生了什么吗?我是 java 的新手。

首先,您忘记制作 ShapeCircle subclass。

然后你说:

The methods i can call on a reference is dependent on the declared type of the variable

但是Shape myShape参数也是一个变量:

 public void display(Shape myShape){
    ...
    myShape.drawCircle();
 }

所以这里也是,对于局部变量或者字段变量,编译器只依赖声明的类型来绑定调用的方法。
由于 Shape class 用作声明变量的类型,因此只能调用此 class 的方法。

如果您确定 myShape 是一个 Circle,您可以明确地将其转换为一个 ((Circle)myShape).drawCircle();Circle myCircle = (Circle)myShape; myCircle.drawCircle(); 但如果你这样做并且它实际上不是 Circle 那么你将得到 ClassCastException

通常,您想尝试避免这种类型的转换,因为它有点代码味道,表明您的设计有点不对劲。 (有时你确实需要这样做,但它没有利用多态性)。

要利用多态性,您需要 ShapedisplayShape() 定义为抽象方法,然后代替 drawCircle()drawSquare() 等...每个子类Shape 将有自己的 displayShape() 方法版本,而在 Shape 中你将拥有: public abstract displayShape(); 这是一种告诉编译器 "all my subclasses will have this displayShape() method so when someone calls displayShape() on one of me, use the one defined in that subclass".

的方式

例如:

Shape myCircle = new Circle();
Shape mySquare = new Square();
myCircle.displayShape(); //draws a circle
mySquare.displayShape(); //draws a square

//And if you can't choose which one you want...
Shape surpriseMe = new Random().nextBoolean() ? myCircle : mySquare;
surpriseMe.displayShape(); //draws either a circle or a square!

reading about polymorphism.

怎么样
public abstract class Shape {
   public abstract void draw();
}

public class Circle extends Shape {
    @Override
    public void draw() {
       System.out.println("Circle drawed");
    }
}

public class Triangle extends Shape {
    @Override
    public void draw() {
       System.out.println("Triangle drawed");
    }
}

public class Test() {
   public static void display(Shape shape) {
      shape.draw();
   }

   public static void main(String[] args) {
      //how can you define "shape" in real world? its triangle or... -> abstraction
      Circle c = new Circle();
      Triangle t = new Triangle();

      display(c);
      display(t);
   } 
}

编译器只知道 myShape 是一个 Shape 类型的引用变量,它只包含一个方法 displayShape() ,所以根据编译器,调用是不可能的Shape class 不包含的方法 drawCircle()

编译器不关心这个变量在运行时持有什么对象。您可以在稍后的某个时间点从 Shape class 扩展另一个 class,并使用 myShape 引用来保存该子 class 对象。编译器只关心 myShape 在编译时是什么类型。

如果您的 Circle class 碰巧覆盖了 displayShape() 方法,如下所示:

public class Circle extends Shape {
    public void displayShape() {
        System.out.println("I am a Circle!");
    }

    public void drawCircle() {
    // Implementation here
    }
}

在运行时发生的唯一决定是调用哪个 displayShape() 方法。