Java编程思想之7复用类

本文探讨了继承和组合作为代码复用手段的本质相似性,分析了子类如何访问父类字段与方法的技术细节,以及final关键字的多种用途。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

伟大的书,每个地方都是伟大的。 

题目的理解

理解这一章,光题目,我理解经过了三个过程。 第一个过程:题目起的很糟糕,这一章的题目应该是继承。组合有什么好讲的啊,就是在一个类里面包含了别的类的对象。为什么为了这么个无关紧要的东西,就把这一章的题目改成了  复用类。  第二个过程:好吧。这个题目也凑合。两者确实比较相似,确实都算是复用了已有的代码,来创建新类型。复用类这个名字起的凑合。    第三个过程:这个名字起的太准确了。原来组合和继承,不仅仅是同时实现了代码复用。连两个的语法都那么类似。简直就是同一种技术。感觉只有将继承跟组合进行深入的比较,才能真正掌握继承。 另外,这一章仅仅是将了继承的一个特性:代码复用。继承的另一个伟大的特性:子类是父类的一种。将放在下一章讲。

为什么说组合和继承是同一种技术

组合和继承的语法规则很简单,就不说了。关键是继承是怎么实现的??    子类如何找到父类的字段,子类如何调用父类的方法??? 

子类如何找父类字段

这个确实很神奇,new了一个子类对象,父类的字段也有了。 必须肯定的是:创建子类实例时,确实给父类分配了空间,要不然父类的private字段存到哪里??这个是很容易验证的,验证父类的private字段的确存在。关键是为这个父类分配的空间在哪里分配的? 是跟子类的空间分配在一起,还是独立分配的?   而且必须在运行中检测访问权限。 这个问题困扰了我很久,但是后来发现,原来《java编程思想4》上面已经写的很清楚。我感觉很重要,就抄一下吧。

从外部看来,子类就像是一个与基类具有相同接口的新类,或许还会有一些额外的方法和域。但继承并不只是复制基类的接口。当创建了一个到处类的对象时,该对象包含了一个基类的子对象。这个子对象与你用基类直接创建的对象是一样的。二者的区别在于,后者来自于外部,而基类的子对象被包装在导出类的对象内部。(129页)

组合和继承都允许在新的类中放置子对象,组合是显示地这样做,而继承则是隐式地做。(137页)

说的已经很清楚了,其实就是分配了父类的一个变量,子类能活动这个变量。  还有一点不太明确的是: 如果父类是抽象类的话,如何生成父类的对象???(有可能是在虚拟机这一层可以这样生成抽象类型的对象实例??)  这两段话,也就说明了组合和继承真的很像,像同一种技术的两种方式。

子类如何找父类方法

子类是如何调用父类的方法呢???这个似乎是容易想到过程的。    首先实例方法调用的时候,都会传过去一个this变量,根据这个类在代码区的一些信息(这些信息表示的内容要比你开始写的java程序 还多) 完全可以找到这个类都包含哪些方法,这个类的父类是谁??   这就好办了,首先看看这个被调用的方法是不是这个类的某个方法,如果不是,就查找它的父类,一直找到Object类。如果都不是的话。那就该报错了。   这种方法调用其实是相当普遍的,为了加快这个过程,每个类都有一个虚方法表,包含了它能调用的所有方法,并且有这个方法的指针。 这样就可以很快找到 要调用的方法了。


final关键字 

(1)final数据  

          a.一个永不改变的编译期常量。

          b.一个在运行时被初始化的值,而你不希望它被改变。(可以是在构造方法中为其赋值)

(2)空白final

          final变量可以在构造方法中赋初值

(3)final参数

        你无法在方法中更改参数引用所指向的对象。

(4)final方法

         a.禁止覆盖

         b.提高效率

         c.类中所有private方法都隐式的是final的。

(5)final类

        不允许它有子类


初始化顺序

(1)基类static成员赋值

(2)子类static成员赋值

(3)基类实例变量赋默认值(分配空间后,全部赋值成0)

(4)基类实例变量赋值

(5)基类构造函数

(6)子类实例变量赋默认值(分配空间后,全部赋值成0)

(7)子类实例变量赋值

(8)子类构造函数。

类加载过程

(1)加载

(2)连接

        a. 验证

        b.准备:为类变量分配空间,赋默认值;

        c.解析:符号引用变直接引用;

(3)初始化:执行<clinit>方法,类变量赋值,静态语句块儿执行。

(4)使用

(5)卸载


这个初始化顺序,其实也好理解,首先基类应该在子类之前,因为子类中要包含基类的对象实例。静态成员肯定是在最前面的,他们在类使用之前就已经搞定了。为实例变量赋值的操作(如: private int a = 3;)在构造方法之前进行。 这个……我们应该知道构造方法的赋值,要比直接为实例变量赋值要灵活很多。 所有,灵活的放在后面用于覆盖之前的赋值操作,也是应该的。整个顺序还是跟我们想象的一致的。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值