尝试调用子方法,但将其实例化为父方法

时间:2013-09-03 23:13:57

标签: java

我已经尝试过为此寻找答案,但找不到答案......这就是情况。我有一个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

4 个答案:

答案 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文件