Почему мы не можем использовать ссылочную переменную суперкласса для доступа к методам его подкласса (методы недоступны в суперклассе)?

Я знаю, что независимо от того, что является реальным объектом, на который ссылается ссылочная переменная, методы, которые я могу вызвать по ссылке, зависят от объявленного типа переменной (в строке 15 кода). Я хочу знать, почему так Почему пользователь класса не может использовать ссылочную переменную s типа 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
               }
             }
         }

Можете ли вы дать мне объяснение того, что происходит на уровне объекта? Я новичок в Java.

4 ответа

Решение

Компилятор просто знает, что 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() метод для вызова.

Если вы уверены, что myShape является Кругом, вы можете явно привести его к одному((Circle)myShape).drawCircle(); или же Circle myCircle = (Circle)myShape; myCircle.drawCircle(); но если вы сделаете это, и это на самом деле не Circle тогда вы получите 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!

Во-первых, вы забыли сделать Circle подкласс Shape,

Тогда вы сказали:

Методы, которые я могу вызвать по ссылке, зависят от объявленного типа переменной

Но Shape myShape Параметр также является переменной:

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

Также и здесь, что касается локальной переменной или переменной поля, компилятор полагается только на объявленный тип, чтобы связать вызываемый метод.
И как Shape Класс используется как тип объявленной переменной, только методы этого класса могут быть вызваны.

Как насчет чтения о полиморфизме.

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);
   } 
}
Другие вопросы по тегам