http://www.cnblogs.com/wenruo/p/5352683.html

一直不是很理解多态,今天看了两遍《think in java》第八章,试着总结一下。

多态的本质就是动态绑定。

将一个方法调用同一个方法主体关联起来叫做绑定。java中除了static方法和final方法(private方法属于final方法)之外,其他所有的方法都是后期绑定。

所以先不考虑static和final,看看多态是怎么样的。

记得c++中父类指针指向子类对象时默认是使用父类函数的,除非父类中函数是虚函数。

而在java不同。一个父类的引用指向子类的对象,如果子类重写了父类的方法,那么默认是调用子类的方法。

重写(override)和重载(overload)的区别

听说面试经常考这个?但是完全不一样嘛。重载要求是方法名相同,参数列表不同,而且和继承无关。但是重写的要求是子类中方法与父类中方法参数列表完全相同,返回值也要相同,或者子类返回值为父类返回值的子类型。重写可以通过@Override标注出来,防止出错,也使代码结构清晰。

用父类引用指向子类对象,会“缩小”接口。一个父类的引用,就算指向了子类的对象,那也只能使用父类有的方法,只不过有一些被重写了而已。一个应该使用父类的方法可以传参为一个子类,称作向上转型(Upcast)。很好理解,因为一个子类拥有父类所有的接口,可以满足方法所有的需求。

多态的好处:

现在来看窝就理解了两点

1.简化代码。写一个参数为父类的方法可以代替为很多子类分别写一个方法。

2.可扩展性。只要写一个父类,就可以随时扩充一个子类。而原来指向父类的方法不需要改变就可以用于新子类。这很重要。

借用别人博客的例子 同时考察了重写和重载

  1. class A {
  2. public String show(D obj) {
  3. return ("A and D");
  4. }
  5. public String show(A obj) {
  6. return ("A and A");
  7. }
  8. }
  9. class B extends A {
  10. public String show(B obj) {
  11. return ("B and B");
  12. }
  13. public String show(A obj) {
  14. return ("B and A");
  15. }
  16. }
  17. class C extends B {}
  18. class D extends B {}
  19.  
  20. public class Main {
  21. public static void main(String[] args) {
  22. A a1 = new A();
  23. A a2 = new B();
  24. B b = new B();
  25. C c = new C();
  26. D d = new D();
  27. System.out.println(a1.show(b)); //
  28. System.out.println(a1.show(c)); //
  29. System.out.println(a1.show(d)); //
  30. System.out.println(a2.show(b)); //
  31. System.out.println(a2.show(c)); //
  32. System.out.println(a2.show(d)); //
  33. System.out.println(b.show(b)); //
  34. System.out.println(b.show(c)); //
  35. System.out.println(b.show(d)); //
  36. }
  37. }

1~3,都是A类引用指向A类对象,那么没有重写多态什么的,直接根据参数选择方法,很简单。

4~6,A类引用指向B类对象,会涉及多态。对于A类引用来说,只会有两个方法,一个是show(D),一个是show(A)。show(D)没有被重写,输出"A and D",show(A)被重写输出"B and A"。然后根据参数选择方法就好了。

7~9,B类引用指向B类对象,不涉及多态。B一共有3个方法,继承自父类的show(D)输出"A and D",继承自父类又被重写的show(A)输出"B and A",子类中添加的show(B)输出"B and B"。然后根据参数选择。

输出:

  1. A and A
  2. A and A
  3. A and D
  4. B and A
  5. B and A
  6. A and D
  7. B and B
  8. B and B
  9. A and D

再写一个我觉得需要注意的

  1. class F {
  2. public void f1() {
  3. System.out.println("f1 in F");
  4. f2();
  5. }
  6. public void f2() {
  7. System.out.println("f2 in F");
  8. }
  9. }
  10.  
  11. class S extends F {
  12. public void f1() {
  13. System.out.println("f1 in S");
  14. f2();
  15. }
  16. public void f2() {
  17. System.out.println("f2 in S");
  18. }
  19. }
  20.  
  21. public class Main {
  22. public static void main(String[] args) {
  23. F f = new S();
  24. f.f1();
  25. }
  26. }

输出

f1 in S
f2 in S

  1. class F {
  2. public void f1() {
  3. System.out.println("f1 in F");
  4. f2();
  5. }
  6. public void f2() {
  7. System.out.println("f2 in F");
  8. }
  9. }
  10.  
  11. class S extends F {
  12. public void f2() {
  13. System.out.println("f2 in S");
  14. }
  15. }
  16.  
  17. public class Main {
  18. public static void main(String[] args) {
  19. F f = new S();
  20. f.f1();
  21. }
  22. }

输出

f1 in F
f2 in S

  1. class F {
  2. public void f1() {
  3. System.out.println("f1 in F");
  4. }
  5. }
  6.  
  7. class S extends F {
  8. public void f1() {
  9. System.out.println("f1 in S");
  10. f2();
  11. }
  12. public void f2() {
  13. System.out.println("f2 in S");
  14. }
  15. }
  16.  
  17. public class Main {
  18. public static void main(String[] args) {
  19. F f = new S();
  20. f.f1();
  21. }
  22. }

输出

f1 in S
f2 in S

  1. class F {
  2. public void f1() {
  3. System.out.println("f1 in F");
  4. f2();
  5. }
  6. public void f2() {
  7. System.out.println("f2 in F");
  8. }
  9. }
  10.  
  11. class S extends F {
  12. public void f1() {
  13. System.out.println("f1 in S");
  14. f2();
  15. }
  16. }
  17.  
  18. public class Main {
  19. public static void main(String[] args) {
  20. F f = new S();
  21. f.f1();
  22. }
  23. }

输出

f1 in S
f2 in F

主要注意一下第二个吧,可以看出即使是父类的方法中调用的方法也会被重写。

然后考虑一下final

考虑一下下面的代码输出什么

  1. class F {
  2. final void f() {
  3. System.out.println("F");
  4. }
  5. }
  6.  
  7. class S extends F {
  8. final void f() {
  9. System.out.println("S");
  10. }
  11. }
  12.  
  13. public class Main3 {
  14. public static void main(String[] args) {
  15. F f = new S();
  16. f.f();
  17. }
  18. }

答案是:

嗯。。编译错误。。Cannot override the final method

所以final方法不能被重写。当你不想让一个方法被重写,可以把方法设置为final

然后看一下private方法。虽然private也是final的,但是在这里还是有一点区别,因为父类的private方法对于子类是不可见的。

  1. class F {
  2. private void f() {
  3. System.out.println("F");
  4. }
  5. }
  6.  
  7. class S extends F {
  8. // @Override 加上这句会出现错误 可知并不是重写
  9. private void f() {
  10. System.out.println("S");
  11. }
  12. }
  13.  
  14. public class Main3 {
  15. public static void main(String[] args) {
  16. F f = new S();
  17. //f.f(); Error:The method f() from the type F is not visible
  18. }
  19. }

对于private方法可以在子类添加相同方法,但并不是重写,只是一个无关的全新方法,同时这样会造成混淆,所以不要这样使用。

接下来是static

按照《thinking in java》上的说法,构造器也是static的(虽然并不理解)。构造器中最好只调用final方法。因为其他方法可能会造成重写,而我们又知道,初始化的时候是先初始化父类再初始化子类的,这样就会导致子类还未初始化完成就被调用,可能产生一些错误。

静态方法的继承

  1. class StaticSuper {
  2. static void f() {
  3. System.out.println("Super");
  4. }
  5. }
  6.  
  7. class StaticSub extends StaticSuper {
  8. static void f() {
  9. System.out.println("Sub");
  10. // super.f(); error:Cannot use super in a static context
  11. }
  12. }
  13.  
  14. public class Main {
  15. public static void main(String[] args) {
  16. StaticSuper sup = new StaticSub();
  17. sup.f();
  18. StaticSub sub = new StaticSub();
  19. sub.f();
  20. }
  21. }

输出:

Super
Sub

可知对于静态方法不存在多态,子类中方法会覆盖父类相同方法。但是静态方法是否被继承?

  1. class StaticSuper {
  2. static void f() {
  3. System.out.println("Super");
  4. }
  5. }
  6.  
  7. class StaticSub extends StaticSuper {
  8. }
  9.  
  10. public class Main {
  11. public static void main(String[] args) {
  12. StaticSuper sup = new StaticSub();
  13. sup.f();
  14. StaticSub sub = new StaticSub();
  15. sub.f();
  16. }
  17. }

输出

Super
Super
可见静态方法是会被继承的。

上面所有讨论的都是方法。对于域,是不存在多态的!

  1. class Super {
  2. public int field = 0;
  3. public int getField() {
  4. return field;
  5. }
  6. }
  7.  
  8. class Sub extends Super {
  9. public int field = 1;
  10. public int getField() {
  11. return field;
  12. }
  13. public int getSuperField() {
  14. return super.field;
  15. }
  16. }
  17.  
  18. public class Main {
  19. public static void main(String[] args) {
  20. Super sup = new Sub();
  21. System.out.println(sup.getField());
  22. Sub sub = new Sub();
  23. System.out.println(sub.getField());
  24. System.out.println(sub.getSuperField());
  25. }
  26. }

输出

1
1
0

over~~

java 关于多态的一点总结的更多相关文章

  1. 深入Java核心 Java中多态的实现机制(1)

    在疯狂java中,多态是这样解释的: 多态:相同类型的变量,调用同一个方法时,呈现出多中不同的行为特征, 这就是多态. 加上下面的解释:(多态四小类:强制的,重载的,参数的和包含的) 同时, 还用人这 ...

  2. 从虚拟机指令执行的角度分析JAVA中多态的实现原理

    从虚拟机指令执行的角度分析JAVA中多态的实现原理 前几天突然被一个"家伙"问了几个问题,其中一个是:JAVA中的多态的实现原理是什么? 我一想,这肯定不是从语法的角度来阐释多态吧 ...

  3. 学习博客之Java继承多态接口

    这一篇博客主要是对软工前一阶段学习的总结,主要是对Java的学习总结,包括三部分:Java的继承.多态和接口 Java的继承 继承是面向对象的三大特性之一,能够实现软件的复用. Java子类继承父类的 ...

  4. java的多态以及重载,重写,前期绑定,后期绑定

    多态的定义: 一个类实例的相同方法在不同情形有不同表现形式.多态机制使具有不同内部结构的对象可以共享相同的外部接口.这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通 ...

  5. 关于java中多态的理解

    java三大特性:封装,继承,多态. 多态是java的非常重要的一个特性: 那么问题来了:什么是多态呢? 定义:指允许不同类的对象对同一消息做出响应.即同一消息可以根据发送对象的不同而采用多种不同的行 ...

  6. 个人对Java中多态的一些简单理解

    什么是多态 面向对象的三大特性:封装.继承.多态.从一定角度来看,封装和继承几乎都是为多态而准备的.这是我们最后一个概念,也是最重要的知识点. 多态的定义:指允许不同类的对象对同一消息做出响应.即同一 ...

  7. Java中多态的一些简单理解

    什么是多态 .面向对象的三大特性:封装.继承.多态.从一定角度来看,封装和继承几乎都是为多态而准备的.这是我们最后一个概念,也是最重要的知识点. .多态的定义:指允许不同类的对象对同一消息做出响应.即 ...

  8. Java JVM 多态(动态绑定)

    Java JVM 多态(动态绑定) @author ixenos 摘要:绑定.动态绑定实现多态.多态的缺陷.纯继承与扩展接口.向下转型与RTTI 绑定 将一个方法的调用和一个方法的主体关联起来,称作( ...

  9. java异常捕获的一点感悟

    class Annoyance extends Exception {} class Sneeze extends Annoyance {} class Human { public static v ...

随机推荐

  1. 2D UI和3D UI的工作原理

    2D UI的工作原理 UI控件的位置在UI Root 的红框(视窗)上,也就是UI控件的z轴,相机的z轴,UI Root的z轴都是0,因为2D UI都是纯粹的2D图片按层次显示,不会不出现三维立体效果 ...

  2. ios字符串操作

    string的操作应用 NSRange range = [self.general rangeOfString:@"."]; NSString *str = [self.gener ...

  3. Docker容器中运行ASP.NET Core

    在Linux和Windows的Docker容器中运行ASP.NET Core 译者序:其实过去这周我都在研究这方面的内容,结果周末有事没有来得及总结为文章,Scott Hanselman就捷足先登了. ...

  4. Linux下 config/configure/Configure、make 、make test/make check、sudo make install 的作用

    转自Linux下 config/configure/Configure.make .make test/make check.sudo make install 的作用 这些都是典型的使用GNU的AU ...

  5. 卡牌手游源码《暗黑世界V1.3》数据库表说明文档!!!

    原地址:http://blog.csdn.net/uxqclm/article/details/11970761 欢迎来到9秒:www.9miao.com 由于看到论坛中有人询问需求<暗黑世界V ...

  6. UVALive - 4287 Proving Equivalences

    给定n个命题之间的已经证明的关系如 a b表示已经证明蕴含式a→b,要求还需要再作多少次证明使得所有的命题都是等价的.将每个命题看成一个点,已经证明的命题之间连一条边,问题转化为添加多少条单向边使得图 ...

  7. 用Unity3.0+MVC4搭建项目

    新年快乐!又是新的一年到来了,我好久没有在园子里面做笔记啦,由于工作上的事,还好年前把该做的都完善了,于是就写了辞职信.由于家庭原因,不得不离职,在春节期间呢,我放松了几天,去这里去那里的,朋友们喜欢 ...

  8. poj1724ROADS(BFS)

    链接 本来想写spfa 加点什么限制什么的可能就过了 写着写着就成裸BFS了 也没优化就水过了 #include <iostream> #include<cstdio> #in ...

  9. 虚拟主机apache

    1.虚拟主机配置 windows: 1)加载配置虚拟主机的配置文件,在Apache/conf中找到httpd.conf文件,并搜索出以下的两句话,将Include conf/extra/httpd-v ...

  10. 【转】OS X Mavericks: 防止 Mac 进入睡眠 -- 不错

    原文网址:https://support.apple.com/kb/PH13808?locale=zh_CN&viewlocale=zh_CN 某些 Mac 电脑将在不活跃一段时间后自动进入睡 ...