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