Java编程思想读书笔记--第七章 复用类

复用类是什么?

  • 众所周知,面向对象的其中一个特性就是继承,也就是我们今天所说的复用类的一种。我们一般将其运用在,需要使用一段旧的代码,但又需要对其进行部分修改。 这个时候,我们选择复用类,可以通过创建新类来复用代码,更大程度上使原代码不被破坏。
  • 复用类目前包含
    • 组合
    • 继承
    • 代理

组合

组合技术简单来说,就是将对象引用于新类中即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 组合
*/
public class ShowCombination {

public void combination(){
//doSomething
System.out.println("ShowCombination");
}
}

class UseCombination{
public void use(){
ShowCombination showCombination = new ShowCombination();
showCombination.combination();
//doSomething
System.out.println("UseCombination");
}

public static void main(String[] args) {
UseCombination useCombination = new UseCombination();
useCombination.use();
}
}/* Output:
ShowCombination
UseCombination
*///:~
`

那么,我们是否可以理解为组合就是创建一个新类去调用已经创建并且调试好的类(在新类里实例化之前的类)?

继承

我们使用extends关键字去实现类复用。这里的ShowExtends被我们称作基类(父类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
* 继承
*/
public class ShowExtends {
public ShowExtends() {
System.out.println("this is ShowExtends construction ");
}

public void extendsMethod(){
//doSomething
System.out.println("ShowExtends");
}

}

class UseExtends extends ShowExtends{

public UseExtends() {
System.out.println("this is UseExtends construction ");
}

@Override
public void extendsMethod() {
super.extendsMethod();
//doSomething
System.out.println("UseExtends");
}

public void otherMethod(){
System.out.println("this is new method");
}
public static void main(String[] args) {
UseExtends useExtends = new UseExtends();
useExtends.extendsMethod();
useExtends.otherMethod();
}
}/* Output:
this is ShowExtends construction
this is UseExtends construction
ShowExtends
UseExtends
this is new method
*///:~

如上代码所看到的,我们在子类使用extends继承父类,这个时候,我们可以使用父类的方法;同时,也可以重写父类的方法或新写一个方法。

注意:
1. 我们在继承父类的时候,父类的方法是不可用private去修饰的。
2. 一般,我们将保密程度较强,但是子类需要的方法定义为protected。
3. super.extendsMethod(), 我们尝试注释掉该句话,将不会执行父类的方法;
4. 在继承中,初始化的顺序是从父类->子类(先初始化父类构造方法,再初始子类构造方法,再进行下边的方法调用;这个时候,即使注释掉super.extendsMethod(),
父类构造方法依然会被初始化)。
5.@Override Java SE5 新增注解,用于想要复写某个方法时,在方法上加以注解。

代理

java并没有提供对代理的直接支持,代理是继承与组合之间的中庸之道。我们使用代理可以拥有更多的控制力,因为我们可以选择只提供在成员对象中的方法的某个子集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 代理
*/
public class ShowAgent {
void firstMethod(){}
void secondMethod(){}
void thirdMethod(){}
}

class UserAgent{
private ShowAgent showAgent = new ShowAgent();
public void secondMethod(){
showAgent.secondMethod();
}
}

向上转型

  • 向上转型:就继承来说,新类可以拥有现有类所有方法,同时可以增加自己新的方法。那我们可以概括为“新类是现有类的一种类型”。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 向上转型
*/
class Instrument{
public void play (){}
static void tune(Instrument i){
//...
i.play();
}
}

public class Wind extends Instrument{
public static void main(String[] args) {
Wind flute = new Wind();
Instrument.tune(flute); //Upcasting
}
}

在组合和继承之间选择

  • 组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形。即在新类中嵌入某个对象,让其实现所需要的功能,但是新类的用户看到的只是为新类所定义的接口,而非所嵌入对象的接口。(为去得此效果,需要在新类中嵌入一个现有类的private对象)
  • 在继承的时候,使用某个现有的类,并开发一个它的特殊版本。通常,这意味着你在使用一个通用类,并为了某个特殊需要而将其特殊化。
  • 选择:判断自己是否需要从新类向基类进行向上转型。如果必须向上转型,则使用继承。否则,则选择组合或者代理。

final 关键字

  • final是恒定不变的?
    • final 对于基本数据类型是恒定不变的。
    • 但是对于引用型数据类型,则是使引用恒定不变,而被引用的对象本身使可以改变的。
  • static :不可变的,静态的,不会随着对象的创建而变化
  • 将final数值定义为静态和非静态的区别:
    • 可以看出i1是随着初始化的变化而变化
    • i2则是固定不变的,这是因为i2是static的,在装载时已被初始化,而不是每次创建新对象时都会初始化。(定义为static的东西只会被初始化一次)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 将final数值定义为静态和非静态的区别
*/
public class FinalWithStatic {
private static Random rand = new Random(7);
private final int i1 = rand.nextInt(20);
static final int i2 = rand.nextInt(20);

@Override
public String toString() {
return "FinalWithStatic{" +
"i1=" + i1 +";i2=" + i2 +
'}';
}

public static void main(String[] args) {
FinalWithStatic fs1 = new FinalWithStatic();
FinalWithStatic fs2 = new FinalWithStatic();
System.out.println(fs1);
System.out.println(fs2);
}
}/*Output:
FinalWithStatic{i1=4;i2=16}
FinalWithStatic{i1=5;i2=16}
*///:~
  • 必须在域的定义处或者每个构造器中用表达式对final进行赋值,这正是final域在使用前总是被初始化的原因所在。

  • 使用final方法原因:

    • 将方法锁定,以防止任何继承类修改它的含义。
    • 效率 (考虑:所带来的性能提高会因为花费于方法内的时间量而被缩减)
    • 只有在想要明确禁止覆盖时,方可将方法设置为final的
  • final 类:

    • 当将某个类的整体定义为final时,就表示你不需要该类做任何变动和被其他类继承。
    • 由于final类禁止继承,所以final类中所有的方法都隐式指定为是final的,因为它们无法被覆盖。

初始化及类的加载

  • 包含static的初始化加载顺序
    • 先加载static
    • 之后加载构造方法
    • 之后加载被调用的类
  • 包含继承和static的初始化加载
    • 先加载父类static
    • 再加载子类static
    • 之后加载父类构造方法
    • 再加载子类构造方法
    • 之后再加载被调用的类

总结

  • 组合一般是将现有类型作为新类型底层实现的一部分来加以复用
  • 继承复用的是接口
  • 一般优先选择组合或者代理,只有确认必要时才使用继承