—-方法的重载、方法的覆盖

多态的两种表现形式

  • 同一类中方法多态(方法重载):同一类中允许多个同名方法,通过参数的数量、类型的差异进行区分。编译时确定调用哪个方法,是编译时多态
  • 子类对父类方法的重新定义(方法覆盖):方法名、返回值和参数形态完全一样。在运行时确定调用哪个方法,是运行时多态。 ```java public class A { void test(int x) {
    1. System.out.println("test(int):" + x );
    } void test(long x) {
    1. System.out.println("test(long):" + x );
    } void test(double x) {
    1. System.out.println("test(double):" + x);
    } public static void main (String[ ] args) {
    1. A a1 = new A();
    2. a1.test(5.0);
    3. a1.test(5);
    } } 运行结果: test(double):5.0 test(int):5

【思考】 1、如果将test(int x)方法注释掉,则调用test(5)如何? 运行结果: test(double):5.0 test(long):5 2、3个方法中,只将test(double x)方法注释掉,程序能编译通过吗? 运行结果: java: 对于test(double), 找不到合适的方法 方法 test.test(int)不适用 (参数不匹配; 从double转换到int可能会有损失) 方法 test.test(long)不适用 (参数不匹配; 从double转换到long可能会有损失)

  1. <a name="c5XWB"></a>
  2. # 方法调用的匹配处理原则
  3. **首先按“精确匹配”原则去查找匹配方法,如果找不到,则按“自动类型转换匹配”原则去查找能匹配的方法。**
  4. - 所谓“**精确匹配**”就是实参和形参类型完全一致。
  5. - 所谓“**自动转换匹配**”是指虽然实参和形参类型不同,**但能将实参的数据按自动转换原则赋值给形参。**
  6. ```java
  7. public class Complex {
  8. private double x, y; //x,y分别代表复数的实部和虚部
  9. public Complex(double real, double imaginary) {
  10. x = real;
  11. y = imaginary;
  12. }
  13. public String toString() {
  14. return "("+ x+","+y+"i"+")";
  15. }
  16. /* 方法1: 将复数与另一复数a相加 */
  17. public Complex add(Complex a) { //实例方法
  18. return new Complex(x+a.x ,y+a.y);
  19. }
  20. /* 方法2: 将复数与另一个由两实数a,b构成的复数相加 */
  21. public Complex add(double a,double b) { //实例方法
  22. return new Complex(x+a , y+b);
  23. }
  24. /* 方法3:将两复数a和b相加 */
  25. public static Complex add(Complex a, Complex b) { //静态方法
  26. return new Complex(a.x+b.x , a.y+b.y); 思考实例方法和静态方法的差异性!(是否用到成员变量)
  27. }
  28. public static void main(String args[]) {
  29. Complex x,y,z;
  30. x=new Complex(4,5);
  31. y=new Complex(3.4,2.8);
  32. z= add(x,y); //调用方法3进行两复数相加
  33. System.out.println("result1="+z);
  34. z= x.add(y); //调用方法1进行两复数相加
  35. System.out.println("result2="+z);
  36. z= y.add(4,5); //调用方法2进行两复数相加
  37. System.out.println("result3="+z);
  38. }
  39. }
  1. public class A {
  2. void test(int x)
  3. void test(long x)
  4. void test(double x)
  5. }
  6. class B extends A {
  7. void test(int x) {
  8. System.out.println("in B.test(int):" + x);
  9. }
  10. void test(String x , int y) {
  11. System.out.println("in B.test(String,int):" + x+","+y);
  12. }
  13. }
  14. 【思考】通过子类B的对象可调用多少test方法?

关于方法覆盖有以下问题值得注意

  • 方法名、参数列表、完全相同才会产生方法覆盖;返回类型通常也要一致,只有返回类型为引用类型时,允许子类方法的返回类型是父类方法返回类型的子类型。其他情形导致类型不一致时编译将指示错误。
  • 覆盖不能改变方法的静态与非静态属性。子类中不能将父类非静态方法定义为静态方法,反之也一样。
  • 不允许子类方法的访问修饰符比父类有更多的限制。
    • 例如:子类不能将父类的public方法定义为protected方法。但可以将父类的private方法在子类中重新定义为public方法.
  • final方法不能被覆盖

    方法重载与覆盖的区别

  1. 重载是同一个类中定义了多个同名的方法,表示方法间的关系,是水平关系;覆盖是子类和父类之间的关系,是垂直关系。
  2. 重载是多个方法之间的关系;覆盖是由一个方法或只能由一对方法产生关系。
  3. 重载要求参数列表不同;覆盖要求参数列表相同。
  4. 重载是根据调用时的实参表与形参表选择方法体;覆盖是根据对象类型来调用方法体。

    6.2.3 访问继承的成员

    (1)如果子类中定义了与父类同名的属性,在子类中将隐藏来自父类的同名属性变量
    (2)通过子类的引用变量访问自己的对象时,无论属性和方法优先考虑子类新定义的。自己类中没有的再到父类找。(优先考虑子类有的)
    (3) 可以将子类的对象引用赋值给父类的引用变量;但将父类引用变量的值赋给子类引用变量必须强制转换。
    (4)父类引用变量引用子类对象时的成员访问(非常重要)
  • 实例方法根据变量所对应对象的实际类型进行访问;———————>称为“动态多态性”
  • 属性和静态方法根据引用变量的类型进行访问. ```java (1)继承关系中方法的继承与父类属性隐藏 class parent{ int x=100; void m() {
    1. System.out.println(x);
    } } public class child extends parent{ int x=200; public static void main(String[] args) {
    1. child a=new child();
    2. a.m();
    3. System.out.println(a.x);
    } } 运行结果: 100 200

(2)继承关系中方法的覆盖 class parent{ int x=100; void m() { System.out.println(x); } } public class child extends parent{ int x=200; void m() { System.out.println(“x=”+x); } public static void main(String[] args) { child a=new child(); a.m(); System.out.println(a.x); } } 运行结果: x=200 200

(3)父类引用子类对象 class parent{ int x=100; void m() { System.out.println(x); } public class child extends parent{ int x=200; void m() { System.out.println(“x=”+x); } public static void main(String[] args) { parent a=new child(); a.m(); System.out.println(a.x); } } 运行结果: x=200 100

  1. ```java
  2. class SuperShow {
  3. int y = 8; // 父类SuperShow的y属性
  4. int m = 2;
  5. void show() { //父类SuperShow的show方法
  6. System.out.println("sup.show,y="+y);
  7. }
  8. }
  9. public class ExtendShow extends SuperShow { 每个子类对象有4个属性:y、z、super.y、m
  10. int y = 20; // 子类ExtendShow的y属性
  11. int z = 1;
  12. void show() { // 子类ExtendShow的show方法
  13. System.out.println("ext. show,y="+y);
  14. }
  15. public static void main(String args[]) {
  16. ExtendShow b = new ExtendShow();
  17. SuperShow a = b;
  18. System.out.println("ext.y=" + b.y); 20
  19. System.out.println("sup.y=" + a.y); 8
  20. b.show(); y=20
  21. a.show(); y=20
  22. System.out.println("z="+b.z+",m="+b.m); z=1,m=2
  23. }
  24. }
  25. 运行结果:
  26. ext.y=20
  27. sup.y=8
  28. ext. show,y=20
  29. ext. show,y=20
  30. z=1,m=2
  1. class Test5 {
  2. int k = 8;
  3. public void doSome() {
  4. System.out.println("k1="+k);
  5. }
  6. }
  7. class Sub extends Test5 {
  8. int k = 66;
  9. public void doSome() {
  10. k=k-2;
  11. System.out.println("k2="+k);
  12. }
  13. public static void main(String args []) {
  14. Test5 obj = new Sub();
  15. obj.doSome();
  16. System.out.println("k3="+obj.k);
  17. }
  18. }
  19. 运行结果:
  20. k2=64
  21. k3=8
  22. 思考:
  23. (1)将obj定义为子类引用变量如何?(Test5->Sub)
  24. 运行结果:
  25. k2=64
  26. k3=64
  27. (2) 将子类的doSome()方法删除又如何?
  28. k1=8
  29. k3=8
  30. 2
  31. class exSuper {
  32. public void func(String p, String s) {
  33. System.out.println(p);
  34. }
  35. }
  36. public class test extends exSuper {
  37. public void func(String p, String s) {
  38. System.out.println(p + " : " + s);
  39. }
  40. static public void main(String arg[ ]) {
  41. exSuper e1 = new exSuper( );
  42. e1.func("hello1", "hi1");
  43. exSuper e2 = new test();
  44. e2.func("hello2", "hi2");
  45. }
  46. }
  47. 运行结果:
  48. hello1
  49. hello2 : hi2