规则五:重写的方法不能使用限制等级更严格的权限修饰符。
可以这样来理解:
如果被重写的方法是 default,那么重写的方法可以是 default、protected 或者 public。
如果被重写的方法是 protected,那么重写的方法只能是 protected 或者 public。
如果被重写的方法是 public, 那么重写的方法就只能是 public。
举个例子,父类中的方法是 protected:
public class Animal {
protected void eat() { }
}
子类中的方法可以是 public:
public class Dog extends Animal {
public void eat() { }
}
如果子类中的方法用了更严格的权限修饰符,编译器就报错了。
规则六:重写后的方法不能抛出比父类中更高级别的异常。
举例来说,如果父类中的方法抛出的是 IOException,那么子类中重写的方法不能抛出 Exception,可以是 IOException 的子类或者不抛出任何异常。这条规则只适用于可检查的异常。
可检查(checked)异常必须在源代码中显式地进行捕获处理,不检查(unchecked)异常就是所谓的运行时异常,比如说 NullPointerException、ArrayIndexOutOfBoundsException 之类的,不会在编译器强制要求。
父类抛出 IOException:
public class Animal {
protected void eat() throws IOException { }
}
子类抛出 FileNotFoundException 是可以满足重写的规则的,因为 FileNotFoundException 是 IOException 的子类。
public class Dog extends Animal {
public void eat() throws FileNotFoundException { }
}
如果子类抛出了一个新的异常,并且是一个 checked 异常:
public class Dog extends Animal {
public void eat() throws FileNotFoundException, InterruptedException { }
}
那编译器就会提示错误:
Error:(9, 16) java: com.itwanger.overriding.Dog中的eat()无法覆盖com.itwanger.overriding.Animal中的eat()
被覆盖的方法未抛出java.lang.InterruptedException
但如果子类抛出的是一个 unchecked 异常,那就没有冲突:
public class Dog extends Animal {
public void eat() throws FileNotFoundException, IllegalArgumentException { }
}
如果子类抛出的是一个更高级别的异常:
public class Dog extends Animal {
public void eat() throws Exception { }
}
编译器同样会提示错误,因为 Exception 是 IOException 的父类。
Error:(9, 16) java: com.itwanger.overriding.Dog中的eat()无法覆盖com.itwanger.overriding.Animal中的eat()
被覆盖的方法未抛出java.lang.Exception
05、如何调用被重写的方法?
规则七:可以在子类中通过 super 关键字来调用父类中被重写的方法。
子类继承父类的方法而不是重新实现是很常见的一种做法,在这种情况下,可以按照下面的形式调用父类的方法:
super.overriddenMethodName();
来看例子。
public class Animal {
protected void eat() { }
}
子类重写了 eat() 方法,然后在子类的 eat() 方法中,可以在方法体的第一行通过 super.eat() 调用父类的方法,然后再增加属于自己的代码。
public class Dog extends Animal {
public void eat() {
super.eat();
// Dog-eat
}
}
06、重写和构造方法
规则八:构造方法不能被重写。
因为构造方法很特殊,而且子类的构造方法不能和父类的构造方法同名(类名不同),所以构造方法和重写之间没有任何关系。
07、重写和抽象方法
规则九:如果一个类继承了抽象类,抽象类中的抽象方法必须在子类中被重写。
先来看这样一个接口类:
public interface Animal {
void move();
}
接口中的方法默认都是抽象方法,通过反编译是可以看得到的:
public interface Animal
{
public abstract void move();
}
如果一个抽象类实现了 Animal 接口,move() 方法不是必须被重写的:
public abstract class AbstractDog implements Animal {
protected abstract void bark();
}
但如果一个类继承了抽象类 AbstractDog,那么 Animal 接口中的 move() 方法和抽象类 AbstractDog 中的抽象方法 bark() 都必须被重写:
public class BullDog extends AbstractDog {
public void move() {}
protected void bark() {}
}
08、重写和 synchronized 方法
规则十:synchronized 关键字对重写规则没有任何影响。
synchronized 关键字用于在多线程环境中获取和释放监听对象,因此它对重写规则没有任何影响,这就意味着 synchronized 方法可以去重写一个非同步方法。
09、重写和 strictfp 方法
规则十一:strictfp 关键字对重写规则没有任何影响。
如果你想让浮点运算更加精确,而且不会因为硬件平台的不同导致执行的结果不一致的话,可以在方法上添加 strictfp 关键字。因此 strictfp 关键和重写规则无关。
最后
学习的过程,就好像登山一样,大概有 80% 的人在这个过程中会掉队。那么请相信我,只要目标明确,努力加上坚持,再加上一点点好运气,你就能登顶!