在详解override和overload前需要对多态做一个详细的了解
什么是多态?
多态的教科书标准定义:允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。 其实可以借助于生活中的常见的一种多态现象来解释多态:比方说按下 F1 键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。
实现多态的技术
在java中,实现多态的两种方式为override重写和overload重载,而最终实现的技术为:动态绑定(dynamic binding),指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法
多态->晚绑定
多态是一种运行期的行为,不是编译期的行为。
多态的方法访问原理
虽然说父类的引用指向的是子类的对象,但是最终该引用还是父类,当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,就会去查找子类中是否有同名方法,如果没有,则调用父类的该方法;如果有,则会判断是否满足重写的两同两小一大原则,如果满足,则调用子类的该方法;如果不满足,则编译器报错;
多态访问的方法访问测试案例
class fun{
public void mi () throws NullPointerException{
System.out.println("fa mi ..." );
}
}
public class overrideTest extends fun {
public static void main (String[] args) {
fun f = new overrideTest();
f.mi();
}
}
class fun{
public void mi () throws Exception{
System.out.println("fa mi ..." );
}
}
public class overrideTest extends fun {
public void mi () throws NullPointerException{
System.out.println("over mi..." );
}
public static void main (String[] args) throws Exception {
fun f = new overrideTest();
f.mi();
}
}
class fun{
public void mi () throws NullPointerException{
System.out.println("fa mi ..." );
}
}
public class overrideTest extends fun {
public void mi () throws Exception{
System.out.println("over mi..." );
}
public static void main (String[] args) throws Exception {
fun f = new overrideTest();
f.mi();
}
}
class fun{
}
public class overrideTest extends fun {
public overrideTest mi () throws NullPointerException{
System.out.println("over mi..." );
return null ;
}
public static void main (String[] args) throws Exception {
fun f = new overrideTest();
f.mi();
}
}
言归正传,现在来说说override和overload
override
重写,是子类对父类的特定方法一种修改,是父类和子类之间的多态的实现
override原则(两同两小一大)
两同:方法名相同,参数列表相同
两小:子类方法返回值小于等于父类;子类抛出的异常小于等于父类
一大:子类方法的修饰符访问权限大于等于父类
代码重点解析override原则->两小
首先我们来看,子类方法的返回值小于等于父类,这里注意的是,如果返回值是基本数据类型,就必须要相等;如果为引用类型的话,可以小于,即子类的返回类型可以是父类返回类型的子类, 即在返回值上面进行了多态;
class fun{
protected fun mi () throws Exception{
System.out.println("fa mi ..." );
return null ;
}
}
public class overrideTest extends fun {
public overrideTest mi () throws NullPointerException{
System.out.println("over mi..." );
return null ;
}
public static void main (String[] args) throws Exception {
fun f = new overrideTest();
f.mi();
}
}
接下来我们来看看下一个:子类方法抛出的异常要小于等于父类,这是为什么呢,从一个很简单的方面进行解释:当我们定义一个需要抛出异常的方法时,我们在main方法(所有的方法)进行调用该方法时,都是需要抛出该方法对应的异常的,而因为引用类型是父类,所以最终main方法中抛出的异常是与父类的该方法一致的,而这个时候子类对该方法进行重写了,所以实质上调用的是子类的方法,如果这个时候子类抛出的异常范围大于父类时,那么就会导致异常捕获失败,不成立; 因此,子类重写的方法抛出的异常是要小于等于父类的;
//代码和test相同,main中抛出的异常与fun .mi一致
代码重点解析override原则->一大
这里一大指的是:子类的方法访问权限要大于等于父类,试想一下,在运行时,我们真正调用的是子类重写后的方法,如果这个时候子类的方法我们没有权限,就只能访问父类的该方法了,从而不符合重写调用,不成立;所以子类的访问权限要大于等于父类的,目的是比父类原生方法有更大的权限进行调用,父类原生方法可以调用的地方都可以调用子类重写后的方法;
overload重载
重载发生在一个类的内部,主要用于实现类对象的多态;
重载的原则
方法名必须相同;
参数列表必须不相同,参数列表或者参数个数任一个不同即可(参数之间为父子关系也算不同,int 和Integer也算不同)
方法的修饰符和返回值可以相同,也可以不相同;
代码重点解析overload原则
一个方法的定义,主要由:访问权限控制符+方法返回值+方法名+参数列表组成,对于重载来说,不管访问权限控制符和方法返回值是否相等,它都必须满足:方法名相同、参数列表不同,即使前面两者都不同,也需要满足这两个条件
public class overrideTest extends fun {
public overrideTest mi () throws NullPointerException{
System.out.println("over mi..." );
return null ;
}
private int a (String s){
return 1 ;
}
public double a (String s){
return 2 ;
}
public static void main (String[] args) throws Exception {
overrideTest t = new overrideTest();
System.out.println(t.a("!1" ));
}
}
总结
多态的两种实现方式: override+overload
多态是一种晚绑定,最终的对象引用是在运行期进行确定,编译期还不能确定
虽然多态实现父类的引用指向的是子类的对象,但是真正的调用还是在父类中发生
override的原则:两同两小一大
overload的原则:方法名必须相同,参数列表必须不同,其余两个可以相同,也可以不同