就 风子柒 “多态和对象的故事” 谈谈我的理解_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 就 风子柒 “多态和对象的故事” 谈谈我的理解

就 风子柒 “多态和对象的故事” 谈谈我的理解

 2012/4/10 13:52:58  逸情公子  程序员俱乐部  我要评论(0)
  • 摘要:就风子柒“多态和对象的故事”谈谈我的理解前记:今晚看到风子柒的一篇名为“我不知道的事—多态和对象的故事”的技术博客,博客地址为:http://februus.iteye.com/blog/1473534,博客借用一段代码讨论了两个知识点:1.构造器里的this关键字2.覆盖和多态看原文的分析过程,似乎有些“暧昧”,感觉对有些问题分析的还是不够深入,所以就说一点自己的理解吧。提出问题:题目代码如下,你知道它的输出结果吗?代码一:classA{privateStringstr="a"
  • 标签:故事 理解

??????????? 就 风子柒 “多态和对象的故事” 谈谈我的理解
前记:

今晚看到风子柒的一篇名为“我不知道的事—多态和对象的故事 ”的技术博客,博客地址为: 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方法无法触及而且能有效隐藏,所以除了把他看成是因为它所归属的类的组织结构的原因而存在外,其他任何事物都不需要考虑到它。


呵呵,这个问题还是蛮有意思的,如有不同意见,希望可以交流。


?

?

?

发表评论
用户名: 匿名