java 关于多态的一点总结
2016-04-04 19:36
495 查看
http://www.cnblogs.com/wenruo/p/5352683.html
一直不是很理解多态,今天看了两遍《think in java》第八章,试着总结一下。
多态的本质就是动态绑定。
将一个方法调用同一个方法主体关联起来叫做绑定。java中除了static方法和final方法(private方法属于final方法)之外,其他所有的方法都是后期绑定。
而在java不同。一个父类的引用指向子类的对象,如果子类重写了父类的方法,那么默认是调用子类的方法。
重写(override)和重载(overload)的区别
听说面试经常考这个?但是完全不一样嘛。重载要求是方法名相同,参数列表不同,而且和继承无关。但是重写的要求是子类中方法与父类中方法参数列表完全相同,返回值也要相同,或者子类返回值为父类返回值的子类型。重写可以通过@Override标注出来,防止出错,也使代码结构清晰。
用父类引用指向子类对象,会“缩小”接口。一个父类的引用,就算指向了子类的对象,那也只能使用父类有的方法,只不过有一些被重写了而已。一个应该使用父类的方法可以传参为一个子类,称作向上转型(Upcast)。很好理解,因为一个子类拥有父类所有的接口,可以满足方法所有的需求。
多态的好处:
现在来看窝就理解了两点
1.简化代码。写一个参数为父类的方法可以代替为很多子类分别写一个方法。
2.可扩展性。只要写一个父类,就可以随时扩充一个子类。而原来指向父类的方法不需要改变就可以用于新子类。这很重要。
借用别人博客的例子 同时考察了重写和重载
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"。然后根据参数选择。
输出:
再写一个我觉得需要注意的
输出
f1 in S
f2 in S
输出
f1 in F
f2 in S
输出
f1 in S
f2 in S
输出
f1 in S
f2 in F
主要注意一下第二个吧,可以看出即使是父类的方法中调用的方法也会被重写。
答案是:
嗯。。编译错误。。Cannot override the final method
所以final方法不能被重写。当你不想让一个方法被重写,可以把方法设置为final
然后看一下private方法。虽然private也是final的,但是在这里还是有一点区别,因为父类的private方法对于子类是不可见的。
对于private方法可以在子类添加相同方法,但并不是重写,只是一个无关的全新方法,同时这样会造成混淆,所以不要这样使用。
静态方法的继承
输出:
Super
Sub
可知对于静态方法不存在多态,子类中方法会覆盖父类相同方法。但是静态方法是否被继承?
输出
Super
Super
可见静态方法是会被继承的。
输出
1
1
0
over~~
一直不是很理解多态,今天看了两遍《think in java》第八章,试着总结一下。
多态的本质就是动态绑定。
将一个方法调用同一个方法主体关联起来叫做绑定。java中除了static方法和final方法(private方法属于final方法)之外,其他所有的方法都是后期绑定。
所以先不考虑static和final,看看多态是怎么样的。
记得c++中父类指针指向子类对象时默认是使用父类函数的,除非父类中函数是虚函数。而在java不同。一个父类的引用指向子类的对象,如果子类重写了父类的方法,那么默认是调用子类的方法。
重写(override)和重载(overload)的区别
听说面试经常考这个?但是完全不一样嘛。重载要求是方法名相同,参数列表不同,而且和继承无关。但是重写的要求是子类中方法与父类中方法参数列表完全相同,返回值也要相同,或者子类返回值为父类返回值的子类型。重写可以通过@Override标注出来,防止出错,也使代码结构清晰。
用父类引用指向子类对象,会“缩小”接口。一个父类的引用,就算指向了子类的对象,那也只能使用父类有的方法,只不过有一些被重写了而已。一个应该使用父类的方法可以传参为一个子类,称作向上转型(Upcast)。很好理解,因为一个子类拥有父类所有的接口,可以满足方法所有的需求。
多态的好处:
现在来看窝就理解了两点
1.简化代码。写一个参数为父类的方法可以代替为很多子类分别写一个方法。
2.可扩展性。只要写一个父类,就可以随时扩充一个子类。而原来指向父类的方法不需要改变就可以用于新子类。这很重要。
借用别人博客的例子 同时考察了重写和重载
class A { public String show(D obj) { return ("A and D"); } public String show(A obj) { return ("A and A"); } } class B extends A { public String show(B obj) { return ("B and B"); } public String show(A obj) { return ("B and A"); } } class C extends B {} class D extends B {} public class Main { public static void main(String[] args) { A a1 = new A(); A a2 = new B(); B b = new B(); C c = new C(); D d = new D(); System.out.println(a1.show(b)); // 1 System.out.println(a1.show(c)); // 2 System.out.println(a1.show(d)); // 3 System.out.println(a2.show(b)); // 4 System.out.println(a2.show(c)); // 5 System.out.println(a2.show(d)); // 6 System.out.println(b.show(b)); // 7 System.out.println(b.show(c)); // 8 System.out.println(b.show(d)); // 9 } }
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"。然后根据参数选择。
输出:
A and A A and A A and D B and A B and A A and D B and B B and B A and D
再写一个我觉得需要注意的
class F { public void f1() { System.out.println("f1 in F"); f2(); } public void f2() { System.out.println("f2 in F"); } } class S extends F { public void f1() { System.out.println("f1 in S"); f2(); } public void f2() { System.out.println("f2 in S"); } } public class Main { public static void main(String[] args) { F f = new S(); f.f1(); } }
输出
f1 in S
f2 in S
class F { public void f1() { System.out.println("f1 in F"); f2(); } public void f2() { System.out.println("f2 in F"); } } class S extends F { public void f2() { System.out.println("f2 in S"); } } public class Main { public static void main(String[] args) { F f = new S(); f.f1(); } }
输出
f1 in F
f2 in S
class F { public void f1() { System.out.println("f1 in F"); } } class S extends F { public void f1() { System.out.println("f1 in S"); f2(); } public void f2() { System.out.println("f2 in S"); } } public class Main { public static void main(String[] args) { F f = new S(); f.f1(); } }
输出
f1 in S
f2 in S
class F { public void f1() { System.out.println("f1 in F"); f2(); } public void f2() { System.out.println("f2 in F"); } } class S extends F { public void f1() { System.out.println("f1 in S"); f2(); } } public class Main { public static void main(String[] args) { F f = new S(); f.f1(); } }
输出
f1 in S
f2 in F
主要注意一下第二个吧,可以看出即使是父类的方法中调用的方法也会被重写。
然后考虑一下final
考虑一下下面的代码输出什么class F { final void f() { System.out.println("F"); } } class S extends F { final void f() { System.out.println("S"); } } public class Main3 { public static void main(String[] args) { F f = new S(); f.f(); } }
答案是:
嗯。。编译错误。。Cannot override the final method
所以final方法不能被重写。当你不想让一个方法被重写,可以把方法设置为final
然后看一下private方法。虽然private也是final的,但是在这里还是有一点区别,因为父类的private方法对于子类是不可见的。
class F { private void f() { System.out.println("F"); } } class S extends F { // @Override 加上这句会出现错误 可知并不是重写 private void f() { System.out.println("S"); } } public class Main3 { public static void main(String[] args) { F f = new S(); //f.f(); Error:The method f() from the type F is not visible } }
对于private方法可以在子类添加相同方法,但并不是重写,只是一个无关的全新方法,同时这样会造成混淆,所以不要这样使用。
接下来是static
按照《thinking in java》上的说法,构造器也是static的(虽然并不理解)。构造器中最好只调用final方法。因为其他方法可能会造成重写,而我们又知道,初始化的时候是先初始化父类再初始化子类的,这样就会导致子类还未初始化完成就被调用,可能产生一些错误。静态方法的继承
class StaticSuper { static void f() { System.out.println("Super"); } } class StaticSub extends StaticSuper { static void f() { System.out.println("Sub"); // super.f(); error:Cannot use super in a static context } } public class Main { public static void main(String[] args) { StaticSuper sup = new StaticSub(); sup.f(); StaticSub sub = new StaticSub(); sub.f(); } }
输出:
Super
Sub
可知对于静态方法不存在多态,子类中方法会覆盖父类相同方法。但是静态方法是否被继承?
class StaticSuper { static void f() { System.out.println("Super"); } } class StaticSub extends StaticSuper { } public class Main { public static void main(String[] args) { StaticSuper sup = new StaticSub(); sup.f(); StaticSub sub = new StaticSub(); sub.f(); } }
输出
Super
Super
可见静态方法是会被继承的。
域
上面所有讨论的都是方法。对于域,是不存在多态的!class Super { public int field = 0; public int getField() { return field; } } class Sub extends Super { public int field = 1; public int getField() { return field; } public int getSuperField() { return super.field; } } public class Main { public static void main(String[] args) { Super sup = new Sub(); System.out.println(sup.getField()); Sub sub = new Sub(); System.out.println(sub.getField()); System.out.println(sub.getSuperField()); } }
输出
1
1
0
over~~
相关文章推荐
- Java抽象类与接口的区别
- 基于Spring + Spring MVC + Mybatis 高性能web构建
- SpringMVC学习记录(三)--异常处理
- java学习之Java注解
- 基于 Spring 和 iBATIS 的动态可更新多数据源持久层
- struts2笔记07-action扩展名
- Java 应用类 - 这些功能再也不用自己写了
- 【LeetCode-61】Rotate List
- 搭建Android开发环境和第一个Android程序(Eclipse版)
- 学习javaEE每一天2016.4.4
- 为什么用spring
- Spring PropertyPlaceholderConfigurer 简单使用
- Java 读取 AD 用户
- java核心基础文章精选
- spring和mybatise的整合
- Eclipse上安装springsource-tool-suite
- 重读《Java编程思想(第四版)》(1-9章)
- Java基础-多线程-③线程同步之synchronized
- Java基础-多线程-②多线程安全问题
- java bridge method