一个JAVA class的秘密

原创
2016/04/15 00:06
阅读数 251

今天看了刘欣写的《我是一个java class》感觉很有意思,最近刚好在看JAVA的构造函数,今天坐火车无聊有点时间,狗尾续貂写了这篇小说,仓促中写成有不少问题,请大家指正。

 

2016414  从北京到呼和浩特的火车上

 

 

一个JAVA class的秘密

(一)诞生

 

我突然有了意识,我感觉到一阵疼痛,就像什么力量突然划出内存的一片空间,把我突然塞了进来,不!使我诞生,接着这股力量开始在我的身体里塞东西。

我感觉到那股力量正在外部搜索什么,它找到后就把东西塞进我的身体里,这种感觉一遍又一遍地发生,有时它塞新的东西时会放在我的身体里的空闲部分,有时候又会覆盖原先已经放入的东西位置。尽管很疼,但是我还是看到了一个塞入的东西,

private password = ……..
private void displayPd(){……}


最后,突然一阵颤抖,我感觉这是最后一次疼痛了,因为这次明显和其他次不一样,感觉赋予了我力量和性格,

…………..
 Account(){
            private password = “123456”
           private void displayPd(){
…………..


我再次睡了过去。


(二)秘密

 

我叫com.mytaobao.domain.Account,一个普通的Java class,我在这个叫com.mytaobao.domain的小房间里已经睡了很长时间了,不过有时候Classloader会来叫醒我,让我去stack办公室,然后一堆线程就会打电话来,让我干这干那,干活时我身上都会有一个reference count显示这数字,每当这个数字显示为0时,我就知道自己很可能马上会回家睡觉了。(请看刘欣所著《我是一个java class》《我是一个线程》)


今天,classloader和它的文件检查器小弟又把我叫醒了,把我带到Stack办公室,我就开始干活,一直有线程电话打进来,让我拿这拿那,忙个不停。


我刚忙一阵,一个电话打进来,一个有点迟疑的声音说”找到你那个叫password的抽屉,把它丢进displayPd的盒子里”,我马上照做了,还顺便看了一下结果

password ……. “123456”

真是太简单的密码了!是我出生时就放入我的身体里的缺省值,实际上大部分情况下这个值都会被修改成一个特别复杂、特别难记、特别长的值,上帝保佑制造那些值的人能永远记住它!

电话那边沉默了,可能是开发者进入了debug阶段。

休息了一段时间,线程打电话进来让我再次重复刚才工作,然后又休息,又重复,我都被它搞得烦死了,因为那个值总是123456,没有什么变化。当然,除了123456还能是什么,password是我出生时就赋予的,我太熟悉了,它不可能是其他的值。


然后进入了很长的一段休息时间,比平时都要长。


“这肯定是新的JAVA码农!”,边上的String一边品着咖啡,一边悠闲自得地说。


“Java是一门恐怖的语言,更恐怖地是还有一些菜鸟在使用着它,结果运行速度慢又说是我们的错,唉……..!”,String接着说,这家伙经常处理些文字材料,所以对人类世界了解颇多,不时还来一点经典格言,但是至于正确性,我总是内心表示怀疑。


“是啊,还是String大哥你知道的多,出口就是经典”,我附和道,虽然内心里有想法,但是String还经常帮我干些类型转换的事情,所以我得巴结它,而且它属于JAVA公司核心员工。


“我告诉你一个秘密,这次debug很长时间,据说和你有关,而且和你的父亲有很大关系,跟你父亲留给你的秘密有关”,String突然压低声音,很神秘地对我说。


“我?我的父亲?”,我感到很奇怪,我的父亲叫Record,但我还很少见到他。


“据说,Record在你身上留了一个Password属性,是Private的,现在需要查它当时留下来的值,但是你每次都只能给你的,所以现在开发者很烦恼,不知道怎么获取Record留给你的这个秘密”,String苦笑着对我说。


我顿时回忆起出生时的那阵感觉,没错!当时是在我身体里写入了一个Private password,但是我记得最后一次疼痛时,写入了一个另一个我自己Password,而我只知道我自己的这个Password,并不知道父亲Record留给我的Password,该怎么办呢?


“别担心,菜鸟去请教其他人了,他们会有办法的”,String对我眨眨眼睛,笑着说。


(三)upcast

果然,很快我又开始工作了,不过这次给我换了一个新stack办公室,刚开始进办公室时我转了一圈,竟然没有发现写我牌子的工位。

喂,你在瞎转什么呢,你的工位在这里?带我来的Classloader瞪了我一眼,指着一个工位说。

我转过去,看了看工位上的铭牌——“Record”咦,这不是我的工位啊,这是我父亲的工位,我大喊到。

没错,给我指令就是这个,你坐上去就是了,开始干活!Classloader给我看看它手中的命令,果然调用的是我的名字,而配对的工位的确是Record,不由分说,Classloader将我按到工位上。

就没有可能搞错吗?我说。

不可能!”Classloader没空跟我废话,丢了一句,急急忙忙地走开了。

死板、教条、墨守成规!我嘀咕道,开始打量起这个办公格子,和我以前工作的没有什么不同。

哈哈,你形容的非常准确,出生时就决定了我们的工作岗位和能力,这正是我静态语言的优点,如果像Javascript他们公司那样不稳定,出生之后还可以想到什么就可以加什么或改点什么,那工作效率就要大打折扣了,突然边上有人插话说。

我抬头一看,居然是java.util.Date,这家伙是外籍员工,可是Java之父James Gosling亲自创造的,想不到我居然有幸和他能坐在一起。

你好!我一时不知道说什么好,

你好!”Date说,我知道你的故事,也知道你为什么来这,这种父岗子做的事情在我们Java很常见,称为upcast”

“upcast?”我叫道,我从没有听过这个名词。

是的,我现在不忙,就跟你简单说说吧”Date瞅了一样桌上的安静的电话,对我说。

当你出生时,构造者会找到你所有的祖先,从第一个开始,逐个将他们的构造函数在你身上执行一遍,包括他们所有的属性和方法Date说。

哦!我想起来出生时那一遍又一遍的疼痛感,下意识地回复道。

包括private的属性!”Date强调,这个过程中,早期的方法会被后期相同名称的方法直接覆盖 ( override ),但属性不会,因为属性是分class空间存放的,所以即使是重名,也没有覆盖,这个问题《think  in java》第四版page 291讲得很清楚

“In this example, different storage is allocated for Super.field and Sub.field Thus, Sub actually contains two fields called field: its own and the one that it gets from Super. However, the Super version is not the default that is produced when you refer to field in Sub; in order to get the Super field you must explicitly say super.field “Date还飙了一大段英文,充分体现了他外籍员工的能力。

那你的意思说,我的父亲Record留给我的Password还藏在我的身体里,只是我不知道?我英文听力不大好,听不太懂其他的意思,于是直接问关键问题。

“Yes”Date肯定到,这家伙突然不知道从哪里找来一张图给我看

你可以访问的scope和你父亲可以访问的scope组成了scope chain,子类和父类的区别在于socpe chain的入口不同,如上图,很显然,子类object可以向上搜索父类的scope,但父类object不能反向搜索子类的scope。通过重写父类的方法,并重新绑定你自己的scope,虽然这样工位还是你父亲Record的,不用调整,但是你可以采取你自己更优秀、更快捷、更强大的方法来做,所以你比你父亲更强”Date笑着对我说。

不同于属性被分类存放,方法会被重写,根据图中的classmethod的颜色,object只能访问颜色相同的method。但是重写时方法的referencescope会被改变,比如上图的add 方法就被修改成指向你的scope,所以这时你的父亲和你调用这个方法是一样的。“Date说。

“但是,private的方法就不一样了,private 的方法不会被重写,如图你父亲的和你的private displayPd方法都存在你的身体里,而且指向各自的scope! “

所以,你可以访问父亲的private属性,但是你必须作为RecorD 才能访问到这个值!”Date指着工位上“Record“,意味深长地对我说。

我顿时恍然大悟,原来如此,所以我只有在我父亲Record的工位上才可以看得到父亲留给我的这份遗产。

这时,我桌上的电话响起来了,我伸手拿起了电话………

 

()

 

附故事的源代码

public class Record {
    
private String password "888888";
    private void 
displayPd(){
        System.
out.println(password);
    
}


    
public static void test(Record r){
        r.displayPd()
;
    
}

    
public static void main(String[] args) {
        Record ra = 
new Account();//upcast
        
test(ra)// 888888
    
}
}

class Account extends Record {
    
private String password "123456";
    private void 
displayPd(){
        System.
out.println(password);
    
}
}



展开阅读全文
打赏
1
9 收藏
分享
加载中
更多评论
打赏
0 评论
9 收藏
1
分享
返回顶部
顶部