第七章 复用类

第一种方法非常直观,就是组合。第二种方法就是继承。
组合只需将对象的引用置于新类中即可。


[color=blue]初始化基类[/color]

当创建了一个导出类的对象时,该对象包含了一个基类的子对象。这个子对象与你用基类直接创建对象是一样的。二者区别就是后者是来自于外部,前者来自于内部。
构建过程是从基类向外扩散的,所以基类在导出类构造器可以访问它之前,就已经完成了初始化。

[color=blue]结合使用组合和继承[/color]
Public class PlaceSertting extends Custom {
private Spoon sp;
private Fork frk;
}

虽然编译器强制你去初始化基类,并且要求你要在构造器起始处就要这么做,但是它并不监督你必须将成员对象也初始化,比如上面的Spoon等,都不会马上初始化。但是可以在构造函数中进行初始化。

[color=blue]final关键字[/color]

使用到final的三种情况:数据、方法和类。

对于编译器常量这种情况,编译器可以将该常量值带入任何可能用到它的计算式中,也就是说,可以在编译时执行计算式,这减轻了一些运行时的负担。在java中,这类常量必须是基本数据类型,并且以关键字final表示。在对这个常量进行定义的时候,必须对其进行赋值。

一个既是static又是final的域只占据一段不能改变的存储空间。

当对对象引用而不是基本类型运用final时,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象。然而,对象其自身确实可以被修改的,java并未提供使任何对象恒定不变的途径。

必须在域的定义处或者每个构造器中用表达式对final进行赋值,这正是final域在使用前总是被初始化的原因所在。

[color=blue]final参数[/color]

Java允许在参数列表中以声明的方式将参数指明为final。这意味着你无法在方法中更改参数引用所指向的对象。

[color=blue]final方法[/color]

在java早期实现中,如果一个方法是final的,就是同意编译器将针对该方法的所有调用都转为内嵌调用。但是如果方法太大,那么你的程序就会膨胀。在使用java SE5/6时,应该让编译器和JVM去处理效率问题,只有想要明确禁止覆盖时,才将方法设置为final的。

[color=blue]final和private关键字[/color]

类中所有private方法都隐式地指定为final的。由于无法读取private方法,所以也就无法覆盖它。可以对private方法添加final修饰词,但这并不能给该方法添加任何额外的意义。
父类有一个private方法,子类的方法即使和父类的方法名字一样,也不属于重写,private只代表他属于本类的一部分。

[color=blue]final类[/color]

当将某个类的整体定义为final时,就表明了你不打算继承该类。注意,final类的域可以根据个人的意愿选择为是或不是final。也就是说如果不是final的,类里面的属性是可以变化的。不论类是否被定义为final,相同的规则都适用于定义为final的域。然而,由于final类禁止继承,所以final类中所有方法都隐式指定为final的,因为无法覆盖它们。

[color=red]初始化及类的加载[/color]


在Beetle上运行java时,所发生的第一件事情就是试图访问Beetle.main(),于是加载器开始启动并找出Beetle类的编译代码(在名为Beetle.class的文件之中)。在对它进行加载的过程中,编译器注意到它有一个基类(这是由关键字extends得知的),于是它继续进行加载。不管你是否打算产生一个该基类的对象,这都要发生。

接下来根基类中的static初始化,然后是下一个导出类,以此类推。这种方式很重要,因为导出类的static初始化可能会依赖于基类成员能否被正确初始化。

至此为止,必要的类都已加载完毕,对象就可以被创建了。首先对象中的所有基本类型都会被设置为默认值,对象引用被设置为null-----这是通过将对象内存设为二进制零值而一举生成的。然后基类的构造器会被调用。然后就是子类的了。
package com.neu.edu.apitest;

public class Beetle extends Insect {
private int k = Test.printInit("Beetle.k initalized");

public Beetle() {
System.out.println("Beetle constructor");
System.out.println("k = " + k);
System.out.println("j = " + j);
}

private static int x2 = Test.printInit("static Beetle.x2 initialized");

public static void main(String[] args) {

Beetle b = new Beetle();
}
}

package com.neu.edu.apitest;

class Insect {
private int i = 9;
protected int j = Test.printInit("Insect.j initalized");

Insect() {
System.out.println("Insect constructor");
System.out.println("I = " + i + ", j = " + j);
j = 39;
}

private static int x1 = Test.printInit("static insect.x1 initialLized");
}


打印的结果:
static insect.x1 initialLized
static Beetle.x2 initialized
Insect.j initalized
Insect constructor
I = 9, j = 1
Beetle.k initalized
Beetle constructor
k = 1
j = 39


[color=red]加载顺序:
1.运行父类的static部分,然后是子类的static部分。
2.父类的变量开始初始化,然后调用构造方法。
3.子类的变量开始初始化,然后调用构造方法。[/color]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值