我已经尝试过为此寻找答案,但找不到答案......这就是情况。我有一个Class和一个子类,我这样定义它们:
public class Shape{
public methodA{
System.out.println("Hello!");
}
}
public class Square extends Shape{
public methodB{
System.out.println("I'm a Square!);
}
}
在main中,我像这样实例化它们但现在我无法调用methodB因为我“给了”(这里不确定术语)它的类型Shape:
Shape square = new Square();
square.methodB() // This doesn't work.
如果我想能够调用子类的方法,我是否只是设计了这个错误?我这样做是因为我有许多从Shape类继承的形状,但我不想将每个形状类导入到我的项目中。我试着搜索,但没有找到我理解的方式的答案。感谢。
-RB
答案 0 :(得分:4)
它不起作用,因为methodB()
未在父类中定义,即Shape
类。为了解决这个问题,您必须在Shape
类(或者更常见的是Shape
的任何子类)中创建方法,然后您可以在Square
类中重写该方法改变它的行为。所以你可以修改它看起来像这样:
public class Shape{
public void methodA(){
System.out.println("Hello");
}
public void methodB(){
System.out.println("I'm a shape");
}
}
public class Square extends Shape{
public void methodB(){
System.out.println("I'm a square");
}
}
现在,当您执行Shape shape = new Square();
并调用shape.methodB();
时,它将打印“我是一个正方形”。
答案 1 :(得分:1)
这将有效:
Square square = new Square();
square.methodB();
就像这样:
Shape square = new Square();
((Square)square).methodB();
编译器不能允许您的原始版本,因为如果您执行以下操作会怎样:
Shape square = new Circle(); // what!
square.methodB(); // What the heck happens here?
没有合理的事情可做。因此,为了防止您编写这样的代码,编译器会检查您正在使用的引用类型上是否存在所有方法。 square
的类型为Shape
,而Shape
可能没有methodB
,因此您会看到错误。
在第一个修复中,我们告诉编译器square
类型为Square
,因此它允许我们调用它的方法。如果您知道需要使用square方法,并且创建了Square,那么这很有用。
在第二个修复中,我们告诉编译器稍后我们知道这个东西是Square
,即使Java只知道它是Shape
。如果您已经(通过代码)想出一个对象必须是Square
,那么这很好,但它绕过了Java的输入帮助。这有可能失败;如果您尝试对Circle
执行此操作,Java将在运行时抛出ClassCastException
。
答案 2 :(得分:1)
你需要决定你想要什么。
多态性的一点是,您可以通过编程到通用(接口或基类或抽象类)来抽象出特定于实现的细节。
如果我想能够同时调用子类'方法
,我是否只是设计了这个错误
我不知道你的意图,但可能不是。如果您希望能够在此特定情况下调用子类的方法,只需更改引用类型
Square square = new Square();
square.methodB() // This doesn't work.
如果你一般希望能够从任何地方调用任何形状的methodB,那么你需要在Shape本身中定义methodB,而不是Square。
public class Shape{
public void methodA{
System.out.println("Hello!");
}
public abstract void methodB();
}
public class Square extends Shape{
public void methodB{
System.out.println("I'm a Square!);
}
}
现在任何形状都保证有一个methodB方法。
要记住的关键是,当您实例化一个对象时,引用类型是唯一一个被继承的对象。调用Shape s = new Square()
时,编译器仅为其构造函数使用Square。一旦被召唤,它会忘记任何有关它的知识,因为你这么说。因此,s.methodB()
将无法编译,因为编译器不知道s是方形,圆形,三角形等。你告诉它忘记了。
如果关于只能在正方形上使用的正方形,则调用代码需要使用Square类而不是Shape。
答案 3 :(得分:0)
你的设计错了。如果你在代码中的某个地方为Shape类变量分配了一些其他子类对象(它没有实现methodB()),然后调用了methodB(),那么Java当时应该做些什么呢?
考虑一下:
class Animal { public void move() {} };
class Human extends Animal { public void talk() {} };
class Dog extends Animal { public void wagTail() {} };
void processAnimal(Animal a) {
a.move(); // Valid: All animals can walk
a.talk(); // INVALID: All animals are not known to be able to talk
a.wagTail(); // INVALID: All animals are not known to be able to wag tail
}
void processHuman(Human m) {
m.move(); // Valid: All animals can walk and Man is an animal
m.talk(); // Valid: All humans can talk
m.wagTail(); // INVALID: Humans can NOT wag tail
}
void processDog(Dog g) {
g.move(); // Valid: All animals can walk and dogs are animals
g.talk(); // INVALID: Dogs can NOT talk
g.wagTail(); // Valid: All dogs can wag tail
}
// These are good. ProcessAnimal() expects an animal and all 3 arguments below are animals
processAnimal(new Animal());
processAnimal(new Human());
processAnimal(new Dog());
processHuman(new Animal()); // INVALID: Expecting a specialized Animal, namely Human, which can talk
processHuman(new Human()); // Valid
processHuman(new Dog()); // INVALID: Expecting Human, which can talk
processDog(new Animal()); // INVALID: Expecting a specialized Animal, namely Dog, which can bark
processDog(new Human()); // INVALID: Expecting Dog, which can bark
processDog(new Dog()); // Valid
为您修复:
if (square instanceof Square) {
Square identifiedSquare = (Square) square;
identifiedSquare.methodB();
}
您无法避免将Square类导入java文件