1

我已经尝试为此寻找答案,但找不到确切的答案......情况如下。我有一个类和一个子类,我这样定义它们:

public class Shape{
   public methodA{
     System.out.println("Hello!");
  }
}

public class Square extends Shape{
   public methodB{
     System.out.println("I'm a Square!);
  }
}

主要是,我像这样实例化它们,但现在我无法调用methodB,因为我“给”了(不确定这里的术语)类型Shape:

Shape square = new Square();
square.methodB() // This doesn't work.

如果我还想调用子类的方法,我是不是把这一切都设计错了?我这样做是因为我有许多从 Shape 类继承的形状,但我不想将每个形状类都导入到我的项目中。我尝试搜索,但没有以我理解的方式找到答案。谢谢。

-RB

4

4 回答 4

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();,它会打印“I'm a square”。

于 2013-09-03T23:16:10.820 回答
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?

真的没有什么合理的事情可以做。因此,为了防止您编写这样的代码,编译器会检查您的所有方法是否存在于您正在使用的引用类型上。的类型squareShape,而Shape 可能没有methodB,因此您会看到错误。

在第一个修复中,我们告诉编译器square是 type Square,所以它允许我们调用它的方法。如果您知道自己需要 Square 的方法并创建了 Square,这将很有用。

在第二个修复中,我们稍后告诉编译器我们知道这个东西是 a Square,即使 Java 只知道它是 a Shape。如果您已经(通过代码)确定对象必须是 a ,这很好Square,但它绕过了 Java 的键入帮助。这有可能失败;如果您尝试对 a 执行此操作Circle,Java 将在运行时抛出 a ClassCastException

于 2013-09-03T23:22:30.123 回答
1

你需要决定你想要什么。

多态性的要点是,您可以通过编程到共同的内容(接口或基类或抽象类)来抽象出特定于实现的细节。

如果我还想调用子类的方法,我是不是设计错了?

我不知道你的意图,但可能不是。如果您希望能够在这种特殊情况下调用子类的方法,只需更改引用类型

Square square = new Square();
square.methodB() // This doesn't work.

如果您通常希望能够从任何地方对任何形状调用methodB,那么您需要在Shape 本身而不是Square 中定义methodB。

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。

于 2013-09-03T23:31:59.450 回答
0

你的设计是错误的。如果在代码中的某处将其他子类对象(不实现 methodB())分配给 Shape 类变量,然后调用 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 文件

于 2013-09-03T23:45:51.093 回答