java 关于多态的一点总结
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.可扩展性。只要写一个父类,就可以随时扩充一个子类。而原来指向父类的方法不需要改变就可以用于新子类。这很重要。
借用别人博客的例子 同时考察了重写和重载
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)); //
System.out.println(a1.show(c)); //
System.out.println(a1.show(d)); //
System.out.println(a2.show(b)); //
System.out.println(a2.show(c)); //
System.out.println(a2.show(d)); //
System.out.println(b.show(b)); //
System.out.println(b.show(c)); //
System.out.println(b.show(d)); //
}
}
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 关于多态的一点总结的更多相关文章
- 深入Java核心 Java中多态的实现机制(1)
在疯狂java中,多态是这样解释的: 多态:相同类型的变量,调用同一个方法时,呈现出多中不同的行为特征, 这就是多态. 加上下面的解释:(多态四小类:强制的,重载的,参数的和包含的) 同时, 还用人这 ...
- 从虚拟机指令执行的角度分析JAVA中多态的实现原理
从虚拟机指令执行的角度分析JAVA中多态的实现原理 前几天突然被一个"家伙"问了几个问题,其中一个是:JAVA中的多态的实现原理是什么? 我一想,这肯定不是从语法的角度来阐释多态吧 ...
- 学习博客之Java继承多态接口
这一篇博客主要是对软工前一阶段学习的总结,主要是对Java的学习总结,包括三部分:Java的继承.多态和接口 Java的继承 继承是面向对象的三大特性之一,能够实现软件的复用. Java子类继承父类的 ...
- java的多态以及重载,重写,前期绑定,后期绑定
多态的定义: 一个类实例的相同方法在不同情形有不同表现形式.多态机制使具有不同内部结构的对象可以共享相同的外部接口.这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通 ...
- 关于java中多态的理解
java三大特性:封装,继承,多态. 多态是java的非常重要的一个特性: 那么问题来了:什么是多态呢? 定义:指允许不同类的对象对同一消息做出响应.即同一消息可以根据发送对象的不同而采用多种不同的行 ...
- 个人对Java中多态的一些简单理解
什么是多态 面向对象的三大特性:封装.继承.多态.从一定角度来看,封装和继承几乎都是为多态而准备的.这是我们最后一个概念,也是最重要的知识点. 多态的定义:指允许不同类的对象对同一消息做出响应.即同一 ...
- Java中多态的一些简单理解
什么是多态 .面向对象的三大特性:封装.继承.多态.从一定角度来看,封装和继承几乎都是为多态而准备的.这是我们最后一个概念,也是最重要的知识点. .多态的定义:指允许不同类的对象对同一消息做出响应.即 ...
- Java JVM 多态(动态绑定)
Java JVM 多态(动态绑定) @author ixenos 摘要:绑定.动态绑定实现多态.多态的缺陷.纯继承与扩展接口.向下转型与RTTI 绑定 将一个方法的调用和一个方法的主体关联起来,称作( ...
- java异常捕获的一点感悟
class Annoyance extends Exception {} class Sneeze extends Annoyance {} class Human { public static v ...
随机推荐
- 在使用Fake framework的时候,为什么有一些函数没有生产mock呢?
在使用Visual studio 2012 的Fake framework 做单元测试的时候,你会发现有一些函数没有生产Stub 或者 Shim的版本,这可能是由于Fake的一些限制导致的,但如何知道 ...
- Junit4.12、Hamcrest1.3、Eclemma的安装和使用
1. Junit4.12和Hamcrest1.3的安装过程 步骤: 网上下载Junit和Hamcrest包文件,保存在本地. 新建Java项目命名为Triangle,在Eclipse菜单栏选择项目(P ...
- new 的用法
在C#中,new关键字有三种用法: 1.new 运算符,用于创建对象和调用构造函数. 2.new 修饰符,在用作修饰符时,new关键字可以显式隐藏从基类继承的成员. 3.new 约束 ,用于在泛型 ...
- HTML5&CSS3&JavaScript&PHP&MySQL学习笔记
1.在文字间添加一条水平线 使用<hr /> 注意该符号不是成对出现的 2.<q> </q>用来标记于段落中的较短引用,浏览器会在它之间的语句两端加上双引号. ...
- gcc和g++的区别
参考What is the difference between g++ and gcc? 1.The actual compiler is "cc1" for C and &qu ...
- ThinkPHP中视图模型详解.
很多TP的新手对于模型中的视图模型不甚了解,官方虽然有详细手册,但是对于初学者来说还是比较难以理解! 先简单说一下视图模型所能实现的功能,基本就是主表与副表之间各个字段的关联问题,实现多表关联查询,相 ...
- php-- 避免表单的重复提交
用户提交表单时可能因为网速的原因,或者网页被恶意刷新,致使同一条记录重复插入到数据库中,这是一个比较棘手的问题.我们可以从客户端和服务器端一起着手,设法避免同一表单的重复提交. 1.使用客户端脚本 提 ...
- SSH框架中配置Hibernate使用proxool连接池
一.导入proxool.jar包 案例用的是proxool-0.8.3.jar,一般通过MyEclipse配置的SSH都会包含这个jar,如果没有,就去网上搜下下载导入就好了. 二.新建Proxool ...
- Visual Studio中一个解决方案设置多个启动项目
在解决方案上右键,选择属性. 这样设置之后,点击开始运行之后,会同时启动2个项目. 适合一个项目既包含客户端也包含服务端,方便调试
- Mysql表的七种引擎类型,InnoDB和MyISAM引擎对比区别总结
InnoDB和MyISAM区别总结 我用MySQL的时候用的是Navicat for MySQL(Navicat for mysql v9.0.15注册码生成器)操作库.表操作的,默认的表就是Inno ...