简体   繁体   English

为什么我们不能使用父类的引用变量来访问其子类的方法(方法在父类中不可用)?

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

I know that,No matter what the actual object is,that the reference variable refers to,The methods i can call on a reference is dependent on the declared type of the variable (in line 15 of code).I want to know why so.Why can't the class user use the reference variable s of type Shape to call its subclass method drawCircle()? 我知道,无论实际对象是什么,引用变量所引用的是,我可以在引用上调用的方法取决于变量的声明类型(在代码第15行中)。我想知道为什么会这样为什么类用户不能使用Shape类型的引用变量调用其子类方法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
               }
             }
         }

Can u provide me an explanation of what happens at the object level?I am new to java. 你能给我解释一下在对象级别会发生什么吗?

First, you forgot to make Circle subclass of Shape . 首先,您忘记将Shape Circle子类化。

Then you said : 然后你说:

The methods i can call on a reference is dependent on the declared type of the variable 我可以在引用上调用的方法取决于变量的声明类型

But the Shape myShape parameter is also a variable : 但是Shape myShape参数也是一个变量:

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

So also here, as for a local variable or a field variable, the compiler relies only the declared type to bound the invoked method. 同样在这里,对于局部变量或字段变量,编译器仅依靠声明的类型来绑定调用的方法。
And as the Shape class is used as the type of the declared variable, only methods of this class may be invoked on. 由于Shape类用作声明的变量的类型,因此只能调用此类的方法。

If you are sure that myShape is a Circle you can explicitly cast it to one ((Circle)myShape).drawCircle(); 如果确定myShape是一个Circle,则可以将其显式转换为一个((Circle)myShape).drawCircle(); or Circle myCircle = (Circle)myShape; myCircle.drawCircle(); 或者Circle myCircle = (Circle)myShape; myCircle.drawCircle(); Circle myCircle = (Circle)myShape; myCircle.drawCircle(); but if you do that and it isn't actually a Circle then you will get a ClassCastException . 但是,如果您这样做却实际上不是一个Circle ,则将收到ClassCastException

Generally, you want to try and avoid this sort of casting though as its something of a code smell which suggests your design is a bit off. 通常,您希望尝试避免这种类型的转换,尽管它具有某种代码味道,这表明您的设计有些偏离。 (Sometimes you do need to do it, but its not taking advantage of polymorphism). (有时您确实需要这样做,但是它没有利用多态性)。

To take advantage of polymorphism you would instead have Shape define displayShape() as an abstract method and then instead of drawCircle() , drawSquare() etc... each subclass of Shape will have its own version of the displayShape() method, while in Shape itself you would have: public abstract displayShape(); 为了利用多态性,您可以将Shape定义为displayShape()作为抽象方法,然后代替drawCircle()drawSquare()等... Shape每个子类都具有自己的displayShape()方法版本,而在Shape本身中,您将拥有: public abstract displayShape(); which is a way of telling the compiler "all my subclasses will have this displayShape() method so when someone calls displayShape() on one of me, use the one defined in that subclass". 这是一种告诉编译器的方式“我的所有子类都将具有此displayShape()方法,因此当有人在我其中一个上调用displayShape()时,请使用该子类中定义的那个”。

So for example: 因此,例如:

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!

How about 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);
   } 
}

The compiler just knows that myShape is a reference variable of type Shape , which contains only one method displayShape() , so according to the compiler, it is not possible to call a method drawCircle() which the Shape class does not contain. 编译器只知道myShapeShape类型的引用变量,它仅包含一个方法displayShape() ,因此根据编译器,不可能调用Shape类不包含的方法drawCircle()

The compiler is not concerned with what object this variable will hold at runtime. 编译器与该变量在运行时将保留的对象无关。 You may extend another class from the Shape class at some later point of time, and use the myShape reference to hold that subclass object. 您可以在稍后的某个时间点从Shape类扩展另一个类,并使用myShape引用保存该子类对象。 The compiler is just concerned with what type myShape is at compile-time. 编译器只关心myShape在编译时的类型。

If your Circle class happened to override the displayShape() method, like below : 如果您的Circle类碰巧覆盖了displayShape()方法,如下所示:

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

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

the only decision happening at runtime would be which displayShape() method to call. 在运行时发生的唯一决定是调用哪个displayShape()方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM