面向对象方法与技术参考资料

上传人:第*** 文档编号:33746249 上传时间:2018-02-17 格式:DOCX 页数:6 大小:28.78KB
返回 下载 相关 举报
面向对象方法与技术参考资料_第1页
第1页 / 共6页
面向对象方法与技术参考资料_第2页
第2页 / 共6页
面向对象方法与技术参考资料_第3页
第3页 / 共6页
面向对象方法与技术参考资料_第4页
第4页 / 共6页
面向对象方法与技术参考资料_第5页
第5页 / 共6页
点击查看更多>>
资源描述

《面向对象方法与技术参考资料》由会员分享,可在线阅读,更多相关《面向对象方法与技术参考资料(6页珍藏版)》请在金锄头文库上搜索。

1、重载(overload):同一个类中名字相同但参数列表不同的多个方法之间的关系。关于重载,是我们比较熟悉的了,最常见的就是运用在类的多个构造函数中,看一下 Java 帮助文档,就可以明白这一情况了。下面一个谜题:1. public class Confusing 2. 3. private Confusing(Object o) 4. System.out.println(Object); 5. 6. 7. private Confusing(double dArray) 8. System.out.println(double array); 9. 10. 11. public static

2、 void main(String args) 12. new Confusing(null); 13. 14. 问此时 main() 中将会输出什么?初初一看,并没有多分析就觉得应该是输出“Object”,虽然 Java 中的数组实际上也是引用类型,但毕竟 Object 是所有类的最终父类,而且目前 JDK 就连参数中的基本数据类型变量也可以被自动想上转型成包装类而成为 Object 的子类。于是我保守一点地就认为参数 null 应该是匹配到 Object 那个重载方法去了。可是这答案是错的,JVM 对于重载方法的解析是这样的:先找出方法名匹配的所有可能的方法;然后根据传进来的形参再次筛选出

3、可能的重载方法;最后才是在这些方法中匹配到一个最精确的一个方法。于是,上面的那个谜题就变成确定哪一个才是最精确这一点子上了。而关于如何判断最精确,有这样的机制:如果某个重载方法能够接收所有传递给另一个重载方法的实参类型,那么对于参数列表来看,显然后者至少是前者的子集,当然也就更精确了。回到谜题上来,Confusing(Object)可以接受任何传递给 Confusing(double )的参数(任何数组引用最终能够都是 Object 对象),因此 main() 中的 null 应该是被 JVM 匹配到 Confusing(double ) 中,也就有了与我所认为的结果相反的输出了。小结:这个谜

4、题表明了我们在写重载方法时,最好是明确地区分出各个方法中的参数列表,不要让彼此之间有互相包含、模糊不清的关系。虽然重载是为了在相同名字的方法中传入实参,由 JVM 动态解析选择合适的方法,但有时也很容易陷入这种方便背后所带来的地雷区当中。其中一种可行的办法就是,提供不同的方法名。但是构造函数的名字一定得相同的啊?实际上,就算是构造函数,也有很好的重构手法将其清晰地区分开来,不使用重载而是用不同名称的方法,将原本需要重载的构造函数委托给具有最大完整参数列表的私有构造函数中。又是一本经典,值得看哦重写(override):父类中的实例方法被其子类重新实现。既然是实例方法,那就是非 static 修

5、饰的了,否则就是 static 静态方法了,那叫做类方法。在我看来,正是重写这一机制的存在,才为多态机制提供了基础。或许 implements (实现)一个 interface (接口)中所声明的方法也能成为重写,因为 interface 的一部分存在原因也是为了多态。对于重写,在Java 解惑中有下面这个谜题让我明白:绝对不能在构造函数中调用可能会被子类重写的方法。1. class Point 2. protected final int x, y; 3. private final String name; 4. 5. Point(int x, int y) 6. this.x = x;

6、7. this.y = y; 8. name = makeName(); 9. 10. 11. protected String makeName() 12. return + x + , + y + ; 13. 14. 15. public final String toString() 16. return name; 17. 18. 19. 20. public class ColorPoint extends Point 21. private final String color; 22. 23. ColorPoint(int x, int y, String color) 24.

7、super(x, y); 25. this.color = color; 26. 27. 28. protected String makeName() 29. return super.makeName() + : + color; 30. 31. 32. public static void main(String args) 33. System.out.println(new ColorPoint(4, 2, purple); 34. 35. 此时程序运行结果并不是我们所想的 4,2:purple ,而是 4,2:null 。为什么会这样?看看下面用流程标号注释过的代码,就能理解了。1

8、. class Point 2. protected final int x, y; 3. private final String name; 4. 5. Point(int x, int y) 6. this.x = x; 7. this.y = y; 8. name = makeName();/ 3. 由于被子类重写过的 makeName() 9. 10. 11. protected String makeName() 12. return + x + , + y + ; 13. 14. 15. public final String toString() 16. return name

9、; 17. 18. 19. 20. public class ColorPoint extends Point 21. private final String color; 22. 23. ColorPoint(int x, int y, String color) 24. super(x, y); / 2. 调用 Point 父类构造函数 25. this.color = color; / 5. 初始化 color ,可是已经太晚了. 26. 27. 28. protected String makeName() 29. / 4. 问题来了:它在子类构造函数之前调用了 30. / 而此时的

10、 color 是 null 的啊! 31. return super.makeName() + : + color; 32. 33. 34. public static void main(String args) 35. / 1. 调用 ColorPoint 子类构造函数 36. System.out.println(new ColorPoint(4, 2, purple); 37. 38. 思路很清晰了,ColorPoint 子类中的构造函数中的 this.color = color; 还未被执行到就将 null 作为 String color 的值了。正是因为这种来来回回的调用使得程序变

11、得不正常了,在我看来,有那么一点类似于“回调”的意思。要去除这种代码结构的不合理,最好还是把 Point 父类构造函数中调用 makeName() 方法一句去掉,然后在 toString 中判断并调用 makeName() 来为 name 初始化隐藏(hide):子类的某个字段、静态方法、成员内部类与其父类的具有相同名字(对于静态方法还需要相同的参数列表),此时父类对应的字段、静态方法、成员内部类就被隐藏了。举个例子,天鹅(Swan)是会飞的,而丑小鸭(UglyDuck)小时候是不会飞的,看看下面的代码,看看能够打印出什么。1. class Swan 2. public static void

12、 fly() 3. System.out.println(swan can fly .); 4. 5. 6. 7. class UglyDuck extends Swan 8. public static void fly() 9. System.out.println(ugly duck cant fly .); 10. 11. 12. 13. public class TestFly 14. public static void main(String args) 15. Swan swan = new Swan(); 16. Swan uglyDuck = new UglyDuck();

13、 17. swan.fly(); 18. uglyDuck.fly(); 19. 20. 按道理的话,我们认为应该是输出两句不同的结果,因为我们可能认为 UglyDuck 继承了 Swan 并且“重写”了 fly() 方法,而且在 main() 方法中 Swan uglyDuck = new UglyDuck(); 也表明了 uglyduck 实际上是 UglyDuck 类型的,因此构成了多态行为。其实,运行结果是两句“swan can fly .”,为什么会这样子?原因有下:1、父类 Swan 中的 static 静态方法 fly() 是不能被重写的,上一段我对重写二字用了双引号;2、尽管子

14、类 UglyDuck 中的 fly() 方法与父类中的有一致的参数列表,但是对于 static 方法来说,这叫隐藏(hide),而不是重写(override);3、对于 static 方法,根本不存在像多态那样的动态分派机制,JVM 不会根据对象引用的实际类型来调用对应的重写方法。这一点在个例子中是最重要的。对于 static 方法,我们称之为类方法,不是实例方法,对 static 方法的调用直接用所属类名加个点就行,如 UglyDuck.fly() 。而实例方法就不得不使用对象引用来获得其可访问方法的调用权。在上面的例子 main() 中的 uglyDuck.fly() 语句,JVM 根本据不会去判断 uglyDuck 引用的究竟是什么类型,既然调用的

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 学术论文 > 毕业论文

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号