就 风子柒 “多态和对象的故事” 谈谈我的理解
前记:
今晚看到风子柒的一篇名为“我不知道的事—多态和对象的故事 ”的技术博客,博客地址为:
http://februus.iteye.com/blog/1473534
,博客借用一段代码讨论了两个知识点:
1.构造器里的this关键字
2.覆盖和多态
看原文的分析过程,似乎有些“暧昧”,感觉对有些问题分析的还是不够深入,所以就说一点自己的理解吧。
提出问题:
题目代码如下,你知道它的输出结果吗?
代码一:
class A{
private String str = "a";
public A(){
System.out.println("constructor A");
System.out.println("this in A is : " + this.getClass());
System.out.println("this.str : " + this.str);
this.fun();
System.out.println("------------------------------------");
}
public void fun(){
System.out.println("A.fun() > " + str);
}
}
class B extends A{
private String str = "b";
public B(){
System.out.println("constructor B");
System.out.println("this in B is : " + this.getClass());
System.out.println("this.str : " + this.str);
this.fun();
System.out.println("-------------------------------------");
}
public void fun(){
System.out.println("B.fun() > " + str);
}
}
class C extends B{
private String str = "c";
public C(){
System.out.println("constructor C");
System.out.println("this in C is : " + this.getClass());
System.out.println("this.str : " + this.str);
this.fun();
System.out.println("------------------------------------");
}
public void fun(){
System.out.println("C.fun() > " + str);
}
}
public class Tester {
public static void main(String[] args) {
new C();
}
}
第一眼看到这段代码,我还是考虑了很久的,呵呵,代码考的确实蛮有水平的。不过知识点应该就是:1.this关键字;2.覆盖和多态。下面贴出输出结果吧:
结果一:
constructor A
this in A is : class C
this.str : a
C.fun() > null
------------------------------------
constructor B
this in B is : class C
this.str : b
C.fun() > null
-------------------------------------
constructor C
this in C is : class C
this.str : c
C.fun() > c
------------------------------------
如果你心中想的结果和上面的存在差别,那就和我一起来窥探窥探其中的奥秘吧。
分析问题:
1.你真的知道java中的this关键字吗?
很多初学者以为this关键字是这个类的对象的引用,其实这个理解只在一般的情况下成立,而在这种情况下不成立。那什么情况是一般情况呢?下面我贴出一段代码吧:
代码二:
/**
* @author 小路
*
*/
public class ThisTest {
public void show(){
System.out.println("这是一个This测试类。");
}
public static void main(String[] args) {
ThisTest tt = new ThisTest(); //后面会分析
tt.show();
}
}
当tt调用show()方法时,其实编译器做了一些幕后工作,它隐含地传入了一个参数,这个参数就是tt(“所操作对象的引用”),可能你是第一次听到这种说法,不过没关系,它可以让你搞清楚什么是this。当tt调用show方法时,ThisTest中的this就被赋值成了tt,在这种情况下this关键字是这个类的对象的引用,也就是tt所指对象的引用。
我们回到原题中的this,先分析一下类C,不过在分析之前,我们需要有一点额外的知识。再看代码二中创建tt对象的语句(代码中标注为:“后面会分析”),其实在成功创建一个ThisTest对象之前,或者说在构造函数还没执行完,tt就已经被赋值了。(引申:呵呵,更可怕的是在执行构造函数之前tt就可能被赋值了。如果此时tt不是局部变量,而是类的属性时(假如属性中只是定义,没有在堆区创建对象),在并发的情况下,对tt对象的创建就可能导致无序的问题。这个问题会出现在“双重检查锁”中,参考博客:http://www.ibm.com/developerworks/cn/java/j-dcl.html。)所以这个时候类C的构造函数中的this关键字指的就是所创建的类C对象的引用。不过在执行类C构造函数中的代码之前,会先创建类B对象,同时把类C中的this传给刚创建的类B的对象,并将类B中的this赋值成传入的这个this(呵呵,希望你不要晕);同样在执行类B构造函数之前会先创建类A对象•••(呵呵,你懂得)。所以,最终这个this指的对象其实是堆区的同一个对象,也就是最初创建的类C对象。这就说明了为什么this.getClass()打印出的结果是一样的,并且都是Class C。那我们该怎么理解this呢?总结一下,其实this表示对当前对象的引用。
2.你真的知道java中的多态吗?
我们知道java中存在多态机制,即子类会覆盖父类同名的方法。那java中的属性有多态机制吗?查阅相关资料你会发现,java中的属性是表示“状态”的,它不具备多态性,所以在编译this.str时,编译器就直接把它当成了str。即自己类内部定义的str。而在执行this.fun()时,就存在多态机制,又此时的this都是指向了类C的对象,所以结果都是执行了类C中的fun方法。但类A和类B的构造函数在执行类C的fun方法时,类C中的str还没有被初始化,还记得吗?这个时候类C的构造函数还没有执行哦。所以此时类A和类B打印出了“C.fun() > null”。到此为止这个问题算是圆满解决了。
可是前面我说:java中存在多态机制,即子类会覆盖父类同名的方法。我们思考一下,是不是只要是同名方法,子类都会覆盖父类呢?如果方法是用private修饰的呢?于是我把类A、类B、类C三个类中的fun方法都改为了private类型。运行结果如下:
结果二:
constructor A
this in A is : class C
this.str : a
A.fun() > a
------------------------------------
constructor B
this in B is : class C
this.str : b
B.fun() > b
-------------------------------------
constructor C
this in C is : class C
this.str : c
C.fun() > c
------------------------------------
这个时候调用this.fun()其实和this.str一样,因为在java中被private修饰的方法和被final修饰后的方法一样不能被子类覆盖。下面引用java编程思想第四版第144页中的一段话:“覆盖”只有在某方法是基类的接口的一部分才会出现。即,必须能将一个对象向上转型为它的基本类型并调用相同的方法。如果某方法为private,它就不是某类的接口的一部分。它仅是一些隐藏于类中的程序代码,只不过是具有相同的名字而已。但如果在导出类中以相同的名称生成一个public、protected或包访问权限方法的话,该方法就不会产生在基类中出现的“仅有相同名称”的情况。此时你并没有覆盖此方法,仅是生成了一个新的方法。由于private方法无法触及而且能有效隐藏,所以除了把他看成是因为它所归属的类的组织结构的原因而存在外,其他任何事物都不需要考虑到它。
呵呵,这个问题还是蛮有意思的,如有不同意见,希望可以交流。
分享到:
相关推荐
允许你继承一个抽象的public接口之后,封装相关的类型,需要付出的代价就是额外的间接性--不论是在内存的获得,或是在类的决断上,C++通过class的pointer和references来支持多态,这种程序风格就称为"面向对象"。...
允许你继承一个抽象的public接口之后,封装相关的类型,需要付出的代价就是额外的间接性--不论是在内存的获得,或是在类的决断上,C++通过class的pointer和references来支持多态,这种程序风格就称为"面向对象"。...
C++补充-多态,简绍了有很多有用的东西,值得学习参考!希望对你有用!
谈谈我对redis分布式锁的理解以及设计
day10【接口、多态】.pdf
越风子办公助手是一款能为用户提供备忘事件提醒、通讯录、事务管理等功能的办公助手,绿色小巧又实用。欢迎各位有需要的小伙伴还在犹豫什么,快来脚本之家下载使用吧! 软件特色 具有备忘录、日记簿、通讯录等功能...
8.2 理解Session的缓存 8.2.1 Session的缓存的作用 8.2.2 脏检查及清理缓存的机制 8.3 Java对象在Hibernate持久化层的状态 8.3.1 临时对象的特征 8.3.2 持久化对象的特征 8.3.3 被删除对象的特征 ...
2、锻炼学生在设计的过程中,建立清晰的类层次,应用继承和多态等面向对象的编程思想; 3、通过本课程设计,加深对面向对象程序设计课程所学知识的理解,熟练掌握和巩固C++语言的基本知识和语法规范,深刻体会面向...
理解掌握友元函数和重载操作符,动态数组,理解掌握继承和多态性:掌握模版的使用:能够进行程序调试过程中的异常处理:进一步掌握利用C++进行类的定义和操作方法:进一步掌握类的继承和派生方法:进一步理解虚函数和多态:...
面向对象的编程语言将客观事物看作具有属性和行为的对象,通过抽象找出同一类对象的共同属性(静态特征)和行为(动态特征),形成类。通过类的继承与多态可以很方便地实现代码重用,大大缩短了软件开发周期,并使得...
掌握Java类的概念、定义及创建类对象的方法,掌握面向对象编程的 基本方法、类的定义和对象创建、方法重载的概念、类的继承概念、多态的概念、理解抽象类与接口的相关概念等相关概念。 4. 掌握Java图形界面程序的...
符合Python风格的对象对象表示形式获取对象的字符串表示形式的标准方式repr() 以便于开发者理解的方式返回对象的字符串表示形式。__format__ 方法
这是参考了BOOST的内存池和对象池的实现的,基本上和BOOST的代码一样,不同的是: (1)风格不一样; (2)把实现的代码尽量简化了 (3)大多代码都加了详尽的注释(注释是中文的) 个人认为这份代码的意义在于如果...
8.2 理解Session的缓存 8.2.1 Session的缓存的作用 8.2.2 脏检查及清理缓存的机制 8.3 Java对象在Hibernate持久化层的状态 8.3.1 临时对象的特征 8.3.2 持久化对象的特征 8.3.3 被删除对象的特征 ...
8.2 理解Session的缓存 8.2.1 Session的缓存的作用 8.2.2 脏检查及清理缓存的机制 8.3 Java对象在Hibernate持久化层的状态 8.3.1 临时对象的特征 8.3.2 持久化对象的特征 8.3.3 被删除对象的特征 ...
8.2 理解Session的缓存 8.2.1 Session的缓存的作用 8.2.2 脏检查及清理缓存的机制 8.3 Java对象在Hibernate持久化层的状态 8.3.1 临时对象的特征 8.3.2 持久化对象的特征 8.3.3 被删除对象的特征 ...
面向对象:理解类(Class)、对象(Object)、实例变量(Instance Variables)、方法(Methods)、继承(Inheritance)、封装(Encapsulation)和多态(Polymorphism)等概念。 内存管理:了解ARC(Automatic Reference Counting,...
20210808-天风证券-机械设备行业:如何理解工程机械板块的周期平滑?.pdf
面向对象: Java是一种纯粹的面向对象编程语言,支持封装、继承和多态等面向对象的概念。这使得Java编写的代码更加模块化、可维护和可扩展。 多线程支持: Java内置了对多线程的支持,允许程序同时执行多个任务。这...