你好!您已经在使用 Java 方法并且对它们了解很多。您可能遇到过这样的情况,一个类有许多名称相同但参数不同的方法。您会记得在那些情况下我们使用了方法重载。今天我们考虑另一种情况。想象一下,我们有一个共享方法,但它必须在不同的类中做不同的事情。我们如何实现这种行为?为了便于理解,让我们考虑一个代表动物的Animal父类,我们将在其中 创建一个speak方法:
public class Animal {
public void speak() {
System.out.println("Hello!");
}
}
虽然我们才刚刚开始编写程序,但您可能会看到一个潜在的问题:世界上有很多动物,它们“说话”的方式都不一样:猫喵喵叫、鸭子嘎嘎叫、蛇嘶嘶叫。 我们的目标很简单:避免创建大量的说话方法。我们不想创建用于喵喵叫的catSpeak()方法、用于发出嘶嘶声的snakeSpeak()方法等,而是调用speak()方法,让蛇发出嘶嘶声、猫叫声和狗叫声。我们可以使用方法覆盖轻松实现这一点。维基百科对术语“覆盖”给出了以下解释:方法覆盖,在面向对象的编程中,是一种语言特性,它允许子类或子类提供其超类之一已经提供的方法的特定实现或父类 这基本上是正确的。方法覆盖让你可以使用父类的一些方法并在每个子类中编写你自己的实现。新实现“替换”了父类在子类中的实现。让我们看看这在示例中的样子。创建 4 个继承我们的Animal类的类:
public class Bear extends Animal {
@Override
public void speak() {
System.out.println("Growl!");
}
}
public class Cat extends Animal {
@Override
public void speak() {
System.out.println("Meow!");
}
}
public class Dog extends Animal {
@Override
public void speak() {
System.out.println("Woof!");
}
}
public class Snake extends Animal {
@Override
public void speak() {
System.out.println("Hiss!");
}
}
“这是未来的一个小技巧:要覆盖父类的方法,请转到 IntelliJ IDE 中的子类代码,单击 Ctrl+O,然后在菜单中选择“覆盖方法...”。习惯使用热键从一开始——它会帮助你更快地编写程序!为了指定我们需要的行为,我们做了一些事情:
- 在每个子类中,我们创建了一个与父类方法同名的方法。
- 我们告诉编译器,将方法命名为与父类中相同的名称并非偶然:我们想要覆盖它的行为。为了将此信息传达给编译器,我们在方法上方设置了@Override 注释。
当放在方法上方时,@Override 注释会通知编译器(以及阅读您的代码的程序员):'一切正常。这不是错误。我不是健忘。我知道这样的方法已经存在,我想覆盖它'。 - 我们为每个子类编写了我们需要的实现。当调用speak()方法时,蛇应该发出嘶嘶声,熊应该咆哮,等等。
public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog();
Animal animal2 = new Cat();
Animal animal3 = new Bear();
Animal animal4 = new Snake();
animal1.speak();
animal2.speak();
animal3.speak();
animal4.speak();
}
}
控制台输出:
Woof!
Meow!
Growl!
Hiss!
出色的!一切正常!我们创建了 4 个存储Animal父类对象的引用变量,并将 4 个不同子类的实例分配给它们。因此,每个对象都表现出自己的行为。对于每个子类,覆盖的speak()方法替换了Animal类中的“本地” speak()方法(它只显示“Hello!”)。 覆盖有几个限制:
-
重写的方法必须具有与父方法相同的参数。
如果父类的speak方法有一个String参数,那么子类中被重写的方法也必须有一个String参数。否则,编译器会产生一个错误:
public class Animal { public void speak(String s) { System.out.println("Hello! " + s); } } public class Cat extends Animal { @Override // Error! public void speak() { System.out.println("Meow!"); } }
-
重写的方法必须与父方法具有相同的返回类型。
否则,我们会得到一个编译器错误:
public class Animal { public void speak() { System.out.println("Hello!"); } } public class Cat extends Animal { @Override public String speak() { // Error! System.out.println("Meow!"); return "Meow!"; } }
-
重写方法的访问修饰符也必须与“原始”方法相同:
public class Animal { public void speak() { System.out.println("Hello!"); } } public class Cat extends Animal { @Override private void speak() { // Error! System.out.println("Meow!"); } }
GO TO FULL VERSION