《Java编程思想》读书笔记01-初始化与清理
来源:互联网 发布:惠阳政府网络问政 编辑:程序博客网 时间:2024/05/23 13:25
开篇
最近在看Java编程思想,想把Java SE部分重新巩固一下。由于之前看过两遍遍《Java疯狂讲义》,但是看过以后很多东西就忘记了,所以想记录一下学习Java SE的过程与重点。初步计划每章会有一篇博客作为总结,因为前几章比较简单,所以从第五章开始记录笔记。
序言
1. 用构造器确保初始化
Java提供构造器,使类的设计者可以确保每个对象都被初始化。构造器命名有两个问题:
- 所取的任何名字都可能与类的某个成员的名字重复
- 调用构造器是编译器的责任,所以必须让编译器知道应该调用哪个方法。
解决办法:让构造器采用与类相同的名字。因此“每个方法的首字母小写”的编码风格不适用于构造器。从概念上将:“初始化”与“创建”是彼此分离的,然而在Java中,两者被捆绑在了一起,不能分离。构造器没有返回值。
2. 方法重载
所谓方法,就是给某个动作取名字,通过起名字,你可以引用所有的对象和方法。名字起到好有助于系统的理解和修改。但是有时候相同的动作需要传入不同的对象,如果为每一个方法都起一个名字,会很难维护。例如清洗()这个方法,如果穿进去的对象是衬衫,那么执行的操作就是清洗衬衫,如何传进去的对象是汽车,那么执行的操作就是清洗汽车。我们当然可以定义两个方法,清洗汽车()和清洗衬衫(),但是这会很难维护。因此Java提供了方法的重载,使得可以用同一个方法名字,根据传入参数的不同,执行不用的操作。
很显然,Java的构造器是强制方法重载的一个重要原因。因为类名决定构造器名,所以要用多种方式创建一个类的对象时,只能根据传入参数的不同来区分。为了让方法名相同而形参不同的构造器同时存在,就必须用到方法重载。
例:
class Tree { int height; Tree() { prt("Planting a seedling"); height = 0; } Tree(int i) { prt("Creating new Tree that is " + i + " feet tall"); height = i; } void info() { prt("Tree is " + height + " feet tall"); } void info(String s) { prt(s + ": Tree is " + height + " feet tall"); } static void prt(String s) { System.out.println(s); }}public class Overloading { public static void main(String[] args) { for (int i = 0; i < 5; i++) { Tree t = new Tree(i); t.info(); t.info("overloaded method"); } // Overloaded constructor: new Tree(); }}如上所示,对象tree有两个构造器,传入不同的参数,会生成不同的tree对象。构造器通过形参不同产生方法重载。2.1 区分方法重载
通过形参列表来区分重载的方法,每个方法都有独一无二的形参列表。注意:参数顺序的不同也可以区分两个不同的方法。例:public class OverloadingOrder { static void print(String s, int i) { System.out.println("String: " + s + ", int: " + i); } static void print(int i, String s) { System.out.println("int: " + i + ", String: " + s); } public static void main(String[] args) { print("String first", 11); print(99, "Int first"); }}上述代码中print方法的参数都为String与int,但参数顺序不同,所以为两个不同的方法。但请注意,尽量不要这样做,这会使代码难易维护。2.2 涉及基本类型的重载
基本类型能从“较小”的类型自动提升至“较大”的类型。如果传入的参数类型小于方法中声明的形式参数类型,实际数据类型就会被提升。char类型略有不同,如果无法找到恰好能接受char参数的方法,就会把char直接提升至int类型。然而如果方法接受较小的类型作为参数。如果传入较大类型的参数,就得通过窄化才能正常调用方法,否则编译器会报错。Java数据类型自动提升的顺序如下图所示:图1 Java数据类型自动提升顺序涉及基本类型重载的例子如下:public class Test { public static void main(String[] args) { // 字面量默认作为int处理 PrimitiveTypeOverload.primitive(5); // 输出结果:int byte b = 1; PrimitiveTypeOverload.primitive(b); // 输出结果:byte // char 在没有确切接收char类型的重载方法的时候,char类型作为int类型处理(65535) char c = 'c'; PrimitiveTypeOverload.primitive(c); // 输出结果:int long l = 5L; // 传入的参数类型大于声明类型, 需要窄化 PrimitiveTypeOverload.primitive((char) l); // 输出结果:int PrimitiveTypeOverload.primitive((short) l); // 输出结果:short PrimitiveTypeOverload.primitive((int) l); // 输出结果:int }}class PrimitiveTypeOverload { public static void primitive(int i) { System.out.println("int "); } public static void primitive(byte b) { System.out.println("byte"); } public static void primitive(short s) { System.out.println("short"); }}2.3 以返回值区分重载方法
有人会想当然认为,可以通过返回值区分方法。例如如下两个方法:void f() {}int f() {}如果用int x = f(),可以很明确的知道调用的是第二个方法。但如果我不关心方法的返回值,指是想要方法调用的效果,那么如下的例子就不能确定是调用的哪个方法:f();结论:根据返回值区分重载方法不可行!
3. 默认构造器
如果你写的类中没有构造器,系统会自动帮你创建一个没有参数的默认构造器。例:class Bird { int i;}public class DefaultConstructor { public static void main(String[] args) { Bird nc = new Bird(); // default! }}如果你已经定义了一个构造器(无论有无参数),系统都不在帮你自动创建默认构造器。例:class Bush { Bush(int i) { } Bush(double d) { }}new Bird(); //此时会报错,因为没有默认构造器。
4. this关键字
调用一个对象的方法时需要这个对象的名字,即引用。如a,b两个对象,他们都有方法peel()。调用时的代码分别是a.peel();b.peel();面向对象的语法编写代码就是发送消息给对象。编译器在此暗自把“所操作对象的引用”发送给了方法peel()。实际情况应该是这样的:Banana.peel(a,1);Banana.peel(b,2);但不能这样写,编译器无法通过。这说明,调用某个对象的方法一定需要该对象的名字,即引用。但如果要在一个方法的内部获取当前对象的引用时,这种方式就无法完成任务。Java提供了this关键字来代表“调用该方法的当前对象”的引用,注意this只能在方法内部使用。特别:如果在一个方法内部调用另一个方法,不必使用this,直接调用即可。只在必要时使用this,遵循一种一直而直观的编程峰哥能节省时间和金钱。4.1 在构造器中调用构造器
通常this指当前对象,代表一个当前对象的引用。但如果在this后添加了参数列表,将调用符合这个参数列表的构造器。注意:
- 构造器调用要放在最起始处,否则编译器会报错。
- this调用构造器不能调用两次,只能用一次。
- 非构造器不能用this调用构造器。
public class Flower { private int petalCount = 0; private String s = new String("null"); Flower(int petals) { petalCount = petals; System.out.println("Constructor w/ int arg only, petalCount= " + petalCount); } Flower(String ss) { System.out.println("Constructor w/ String arg only, s=" + ss); s = ss; } Flower(String s, int petals) { this(petals); // ! this(s); // 1.不能调用两次this this.s = s; // Another use of "this" System.out.println("String & int args"); } Flower() { this("hi", 47); System.out.println("default constructor (no args)"); } void print() { // ! this(11); 2.只能在构造器内使用this调用构造器 System.out.println("petalCount = " + petalCount + " s = " + s); } public static void main(String[] args) { Flower x = new Flower(); x.print(); }}4.2 static含义
static方法就是没有this的方法,在static方法的内部不能调用非静态方法,反过来却可以。因为可以使用类本身来调用static方法而无需创建类对象,如果static方法调用了非静态方法,而非静态方法需要依赖于对象的实例,可是此时对象还没有创建,因此就找不到该对象的非静态方法,会出错。当然,如果代码中出现了大量static方法,那一定需要重新考虑自己的设计。
5. 清理:终结处理和垃圾回收
- 对象可能不被垃圾回收。
- 垃圾回收不等于“析构”。
- 垃圾回收只与内存有关。
5.1 finalize()的用途
5.2 你必须实施清理
5.3 终结条件
public class Tank { boolean status=false;//false为空,true为满 Tank(boolean stat){ status=stat; } void empty(){ status=false; } protected void finalize(){ if(status) System.out.println("error"); } }public class Test { public static void main(String args[]){ Tank tk1=new Tank(true); tk1.empty(); //Tank tk2=new Tank(true); new Tank(true); //对象一创建就成为垃圾,因为没有引用指向它 System.gc(); //强制执行终结操作 } }输出为error。
本例终止的条件为:Tank()的status值为false,即tank为空。当Tank的status值为true时,会输出error。如果没有finalize()来验证终止条件,很难发现这种缺陷。gc()函数的作用是提醒虚拟机,程序员希望进行一次垃圾回收,但并不保证一定会执行垃圾回收。具体什么时候取决于虚拟机,不同虚拟机有不同对策。
5.4垃圾回收器如何工作
6. 成员初始化
boolean false
char '/uoooo'(null)
byte (byte)0
short (short)0
int 0
long 0L
float 0.0f
double 0.0d
6.1 指定初始化
class Measurement { boolean b = true; char c = 'x'; byte B = 47; short s = 0xff; int i = 999; long l = 1; float f = 3.14f; double d = 3.14159;}也可以以同样方法初始化非基本类型的对象。
class Measurement { Depth o = new Depth(); boolean b = true;}如果没有初始化d的值就是用它,会出现运行时错误。
7. 构造器初始化
class Counter { int i; Counter() { i = 7; }}i的值首先是0,然后变成7。对于所有的基本类型和对象引用,包括在定义时已经指定初始值的变量,都是如此。
7.1 初始化顺序
class Tag { Tag(int marker) { System.out.println("Tag(" + marker + ")"); }}class Card { Tag t1 = new Tag(1); // Before constructor Card() { // Indicate we're in the constructor: System.out.println("Card()"); t3 = new Tag(33); // Re-initialize t3 } Tag t2 = new Tag(2); // After constructor void f() { System.out.println("f()"); } Tag t3 = new Tag(3); // At end}public class OrderOfInitialization { public static void main(String[] args) { Card t = new Card(); t.f(); // Shows that construction is done }}其输出结果如下:
Tag(1)Tag(2)Tag(3)Card()Tag(33)f()可以看出,即使tag的定义散布于方法之间,仍然先于任何方法得到了初始化。
7.2 静态数据的初始化
无论创建多少个对象,静态数据都只占用一份存储区域。静态代码只执行一次。static关键字不能用于局部变量。静态初始化只在必要时进行,两个时刻:- 第一次new创建对象时。
- 第一次访问静态数据时。
class Bowl { Bowl(int marker) { System.out.println("Bowl(" + marker + ")"); } void f(int marker) { System.out.println("f(" + marker + ")"); }}class Table { static Bowl b1 = new Bowl(1); Table() { System.out.println("Table()"); b2.f(1); } void f2(int marker) { System.out.println("f2(" + marker + ")"); } static Bowl b2 = new Bowl(2);}class Cupboard { Bowl b3 = new Bowl(3); static Bowl b4 = new Bowl(4); Cupboard() { System.out.println("Cupboard()"); b4.f(2); } void f3(int marker) { System.out.println("f3(" + marker + ")"); } static Bowl b5 = new Bowl(5);}public class StaticInitialization { public static void main(String[] args) { System.out.println("Creating new Cupboard() in main"); new Cupboard(); System.out.println("Creating new Cupboard() in main"); new Cupboard(); t2.f2(1); t3.f3(1); } static Table t2 = new Table(); static Cupboard t3 = new Cupboard();}输出:
Bowl(1)Bowl(2)Table()f(1)Bowl(4)Bowl(5)Bowl(3)Cupboard()f(2)Creating new Cupboard() in mainBowl(3)Cupboard()f(2)Creating new Cupboard() in mainBowl(3)Cupboard()f(2)f2(1)f3(1)
7.3 显示的静态初始化
class Spoon { static int i; static { i = 47; }}
7.4 非静态实例初始化
8. 数组初始化
9. 枚举类型
- 《Java编程思想》读书笔记01-初始化与清理
- JAVA编程思想读书笔记5:初始化与清理
- java编程思想读书笔记 第五章 初始化与清理
- java编程思想读书笔记----第五章 初始化与清理
- java编程思想读书笔记五:初始化与清理
- Java编程思想读书笔记——初始化与清理(一)
- Java编程思想读书笔记——初始化与清理(二)
- 初始化与清理【java编程思想杂记】
- <Java编程思想> 初始化与清理
- 《JAVA编程思想》笔记-初始化与清理
- 【Java编程思想】(1)初始化与清理
- Java编程思想之清理与初始化
- Java编程思想之初始化与清理
- 5初始化与清理-Java编程思想
- java 编程思想--初始化与清理
- Java编程思想-05初始化与清理
- Java编程思想初始化与清理
- JAVA编程思想笔记--初始化与清理
- 角格点问题怎么批量发掘?
- 软件测试常见的面试题
- poj 2560 Freckles
- 大型网站架构演化
- LeetCode.75 Sort Colors
- 《Java编程思想》读书笔记01-初始化与清理
- 10月15日 字典树(Babelfish)
- Linux —— C语言编程入门
- 求一批整数中出现最多的数字。--C语言下
- maven入门
- 算法面试经常出现的问题——扑克牌中顺子和同花哪一个概率大?
- 数据库索引
- UVA
- Pro Spring 5, 5th Edition.pdf 英文原版免费下载