目录
一、Override
在我们开始了解Java重写规则之前,先了解一个注解:Override,接下来我会借助这个注解和多态机制来阐述重写机制
在 Java 中,@Override 是一个注解(Annotation),用于指示一个方法是重写(Override)了父类或接口中的方法。它的主要作用是帮助开发者明确代码意图,并在编译时检查方法签名是否正确。如果方法签名不符合父类或接口的定义,编译器会抛出错误。
-
明确代码意图:告诉编译器和阅读代码的人,这个方法是重写父类或接口中的方法。
-
编译时检查:如果方法签名与父类或接口中的方法不匹配,编译器会报错,从而避免潜在的错误。
也就是说,如果给方法前面加上override注解,而编译器又不报错的情况下,就是重写成功了
二、父类与子类
1.实例方法与实例方法
1.1正常情况可以重写
代码
public class Person
{
protected String name;
protected int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void show()
{
System.out.println("姓名:"+name+" 年龄:"+age);
}
}
class Student extends Person
{
private String id;
private String major;
public Student(String name, int age, String id, String major) {
super(name, age);
this.id = id;
this.major = major;
}
@Override
public void show()
{
System.out.println("姓名:"+super.name+" 年龄:"+age+" 学号:"+id+" 专业:"+major);
}
}
class Test
{
public static void main(String[] args)
{
//重写
Student s=new Student("小明",19,"23100666","计科");
s.show();
//多态
Person p=new Student("小美",20,"8888","计科");
p.show();
}
}
运行结果

1.1不能重写的几种特殊情况
(1)子类重写的访问权限不能比父类低(严格),若父类方法是public,则子类也必须是public,不能是protected或private,若违反则报错如下:

(2) 父类方法是private权限时,子类不能重写,只能“隐藏”
若用override尝试重写,报错如下:

这其实已经证明不能重写了,下面我们通过一个例子证明是“隐藏”而非“重写”:
代码
class Parent {
private void privateMethod() {
System.out.println("This is a private method in Parent.");
}
// 提供一个公共方法来调用 privateMethod
public void callPrivateMethod() {
privateMethod();
}
}
class Child extends Parent {
// 尝试重写父类的 private 方法
private void privateMethod() {
System.out.println("This is a private method in Child.");
}
public static void main(String[] args) {
Child child = new Child();
child.callPrivateMethod(); // 调用父类的公共方法
}
}
运行结果

可以看到,调用的是父类的方法,我们来对比一下访问权限为public时成功重写的情况
代码
class Parent {
public void publicMethod() {
System.out.println("This is a public method in Parent.");
}
// 提供一个公共方法来调用 publicMethod
public void callPrivateMethod() {
publicMethod();
}
}
class Child extends Parent {
// 尝试重写父类的 public 方法
public void publicMethod() {
System.out.println("This is a public method in Child.");
}
public static void main(String[] args) {
Child child = new Child();
child.callPrivateMethod(); // 调用父类的公共方法
}
}
运行结果

可以看到,成功重写时,调用的是子类的方法 、
(3)子类重写的方法不能比父类方法抛出更多的异常
这部分具体可见我的另一篇博客【Java】异常处理总结
2.实例方法与类方法
实例方法与类方法不能互相重写
这部分很好理解,重写本质上是为多态服务的,而多态访问方式应该一致,这就要求重写前后的访问方式应该不变,而实例方法和类方法的访问方式是不同的,因此不能互相重写
2.1实例方法不能被类方法重写
代码
class Parent {
public void display() {
System.out.println("Parent instance method");
}
}
class Child extends Parent {
// 尝试用实例方法重写父类的静态方法
public static void display() {
System.out.println("Child static method");
}
}
class Main {
public static void main(String[] args) {
Parent obj1 = new Child();
obj1.display(); // 调用的是Parent类的实例方法
Child obj2 = new Child();
obj2.display(); // 调用的是Child类的静态方法
}
}
报错

2.2类方法不能被实例方法重写
代码
class Parent {
public static void display() {
System.out.println("Parent static method");
}
}
class Child extends Parent {
// 尝试用实例方法重写父类的静态方法
public void display() {
System.out.println("Child instance method");
}
}
class Main {
public static void main(String[] args) {
Parent obj1 = new Child();
obj1.display(); // 调用的是Parent类的静态方法
Child obj2 = new Child();
obj2.display(); // 调用的是Child类的实例方法
}
}
运行结果

3.类方法与类方法
类方法不能被类方法重写,只是“隐藏”
尝试用override注解
代码
class Parent {
public static void display() {
System.out.println("Parent static method");
}
}
class Child extends Parent {
// 尝试重写父类的静态方法
@Override
public static void display() {
System.out.println("Child static method");
}
}
class Main {
public static void main(String[] args) {
Parent obj1 = new Child();
obj1.display();
Child obj2 = new Child();
obj2.display();
}
}
报错

不使用override注解时,是“隐藏”
代码
class Parent {
public static void display() {
System.out.println("Parent static method");
}
public void show()
{
display();
}
}
class Child extends Parent {
// 尝试重写父类的静态方法
public static void display() {
System.out.println("Child static method");
}
}
class Main {
public static void main(String[] args) {
Child obj = new Child();
obj.show();
}
}
运行结果

三、抽象类
首先需要明确,抽象类是可以含有抽象方法的特殊的类,因此服从<二、父类与子类>中的所有规则,除此以外,还需要考虑abstract,final修饰符等
总体来讲,这部分可以从这个角度来考虑:抽象方法存在的意义就是为了继承重写的,因此但凡是某个代表需要重写的修饰符和某个代表不能重写的修饰符混用,这就矛盾了,是错误的
(1)代表需要重写的修饰符:abstract
(2)代表不能重写的修饰符:final,static,private(还包含二.1中几个不能重写的特殊情况)
为了证明这一点,我们来看几个例子
1.abstract+final
代码
abstract class Parent {
final abstract public void display();
}
class Child extends Parent {
public void display() {
System.out.println("Child instance method");
}
}
class Main {
public static void main(String[] args) {
Child obj = new Child();
obj.display();
}
}
报错

2.abstract+static
代码
abstract class Parent {
abstract public static void display();
}
class Child extends Parent {
public static void display() {
System.out.println("Child static method");
}
}
class Main {
public static void main(String[] args) {
Child obj = new Child();
obj.display();
}
}
报错

3.abstract+访问权限降低
代码
abstract class Parent {
abstract public void display();
}
class Child extends Parent {
protected void display() {
System.out.println("Child static method");
}
public static void main(String[] args) {
Child obj = new Child();
obj.display();
}
}
报错

四、接口
接口的重写规则仍然服从上面说的基本规则,但还需考虑特殊情况
接口与类不同,接口的实现类可以实现多个接口,这种情况下,如果多个接口中定义了同名的默认方法,实现类必须显式地重写该方法,不然编译器就无法确定使用哪个接口的默认方法
示例
interface A {
default void greet() {
System.out.println("Hello from A");
}
}
interface B {
default void greet() {
System.out.println("Hello from B");
}
}
class C implements A, B {
@Override
public void greet() {
System.out.println("Hello from C"); // 显式实现
}
}
若没有显式重写,报错如下:


1197

被折叠的 条评论
为什么被折叠?



