就 风子柒 “多态和对象的故事” 谈谈我的理解
前记:
今晚看到风子柒的一篇名为“我不知道的事—多态和对象的故事 ”的技术博客,博客地址为:
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来支持多态,这种程序风格就称为"面向对象"。...
这一阶段的关键概念包括对象、类、接口、继承、封装和多态等。对象是现实世界中具有特定属性和行为的实体,类是对相似对象的抽象,接口定义了对象间交互的方式,继承允许类之间共享属性和行为,封装则保护对象的内部...
在Java编程语言中,接口(Interface)和多态(Polymorphism)是两个非常核心的概念,它们与面向对象编程(OOP)紧密相关。在本篇文章中,我们将深入探讨接口的三大特征——多态,引用类型转换,以及接口在Java语言中...
面向对象设计的关键在于封装、继承和多态。封装使数据和行为结合在一起,保护内部状态不被外部随意修改。继承允许我们创建新的类,它们具有现有类的属性和行为,而无需重复代码。多态则允许我们通过基类的指针或引用...
在C++中,面向对象主要体现在三个方面:封装、继承和多态。 1. 封装:封装是面向对象的基础,它隐藏了对象内部的实现细节,只对外提供接口进行交互。在C++中,通过定义类(class)来实现封装。类是具有相同属性和...
允许你继承一个抽象的public接口之后,封装相关的类型,需要付出的代价就是额外的间接性--不论是在内存的获得,或是在类的决断上,C++通过class的pointer和references来支持多态,这种程序风格就称为"面向对象"。...
面向对象编程(Object-Oriented Programming,简称OOP)是一种重要的编程范式,它基于“对象”的概念,通过封装、继承和多态等核心特性,实现了代码的复用和模块化设计。C++是一种支持面向对象编程的强类型、编译型...
面向对象程序设计是一种重要的编程范式,它基于“对象”的概念,将数据和操作数据的方法封装在一起,使得代码更易于理解和维护。谭浩强老师在IT教育领域有着深厚的造诣,他的面向对象程序设计课程因其深入浅出的讲解...
JavaScript,作为一种广泛使用的脚本语言,常常被误解为非面向对象的语言,但实际上,JavaScript完全支持面向对象编程(OOP)的三大核心原则:封装、继承和多态。尽管它的实现方式与传统的面向对象语言(如Java或C++...
面向对象的程序设计是软件开发中的核心概念,它基于“对象”的思想,将数据和操作数据的方法封装在一起,使得代码更具有模块化、可维护性和重用性。...学习这些知识对于理解C++和面向对象编程至关重要。
本教案旨在帮助学习者深入理解和掌握面向对象编程的核心原理和实践技巧。 1. **面向对象的基本概念** - **对象**:面向对象编程中的核心元素,代表现实世界中的实体,包含属性(数据)和行为(方法)。 - **类**...
面向对象编程(Object-Oriented Programming,简称OOP)是一种编程范式,它将程序设计中的实体(如数据和操作)封装在一起,形成对象。在本案例中,"KWIC"(Key-Word in Context)源代码是用面向对象的方式实现的。...
Objective-C允许开发者使用C语言进行编程,同时引入了Smalltalk风格的消息传递机制,从而提供了类、继承和多态等面向对象特性。 面向对象编程的关键概念包括: 1. 数据和操作:数据通常指的是对象的状态,操作指的...
面向对象系统设计是一种广泛应用在软件工程中的方法论,它基于对象和类的概念,通过封装、继承和多态等机制来构建复杂系统。本教程“面向对象系统设计循序渐进”旨在为初学者提供一个易懂的学习路径,帮助他们逐步...
- 缺乏内置支持:C语言本身不支持类、继承和多态等面向对象特性,需要通过技巧来模拟。 - 性能影响:由于面向对象的一些特性是通过函数指针和间接调用来实现的,这可能会对程序的性能产生一定影响。 - 可读性和可...
面向对象程序设计是一种软件开发范式,它以对象为基础来构建软件模型,其基本概念包括封装、继承和多态。结构化程序设计则更侧重于过程,它以功能模块为软件开发的基础。从结构化设计风格向面向对象程序设计的转变,...
而面向对象的代码虽然看起来更为复杂,但通过封装、继承和多态等特性,能够更好地组织代码,提高代码的复用性和可维护性。例如,在`MathNum`类中,如果未来需要对素数相关的算法进行修改或扩展,只需要在该类中进行...