0

我知道,无论实际对象是什么,引用变量指的是什么,我可以在引用上调用的方法取决于变量的声明类型(在代码的第 15 行)。我想知道为什么.为什么类用户不能使用Shape类型的引用变量s来调用它的子类方法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新手。

4

4 回答 4

0

首先,您忘记Circle创建Shape.

然后你说:

我可以在引用上调用的方法取决于变量的声明类型

Shape myShape参数也是一个变量:

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

同样在这里,对于局部变量或字段变量,编译器仅依赖声明的类型来绑定调用的方法。
并且由于Shape该类用作声明变量的类型,因此只能调用该类的方法。

于 2017-07-15T08:15:09.867 回答
0

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

一般来说,你想尽量避免这种类型的转换,因为它有点代码味道,这表明你的设计有点偏离。(有时您确实需要这样做,但它没有利用多态性)。

为了利用多态性,您将改为Shape定义displayShape()为抽象方法,然后代替drawCircle(),drawSquare()等等...的每个子类Shape都有自己的displayShape()方法版本,而Shape您本身将拥有: public abstract displayShape();这是告诉编译器的一种方式“我的所有子类都将具有此 displayShape() 方法,因此当有人对我其中一个调用 displayShape() 时,请使用该子类中定义的方法”。

例如:

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!
于 2017-07-15T08:28:25.047 回答
0

如何阅读有关多态性的内容。

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);
   } 
}
于 2017-07-15T08:29:33.603 回答
0

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

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

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

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

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

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

于 2017-07-15T08:35:48.997 回答