《THING IN JAVA》 7章复用类-读书笔记

1、组合语法
2、继承语法

(1)当创建一个类时总是在继承,除非已明确指出要从其他类中继承,否则就是在隐式地从Java的标准根类Object进行继承。

(2)当一个类继承另一个类时,会自动得到基类中所有的域和方法。

(3)可以为每个类都创建一个main()方法。这种在每个类都设置一个main()方法的技术可使每个类的单元测试都变得简便易行。

(4)即使一个类只具有包访问权限,其public main()仍然是可以访问的。

(5)一般来说为了继承,一般的规则是将所有的数据成员都指定为private,将所有的方法指定为public,当然在特殊情况下,必须做出调整。

(6)如果在基类中想调用超类的方法,super关键字代表了超类对象,否则达不到调用的效果。

(7)在继承时关于带参数的构造器:必须用关键字super显式地编写调用基类构造器的语句,并且配以适当的参数列表,否则编译器会无法找到合适的构造器而报编译错误,并且,调用基类构造器必须是你在导出类构造器中要做的第一件事。


3、代理

(1)代理关系:Java并没有提供对它的直接支持。这是继承与组合之间的中庸之道,下面展示一个代理的例子:


//展示代理关系

public class MyTest1 {
public void f(int i){
System.out.println("i="+i);
}
}

class MyTest2 {
private MyTest1 myTest1 = new MyTest1();
public void f(int i ){
myTest1.f(i);
}
}

可以看到,我们使用代理时可以拥有更多的控制力,因为我们可以选择只提供在成员对象中的方法的某个子集。

尽管Java语言不直接支持代理,但是很多开发工具却支持代理。例如,使用JetBrains IdeaIDE就可以自动生成上面的例子。


4、结合使用组合和继承

(1)析构函数是一种在对象被销毁时可以被自动调用的函数。其原因可能是因为在Java中,我们的习惯只是忘掉而不是销毁对象,并且让垃圾回收器在必要使释放其内存。

(2)因此,如果你要某个类清理一些东西,其首要任务就是,必须将这一清理动作置于finally子句之中,以预防异常的出现。

(3)垃圾回收器可能永远也无法被调用,即使被调用,它也可能以任何它想要的顺序来回收对象。最好的办法是除了内存以外,不能依赖垃圾回收器去做任何事。如果需要进行清理,最好是编写自己的清理方法,但不要使用finalize()。

(4)Java SE5新增加了@Override注解,它并不是关键字,但是可以把它当作关键字使用。当你想要覆写某个方法时,可以选择添加这个注解,在你不留心重载而并非覆写了该方法时,编译器就会生成一条错误消息:


public class MyTest3 {
public void f(){
System.out.println("This is the class MyTest3");
}
}


class MyTest4 extends MyTest3{
@Override
public void f(String s){  //编译错误
System.out.println("This is the class MyTest4");
}
}


@Override注解可以防止你在不想重载时而意外地进行了重载


5、在组合与继承之间选择

(1)组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形(其实在复用代码中经常碰见这种情况,由于两个功能所包含的代码能复用,经常进行“抽类”以达到代码复用的效果),为取得此效果,需要在新类中嵌入一个现有类的private对象。

(2)“is-a”(是一个)的关系是用继承来表达的,而“has-a”(有一个)的关系则是用组合来表达的。


6、protected关键字

(1)尽管可以创建protected域,但是最好的方式还是将域保持为private


7、向上转型

(1)在向上转型的过程中,类接口中惟一可能发生的事情是丢失方法,而不是获取它们。 向以下例子:


public class MyTest5 {
public void f(){
System.out.println("This is the class MyTest5");
}
public static void main(String[] args){
MyTest5 t = new MyTest6();
t.f();     //向上转型调用的方法,如子类有重写方法,则调用子类的
// t.g();     //向上转型会丢失方法
}
}


class MyTest6 extends MyTest5{
public void f(){
System.out.println("This is the class MyTest6");
}
public void g(){
System.out.println("The mothod g");
}
}


(2)再论组合与继承

在实际中,继承技术其实不太常用的。因此,尽管在教授OOP的过程中我们多次强调继承,但并不意味可以随便滥用,相反,使用时应谨慎使用。

应该是使用组合还是继承这里有一个清晰的判断:

是否需要从新类向基类进行向上转型。如果必须向上转型,则继承是必须的,但如果不需要,则应当好好考虑自己是否需要继承。


8、final关键字

先看下面一个实例:


public class MyTest7 {
private static Random rand = new Random(47);
private String id;
public MyTest7(String id){
this.id = id;
}
private final int valueOne = 9;
private static final int VALUE_TWO = 99;
public static final int VALUE_THREE = 39;
private final int i4 = rand.nextInt(20);
static final int INT_5 = rand.nextInt(20);
private Value v1 = new Value(11);
private final Value v2 = new Value(22);
private static final Value VAL_3 = new Value(33);
private final int[] a = {1,2,3,4,5,6};

@Override
public String toString(){
return id + ":"+"i4=" + i4 + ",INT_5" + INT_5;
}

public static void main(String[] args){
MyTest7 t1 = new MyTest7("t1");
// t1.valueOne++;  //不能改变常量的值
t1.v2.i++;
t1.v1 = new Value(9);
for(int i =0;i<t1.a.length;i++){
t1.a[i]++;
}
// t1.v2 = new Value(0);  //用final修饰的引用对象不能指向新的对象
// t1.VAL_3 = new Value(1);
// t1.a = new int[3];

System.out.println(t1);
System.out.println("Creating new MyTest7");
MyTest7 t2 = new MyTest7("t2");
System.out.println(t1);
System.out.println(t2);
}
}


public class MyTest8 {
public void f(final int a){
a++;  //编译错误,参数为final不可修改
}
}


(1)定义为static,则强调只有一份,定义为final,则说明它是一个常量。请注意,带有恒定初始值(也就是说关键字为 static final 的变量不允许空final)

(2)空白final:Java允许生成“空白final”,所谓空白final是指被声明为final但又未给定初值的域,编译器都确保空白final在使用前必须被初始化(static final 除外)。

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

(4)final方法:使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义。这是出于设计的考虑,想要确保在继承中使方法行为保持不变,并且不会被覆盖。第二个原因是效率,这个在近期的Java版本中,可以探测到这些情况,因此不再需要使用final方法进行优化了。

(5)final和private关键字:类中所有的private方法都隐式地指定为是final的。由于无法取用private方法,所以也就无法覆盖它。可以对private方法添加final修饰词,但这并不能给该方法增加任何额外的定义

(6)final类:当将某个类的整体定义为final时(通过将关键字final置于它的定义之前),就表明了你打算继承该类,而且也不允许别人这样做。

(7)由于final类禁止继承,所以final类中所有的方法都隐式指定为是final的,因为无法覆盖它们。在final类中可以给方法添加final修饰词,但这不会增加任何意义。


9、初始化及类的加载

(1)一般来说,可以说:”类的代码在初次使用时才加载。“这通常是指加载发生于创建类的第一个对象之时,但是当访问static域或static方法时,也会被加载(在下一节会有例子一并证明)

(2)在对类编译的过程中,编译器注意到它有一个基类(这是由关键字extends得知的),于是它继续进行加载,不管你是否打算产生一个该类的对象。

(3)如果该基类还有自身的基类,会以此类推逐一加载,这种方式很重要,因为导出类的static初始化可能会依赖于基类成员能否被正确初始化,必要的类都已加载完毕,对象就可以被创建。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值