Java读书笔记--Thinking in Java

Java初学者,记录TIJ自己觉得重要的点。

static
只有在创建类的第一个对象 (或者第一次访问static成员) 的时候,static成员才会被初始化,此后static对象不会再作初始化。如果先前没有创建过对象,因而其static的成员尚未初始化的话,初始化会先处理其static成员,再处理非static的对象。

package
对于一个MyClass.java文件,其中可以有,而且只能有一个public类,而这个类的名字只能是MyClass (大小写都要相同)。
如果要用 MyClass ,或者 mypackage 中的其他 public 类,就要使用 import 关键词来引入 package:

    import mypackage.*

或给出这个类的全名:

     mypackage.MyClass m = new mypackage.MyClass();

上述情况下,环境变量CLASSPATH中需加入package的路径,这是通过操作系统设置的。查找当前目录,需把 ‘.’ 放到CLASSPATH。

默认的package:两个文件(.java)在同一个目录中,且都没有package声明。

条件编译 (conditional code) 用于调试代码
调试功能在开发版里是能用的,但在正式版里被禁用。可以通过修改package来切换调试版和发布版所使用的代码。

singleton

class Soup{
        private Soup() {}
    // (1) Allow creation via static method
        public static Soup makeSoup() {
                return new Soup();
        }
    // (2) Create a static object and return a reference upon request. (The “Singleton” pattern)
        private static Soup ps1 = new Soup();
    public static Soup access(){
        return ps1;
    }
    public void f() {}
}

singleton模式,只允许你创建一个这种类的对象。这个对象是被当做Soup类的static private成员来创建的,因此它有且只有一个对象,而且除非是通过public的access()方法,否则没法获取。

合成
所有非primitive对象都有一个toString()方法,当编译器需要一个String而它却是一个对象的时候,编译器就会自动调用这个方法。如果想让你写的类也具备这个功能,只要写一个toString()方法就行。

当primitive数据作为类的成员的时候,会被自动地初始化为零。而对象的reference则会被初始化为null。
编译器不为reference准备默认对象。如果想对reference进行初始化,可以在以下几个时间进行:
1. 在定义对象的时候。这就意味着在构造函数调用之前,它们已经初始化完毕了。 (对象定义在构造函数之前)
2. 在这个类的构造里
3. 在即将使用那个对象之前。这种做法通常被称为“偷懒初始化(lazy initialization)”。如果碰到创建对象的代价很高,或者不是每次都需要创建对象的时候,这种做法就能降低程序的开销了。
eg:

private WaterSource source;  //未调用构造函数
private WaterSource source = new WaterSource();  //调用构造函数

继承
继承设计通用准则:
把数据都设成private,把方法都设成public (protected?)。碰到特殊情况还要进行调整。

Java提供了一个当前类所继承的“基类(superclass)”的super关键词。当派生类中重定义了基类中的方法时,super.classname() 就会调用基类方法。
若构造函数是不带参数的,编译器能够生成默认的构造函数,再由它来调用基类的构造函数。但是如果基类的构造函数是带参数的,就必须用super关键词以及合适的参数明确地调用基类的构造函数。
对派生类的构造函数而言,调用基类的构造函数应该是它做的第一件事。

各个类在覆写基类的dispose()方法时,除了用super调用基类的dispose()之外,还要完成它自己的清理活动。
在清理方法中,如果子对象之间有依赖关系,那么还要留意其基类和成员对象的清理方法的调用顺序。这个顺序同C++的编译器要求的析构函数的执行顺序是一样的:先按照创建对象的相反顺序进行类的清理。(一般来说,这要求留着基类对象以供访问。)然后调用基类的清理方法。

main() 函数中:

try{
    …
}finally{
    …
}

try表示下面这段程序(由花括号限定)是一个需要给予特殊关注的受保护的区域(guarded region)。所谓的特殊关注就是,无论以何种方式退出try区块,都必须执行跟在这个受保护区域后面的finally子句。(对于异常处理来说,会有很多非正常退出try区块的情况。)

合成or继承
一般来说,合成用于新类要使用旧类的功能,而不是接口的场合。也就是说,把对象嵌进去,用它来实现新类的功能,但是用户看到的是新类的接口,而不是嵌进去的对象的接口。因此,需要在新类里嵌入private的旧类对象。
继承则是要对已有的类做一番改造,以此获得一个特殊版本。简而言之, 就会知道,用 vehicle(车辆)对象来合成一个car(轿车)是毫无意义的——car不包含vehicle,它本来就是 vehicle。继承要表达的是一种“是 (is-a)”关系,而合成表达要表达的是“有(has-a)”关系。

protected
最好的做法是,将数据成员设成private:你应该永远保留修改底层实现的权利。然后用protected权限的方法来控制继承类的访问权限。

合成or继承again
判断应该使用合成还是继承的时候,有一个最简单的办法,就是问一下你是不是会把新类上传(upcasting)给基类。如果你必须上传,那么继承就是必须的,如果不需要上传,那么就该看看是不是应该用继承了。

final关键词
总的来说,它的意思是“这样东西不允许改动”。
1. final数据
static强调只有这一个数据,final表示这是一个常量。通常约定被初始化为常量值的final static的primitive的名字全用大写,词与词之间用下划线分开。
当final不是指primitive,而是用于对象的reference的时候,final的意思是这个reference是常量。初始化的时候,一旦将reference连到了某个对象,那么它就再也不能指向别的对象了。但是这个对象本身是可以修改的。这种局限性也体现在数组上,因为它也是一个对象。

blank finals
Java能让你创建“空白的final数据(blank finals)”,也就是说把数据成员声明成 final 的,但却没给初始化的值。碰到这种情况,你必须先进行初始化,再使用空白的final数据成员,而且编译器会强制你这么做。

Final的参数
Java 允许你在参数表中声明参数是 final 的,这样参数变成final了。也就是说,你不能在方法里让参数 reference 指向另一个对象了。

2.final方法
使用 final 方法的目的有二。第一,为方法上“锁”,禁止派生类进行修改。这是出于设计考虑。当你希望某个方法的功能,能在继承过程中被保留下来,并且不被覆写,就可以使用这个方法。
第二个原因就是效率。如果方法是 final 的,那么编译器就会把调用转换成“内联的(inline)”。当编译器看到要调用final方法的时候,它就会(根据判断)舍弃普通的,“插入方法调用代码的”编译机制。
不过,最好还是把效率问题留给编译器和 JVM 去处理,而只把 final 用于要明确地禁止覆写的场合。

final和private
private方法都隐含有final的意思。由于你不能访问private的方法,因此你也不能覆写它。你可以给 private 方法加一个 final 修饰符,但是这样做什么意义也没有。
只有是基类接口里的东西才能被“覆写”。也就是说,对象可以被上传到基类,然后再调用同一个方法。如果方法是 private 的,那它就不属于基类的接口。它只能算是被类隐藏起来的,正好有着相同的名字的代码。如果你在派生类里创建了同名的 public 或 protected,或 package 权限的方法,那么它们同基类中可能同名的方法没有任何联系。你并没有覆写那个方法,你只是创建了一个新的方法。

3.final类
把整个类都定义成final的 (把final关键词放到类的定义部分的前面) 就等于在宣布,你不会去继承这个类,你也不允许别人去继承这个类。换言之,出于类的设计考虑,它再也不需要作修改了,或者从安全角度出发,你不希望它再生出子类。
由于final类禁止了继承,覆写方法已经不可能了,因此所有的方法都隐含地变成final了。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值