重载与覆盖区别

参考网址:http://xm-king.iteye.com/blog/765334

重载与覆盖区别
     有时候,类的同一种功能有多种实现方式,到底采用那种实现方式,取决于调用者给定的参数。例如 杂技师能训练动物,对于不同的动物有不同的训练方式。

Java代码   收藏代码
  1. public void train (Dog dog){   
  2. //训练小狗站立,排队,做算数   
  3. }   
  4. public void train(Monkey monkey){   
  5. //训练猴子骑自行车等   
  6. }   

 
      再如某个类的一个功能是比较两个城市是否相同,一种方式是比较两个城市的名字,一种是除了比较两个城市的名字外,还要比较所在国家的名字。

Java代码   收藏代码
  1. publi boolean isSameCity (String city1,String city2){   
  2. return city1.equals(city2);   
  3. }   
  4. public boolean isSameCity(String city1,String city2,Stirng Country1,String Country2){   
  5. return isSameCity(city1,city2)&&Country1.equals(Country2);   
  6. }  

 

 

在例如 java.lang.Math 类的 max ()方法能够从两个数字中取出最大值,它有多种实现方式。

 

Java代码   收藏代码
  1. public static int max(int a,int b)   
  2. public static int max(long a, long b)   
  3. public static int max(float a,float b)   

  
      以下程序多次调用Math 类的max() 方法,运行时,Java 虚拟机先判断给定参数的类型,然后决定到底执行哪个 max()方法。 
      // 参数为 int 类型,因此执行max(int a, int b)方法 
      Math.max(1,2); 
      //参数为 flloat 类型,因此执行 max(float a, float b) 方法 
      Math.max(1.0F,2.9F);

      对于类的方法(包括从父类中继承的方法)如果有两个方法的方法名相同,但参数不一致,那么可以说,一个方法是另一个方法的重载方法。 
      重载方法满足以下条件 
            方法名相同 
            方法的参数类型,个数,顺序至少有一项不相同 
            方法的返回类型可以不相同 
            方法的修饰符可以不相同 
      在一个类中不允许定义另个方法名相同,并且参数签名也完全相同的方法。假如存在这样的两个方法,Java 虚拟机 在运行时就无法决定到底执行哪个方法。参数签名是指参数的类型,个数和顺序。 
      例如 :

Java代码   收藏代码
  1. public class Sample {   
  2. public void amethod(int i,String s){} }   
  3. //下面哪个方法可以加入到 Sample 类中去?   
  4. public void amethod(String s,int i) //OK   
  5. public int amethod(int i,String s){return 0//NO   
  6. //不行,参数签名和类中方法一样   
  7. public void amethod(int i,String myString){} //NO   
  8. //不行,参数签名和类中方法一样   
  9. public void Amethod (int i,Sting s){} // OK   
  10. //可以,因为 Amethod 和amethod 是两个不同的方法名称。   
  11. abstract void amethod( int i); //NO   

 
       尽管它的参数列和 类中方法参数不一样,但是,此处的Sample 类不是抽象类,所以不能包括这个抽象方法。假如把Sample 类改为抽象类,就能把这个方法加入到 Sample 类中了。 
(源码) 

Java代码   收藏代码
  1. public boolean compareCity(String city1,String city2){   
  2. return city1.equals(city2);   
  3. }   
  4.      
  5. public int compareCity(String city1,String city2){   
  6.      
  7. if(city1.equals(city2)){   
  8. return 1;   
  9. }else{   
  10. return 0;   
  11. }   
  12. }   

 
编译错误:

Java代码   收藏代码
  1. compareCity(java.lang.String,java.lang.String) is already defined   
  2. // compareCity(String ,String ) 方法已经被定义过   
  3. 作为程序的入口 main()方法也可以被重载。   
  4. public static void main(String args[]){   
  5.   
  6. }   
  7.   
  8. public void main(String s,int i){} //可以   
  9.   
  10. private void main(int i,String myString []){} //可以   
  11.   
  12. public void main(String s)throws Exception{} //可以   
  13.   
  14. public final static int main(String args[]){} //不可以   
  15. 它已经和已有的 main ()方法有相同的签名,因此不允许再加到这个类中来。   
  16. main(java.lang.String []) is already defined in Sample   

 


    方法覆盖 
      假如有100个类,分别是 Sub1,Sub2,Sub3…….Sub100 ,它们的一个共同行为是写字,除了Sub1用脚写字外,其他都用手写字。可以抽象一个父类Base,它有一个表示写字的方法 write(),那么这个方法到底如何实现呢? 从尽可能提高代码可重用性的角度看,write() 方法应该采取适用于大多数子类的实现方式,这样就可以避免在大多数子类中重复定义 write()方法。因此Base 类的 write() 方法定义如下: 
public void write(){ // Base 类的 write() 方法 用手写字} 
      由于 Sub1 类的写字的实现方式与Base 类不一样,因此在Sub1类中必须重新定义 write() 方法。 
      public void write(){// Sub1 类中的 write() 方法 // 用脚写字}

      如果在子类中定义的一个方法,其名称,返回类型及参数签名正好与父类中某个方法的名称,返回类型及参数签名相匹配,那么可以说,子类的方法覆盖了父类的方法。 
覆盖方法 必须满足多种约束 
1)子类方法的名称,参数签名和返回类型必须与父类方法的名称,参数签名和返回类型一致 
例如,下列代码将发生编译错误 

Java代码   收藏代码
  1. public class Base{   
  2.    public void method(){……….}   
  3. }   
  4. public class Sub extends Base{   
  5.    public int method(){……………. return 0};// 编译错误   
  6. }   

 
           method() in Simon.Sub cannot overrid method() in Simon.Base; 
       attempting to use incompatible return type 
       在Simon 包 Sub 中的方法不不能重写(覆盖) 在 Simon 包 Base类中的方法试图用不匹配的返回类型,Java编译器首先判断Sub 类的 method()方法与 Base 类的 method() 方法的参数签名。由于两者一致,所以Java 编译器就认为 Sub 类 的 method() 方法试图覆盖父类的方法,既然如此,Sub 类的 method() 方法就必须和被覆盖的方法具有相同的返回类型。 
以下代码中子类覆盖了父类的一个方法,然后又定义了一个重载方法,这是合法的。

Java代码   收藏代码
  1. public class Base{   
  2. public void method(){…………..}   
  3. }   
  4.   
  5.    public class Sub extends Base{   
  6.    public void method(){……….}//覆盖 Base 类的method 方法   
  7.    public int mehod(int a){………return 0.} //重载method 方法   
  8. }   

 
2) 子类方法不能缩小父类方法的访问权限。例如以下代码中子类的 method() 方法是私用的,父类的 method()方法是公共的,子类缩小了 父类方法的访问权限,这是无效的方法覆盖,将导致编译错误。

Java代码   收藏代码
  1. public class Base{   
  2. public void method(){…………..}   
  3. }   
  4.   
  5. public class Sub extends Base{   
  6. private void method(){……….}//覆盖 Base 类的method 方法,但是缩小了 父类方法访问权限   
  7. }   

 

      method() in Simon.Sub cannot override method() in Simon.Base; 
      attempting to assign weaker access privileges ; 
      was public Simon 包中 的 Sub 类 method()不能重写、覆盖 Simon 包中Base类的 method()方法。 试图分配一个更弱的访问权限原来是 public (现在却是 private) 为什么子类方法不允许缩小父类方法的访问权限呢?这时因为假如没有这个限制,将于Java 语言的多态机制发生冲突。Base base = new Sub() ;//base 变量被定义为Base 类型,但引用 Sub 的实例。

       base.method(); Java 编译器认为以上是合法的代码,但是在运行时,根据动态绑定规则,Java 虚拟机会调用base 变量所引用的Sub 实例的 method()方法,如果这个方法为 private 类型,Java 虚拟机就没有办法访问它.所以为了避免这样的矛盾,Java 语言不允许子类方法缩小父类中被覆盖方法的权限。 
3)子类方法不能抛出比父类方法更多的异常。 
      子类方法抛出的异常必须和父类方法抛出的异常相同,或者子类方法抛出的异常类是父类抛出的异常类的子类。 
      假设异常类ExceptionSub1 和 ExceptionSub2 是 ExceptionBase 类的子类,则以下代码是合法的。 

Java代码   收藏代码
  1. public class Base{   
  2. void method () throws ExceptionBase{}   
  3. }   
  4. public class Sub1 extends Base{   
  5. void method () throws ExceptionSub1{}   
  6. }   
  7. public class Sub2 extends Base{   
  8. void method () throws ExceptionSub1,ExceptionSub2   
  9. }   
  10. public class Sub3 extends Base{   
  11. void methos () throws ExceptionBase   
  12. }   
  13. //以下代码不合法   
  14. public class Base{   
  15. void method() throws ExceptionSub1{ }   
  16. }   
  17. public class Sub1 extends Base{   
  18. void method() throws ExceptionBase{ } //编译出错   
  19. }   
  20. public class Sub2 extends Base{   
  21. void method() throws ExceptionSub1,ExceptionSub2{}//编译出错   
  22. }   

 
为什么子类不允许抛出比父类方法更多的异常呢?这时因为假如没有这个限制,将会与Java 语言的多态机制发生冲突。 

Java代码   收藏代码
  1. Base base = new Sub2() ;//base 变量被定义为Base 类型,但引用Sub2 的实例。   
  2. try{   
  3.    base.method();   
  4. }catch(ExceptionSub1 e){……..} //仅仅描述ExceptionSub1 异常   

 
      Java 编译器认为以上是合法的代码。但在运行时,根据动态绑定规则,Java虚拟机会调用 base 变量所引用的Sub2 实例的 method() 方法。 假如 Sub2 实例的 method() 方法抛出 ExceptionSub2 异常,由于该异常没有被捕获,将导致程序异常终止。 
4)方法覆盖只存在于子类和父类(包括直接父类和间接父类)之间,在同一个类中方法只能被重载,不能被覆盖。 
5)父类的静态方法不能被子类覆盖为非静态方法。

例如:

Java代码   收藏代码
  1. public class Base {   
  2. public static void method(){}   
  3. }   
  4. public class Sub extends Base{   
  5. public void method(){} //编译错误   
  6. }   

 
      method () in Simon.Sub cannot override method() in Simon.Base; 
      Overridden method is static
 
      在包Simon ,Sub类中的 method() 方法不能够重写 Base 类中的 method()方法。 被重写的方法是静态的。 
6)子类可以定义与父类的静态方法同名的静态方法,以便在子类中隐藏父类的静态方法。 
      在编译时,子类定义的静态方法也必须满足与方法覆盖类似的约束: 
      方法的参数签名一致,返回类型一致,不能缩小父类方法的访问权限,不能抛出更多的异常。以下代码是合法的。 
public class Base { 
static int method(int a)throws BaseException{ return 0 } 

public class Sub extends Base{ 
public static int method(int a)throws SubException{ return 0} } 
子类隐藏父类的静态方法和子类覆盖父类的实例方法,这两者的区别就在于:运行时,JVM把静态方法和所属的类绑定,而把实例方法和所属的实例绑定。 

Java代码   收藏代码
  1. Base.java   
  2. package Simon;   
  3.     
  4. public class Base{   
  5.      
  6. void method(){   
  7. System.out.println("method of Base !");//实例方法   
  8. }   
  9. static void staticMethod(){   
  10. System.out.println("static method of Base !");//静态方法   
  11. }   
  12. }   
  13. Sub.java   
  14. package Simon;   
  15.      
  16. public class Sub extends Base{   
  17.      
  18. void method(){ //覆盖父类实例方法 method()   
  19. System.out.println("method of Sub !");   
  20. }   
  21.     
  22. static void staticMethod(){ //隐藏父类的静态方法 staticMethod ()   
  23. System.out.println("static method of Sub !");   
  24. }   
  25. public static void main(String args[]){   
  26.   
  27.    Base sub1 = new Sub(); //sub1 变量 被声明为 Base 类型,引用Sub 实例   
  28. sub1.method() ;//打印 method of Sub !   
  29. sub1.staticMethod() ;//打印 static method of Base    
  30.    Sub sub2 = new Sub(); //sub2 变量 被声明为 Sub 类型,引用 Sub 实例   
  31. sub2.method(); // 打印 method of Sub   
  32.    sub2.staticMethod(); // 打印 static method of Sub   
  33. }   
  34.    }   

 
        引用变量sub1 和 sub2 都引用 Sub 类的实例,java 虚拟机在执行 sub1.method() 和 sub2.method() 时,都调用Sub 实例的 method()方法,此时父类Base 实例方法 method() 被子类覆盖。 
引用变量sub1 被声明为Base 类型,java 虚拟机在执行 sub1.staticMethod()时,调用Base 类的staticMethod()方法,可见父类Base 类的静态方法staticMethod ()不能为被子类覆盖。 
引用变量 sub2 被声明为 Sub 类型,java 虚拟机在执行sub2.staticMethod()时,调用Sub 类的 staticMethod 方法,Base 类的staticMethod()方法隐藏。 
7)父类的非静态方法不能被子类覆盖为静态方法。 
以下代码编译有错误 

Java代码   收藏代码
  1. public class Base {   
  2.    public void method(){}   
  3. }   
  4.    public class Sub extends Base{   
  5. public static void method(){} //编译错误   
  6. }   

 
method () in Simon.Sub cannot override method() in Simon.Base; 
overriding method is static .

8)父类的私有方法不能被子类覆盖 
      子类方法覆盖父类方法的前提是:子类必须能继承父类的特定方法。 
      由于父类中的某个私有方法无法被子类访问,继承,所以也不存在被子类覆盖的关系。 
示例: 

Java代码   收藏代码
  1. Base.java   
  2. package Simon;   
  3.     
  4. public class Base{   
  5.     
  6. private String showMe(){   
  7. return "Base";   
  8. }   
  9.   
  10. public void print(){   
  11. System.out.println(showMe());//到底调用哪一个showMe(),是Base 类还是Sub类中的。   
  12. }   
  13. }   
  14. Sub.java   
  15. package Simon;   
  16.     
  17. public class Sub extends Base{   
  18.   
  19. public String showMe(){   
  20. return "Sub";   
  21. }   
  22.     
  23. public static void main(String args[]){   
  24.     
  25. Sub sub = new Sub();   
  26.     
  27. sub.print();   
  28. }   
  29. }   
  30.     

 
执行以上Sub 类的 main() 方法,会打印出结果 Base ,这时因为print()方法在Base 类中定义,因此print()方法会调用在Base 类中定义的 private 类型的 showMe() 方法 
如果把Base类的showMe() 方法改为 public 类型,其他代码不变 
public String showMe(){ 
return "Base"; 

在执行以上Sub 类的main ()方法,会打印出 Sub,这是因为此时Sub 类的 showMe() 方法覆盖了 Base 类的showMe() 方法。因此尽管print()方法在Base 类中定义,JVM 还是会调用当前Sub 实例的 ShowMe 方法。 
9)父类的抽象方法可以被子类通过两种途径覆盖掉,一是子类实现父类的抽象方法,二是子类重新声明父类的抽象方法。 

Java代码   收藏代码
  1. public abstract class Base{   
  2. abstract void method1();   
  3. abstract void method2   
  4. }   
  5. public abstract class Sub extends Base{   
  6. public void method(){…………}//实现method1方法,扩大访问权限   
  7. public abstract void method2();//重新声明 method2 方法,仅仅扩大访问权限,但不实现。   
  8. }   

 
      狭义的理解,覆盖仅指子类覆盖父类的具体方法,即非抽象方法,在父类中提供了方法的默认实现方式,而子类采用不同的实现方式。 
例如,以下代码编译会有误。 

Java代码   收藏代码
  1. public abstract class Base{   
  2.     
  3. abstract void method1();   
  4. abstract void method2();   
  5. }   
  6. public abstract class Sub extends Base{   
  7.     
  8. private void method(){//编译有误,不能缩小访问权限   
  9.     
  10. System.out.println("method test!");   
  11. }   
  12.     
  13. private abstract void method2();//编译有误,不能缩小访问权限,且会出现以下错误   
  14.   
  15. }   
  16. illegal combination of modifiers : abstract and private   
  17. abstract 不能和 private 关键字一起使用。抽象方法必须需要被实现,但是 private 是私有的,外界无法访问,所以不行。   
  18. 10)父类的非抽象方法可以被覆盖为抽象方法   
  19. public class Base{   
  20. void methos();   
  21. }   
  22. public abstract class Sub extends Base{   
  23. public abstract void method(); //合法   
  24. }   
  25.   
  26.    

 

 

Java 方法重载 (OverLoad)与方法覆盖(Override)的区别 
       方法覆盖和方法重载具有以下相同点 
             都要求方法名相同 
             都可以用于抽象方法和非抽象方法之间 
      不同点 
            方法覆盖要求参数签名必须一致,而方法重载要求参数签名必须不一致 
            方法覆盖返回类型必须一致,方法重载对此不做限制 
            方法覆盖只能用于子类覆盖父类的方法,方法重载用于同一个类的所有方法(包括从父类中继承而来的方法) 
            方法覆盖对方法的访问权限和抛出的异常有特殊的要求,而方法重载在这方面没有任何限制 
            父类的一个方法只能被子类覆盖一次,而一个方法在所在类中可以被重载多次

 



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值