Thinking In Java 读书笔记
==========================
create by wythe 2016/2/15 21:49
在看TIJ之前,已经有了C/C++的一点基础。最近因为参加学校的软件编程比赛,做移动端的app,马马虎虎算是弄完了。在做得过程发现自己的java不熟悉(菜的一笔),所以闲时就看看这本经典,做些笔记
一 、 Introduction to Object
- 主数据类型(Primitive Type)
类型 | 大小 | 默认值 |
---|---|---|
byte | 8 bits | (byte)0 |
char | 16 bits | '\u0000'(null) |
boolean | 1 bit | false |
short | 16 bits | (short)0 |
int | 32 bits | 0 |
long | 64 bits | 0L |
float | 64 bits | 0.0f |
double | 64 bits | 0.0d |
若主数据类型属于一个类成员,则会以上述的默认值初始化。但是局部变量会得到随机值
99
二 、 Everything is Object
-
String str = new String("hello world")
str
为句柄Java通过句柄(str)来操作对象;
句柄(str)在它的作用域(Scope)终点自动销毁,然而句柄指向的对象还占据内存空间; - 内存
类型 | 作用 |
---|---|
寄存器(Registers) | 我们没有直接控制权,只能由编译器分配 |
堆栈(The stack) | 对象句柄的储存的地方 |
堆(The heap) | 对象的储存地方 |
- 注意点
如果您的main()用package语句封装到一个文件里,那么必须在程序名前面指定完整的包裹名称,否则不能运行程序。
三 、 Operator
- ==和!=运算符
关系运算符==和!=也适用于所有对象。下面是一个例子:
//:
Equivalence.java public class Equivalence {
public static void main(String[] args) {
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println(n1 == n2);
System.out.println(n1 != n2);
}
} ///:~
其中,表达式System.out.println(n1 == n2)
可打印出内部的布尔比较结果。一般人都会认为输出结果肯定先是true,再是false,因为两个Integer对象都是相同的。但尽管对象的内容相同,句柄却是不同的,而==和!=比较的正好就是对象句柄。所以输出结果实际上先是false,再是true。这自然会使第一次接触的人感到惊奇。 若想对比两个对象的实际内容是否相同,又该如何操作呢?此时,必须使用所有对象都适用的特殊方法equals()。但这个方法不适用于“主类型”,那些类型直接使用==和!=即可。由于equals()的默认行为是比较句柄。所以除非在自己的新类中改变了equals(),否则不可能表现出我们希望的行为
- 移位运算符
1、左移位运算符(<<)能将运算符左边的运算对象向左移动运算符右侧指定的位数
(在低位补0);
2、“有符号”右移位运算符(>>)则将运算符左边的运算对象向右移动运算符右侧指定
的位数。“有符号”右移位运算符使用了“符号扩展”:若值为正,则在高位插入0;若值为负,则在高位插入1;
3、Java也添加了一种“无符号”右移位运算符(>>>),它使用了“零扩展”:无论正负,都在高位插入0;
- 主数据类型(int、long etc.)的二进制为补码形式,用以下代码验证
//:Main.java
//Test for Learning Java
package com.company;
import java.util.*;
public class Main {
public static void main(String[] args) {
// write your code here
int i = -1;
printIntBinary(i);
printIntBinary(i>>3);
printIntBinary(i>>>3);
}
static void printIntBinary(int a){
for(int j = 31; j >= 0; --j) {
if((( 1 << j ) & a ) != 0)
System.out.print("1");
else
System.out.print("0");
}
System.out.println();
}
}
///:The end~
结果:
结果
- javadoc sample.class
通过代码的注释,自动生成api文档 教程
四 、 Initialization & Clean up
- 对象初始化
static变量在非static变量前初始化
示例:
class Man{
static int cnt;
String name;
//static区块用于初始化static变量
static{
cnt=1;
}
//非静态变量的初始化区块,支持"匿名内部类"的初始化
{
name = "Mike";
}
Man(){
cnt++;
}
}
- 数组初始化
1、主数据类型(int、char etc.):表达式
int[] a = new int[size]
产生长度为size
的int
数组,初始化值为默认值0
.
2、对象:表达式Interger[] a = new Interger[size]
产生一个句柄数组,具体的对象空间未分配。此时,数组元素的值为null
。通过a[i] = new Interger(2)
来关联对象.
- 多维数组
多维数组可以任意指定各维的大小
示例:
int [][][] a = new int[randInt()][][];
for(int i = 0; i < a.length; ++i){
a[i] = new int[randInt()][];
for(int j = 0; j < a[i].length; ++j){
a[i][j] = new int[randInt()];
for(int k = 0; k < a[i][j].length; ++k)
a[i][j][k] = i*j*k;
}
}
- finalize()方法
Java提供了一个名为finalize()的方法,我们可以在自己类中定义它。它的工作原理:当垃圾收集器准备好释放对象占用的储存空间,它会首先调用finalize(),而且只有在下一次垃圾收集过程中,才会真正回收对象内存。因此,可以用finalize()在垃圾收集期间进行一些重要的清除工作
示例:
//: initialization/TerminationCondition.java
// Using finalize() to detect an object that
// hasn’t been properly cleaned up.
class Book {
boolean checkedOut = false;
Book(boolean checkOut) {
checkedOut = checkOut;
}
void checkIn() {
checkedOut = false;
}
protected void finalize() {
if(checkedOut)
System.out.println("Error: checked out");
// Normally, you’ll also do this:
// super.finalize();
// Call the base-class version
}
}
public class TerminationCondition {
public static void main(String[] args) {
Book novel = new Book(true);
// Proper cleanup:
novel.checkIn();
// Drop the reference, forget to clean up:
new Book(true);
// Force garbage collection & finalization:
System.gc();
}
}
/* Output: Error: checked out *///:~
五 、Access Control
- 修饰符
1、
friendly
默认的访问修饰符,它不是显式的,不用特意来使用它。它指明可在包内访问,包外不可访问。
2、protected
在包内访问上与friendly
一致。但protected
可访问性比friendly
强。
可看以下图片,红色为语法错误
Package1
Package2
六 、Reusing Classes
- final关键字
1、自变量final:例如,
void sampleMethod(final sampleClass s)
中,无法改变自变量s
句柄的指向(对象);
2、空白final:例如,
class blankFinal{
final int i;
blankFinal(){
i = 1;
}
}
在对象初始化时,对final进行正确的赋值;
七、 Polymorphism
- 多形性实例
//:Main.java
//Test for Learning Java
package com.company;
import com.company.tools.*;
class Instrument{
public void play(){
CustomPrint.print("Instrument~");
}
}
class Wind extends Instrument{
public void play(){
CustomPrint.print("Wind~");
}
}
class Brass extends Instrument{
public void play(){
CustomPrint.print("Brass~");
}
}
class Brass2 extends Brass{
public void play(){
CustomPrint.print("Brass2~");
}
}
public class Main {
public static void tune(Instrument isn){
isn.play();
}
public static void main(String[] args) {
Brass brass = new Brass();
Brass2 brass2 = new Brass2();
tune(brass);
tune(brass2);
}
}
///:The end~
![结果](https://img.haomeiwen.com/i1623908/565bb364a569d2df.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
如果,
将上述的`play()`方法,加上static关键字`public static void play()`,则结果是:
![结果](https://img.haomeiwen.com/i1623908/76d9edf55c437f8d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 接口
>***1、接口介绍***
1)接口不规定方法主体;
2)接口可以声明**基本数据类型**的数据成员,它们都***默认***为static 和final;
3)与类相似,我们可在interface关键字的前面添加一个 public关键字(但只有接口定义于同名的一个文件内);或者将其省略,营造一种“friendly”状态;
4)接口中的方法声明默认为 public。所以在实现一个接口的时候,来自接口的方法***必须***定义成public。不然它们会默认为“friendly"
就像这样,
interface Instrument5 {
// Compile-time constant:
int i = 5; // static & final
// Cannot have method definitions:
void play(); // Automatically public
String what();
void adjust();
}
接口也具有多形性。下面这段代码的结果和`多形性实例`的结果一致:
//:Main.java
//Test for Learning Java
package com.company;
import com.company.tools.*;
interface Instrument{
void play();
}
class Wind implements Instrument {
public void play(){
CustomPrint.print("Wind~");
}
}
class Brass implements Instrument {
public void play(){
CustomPrint.print("Brass~");
}
}
class Brass2 extends Brass{
public void play(){
CustomPrint.print("Brass2~");
}
}
public class Main {
public static void tune(Instrument isn){
isn.play();
}
public static void main(String[] args) {
Brass brass = new Brass();
Brass2 brass2 = new Brass2();
tune(brass);
tune(brass2);
}
}
///:The end~
**2、接口实现“多重继承”**
>就像这样,`class samlpe implements interface1,interface2,interface3`。sample可以将类型上溯至interface1,interface2,interface3中的任意一种。下面是一个实例:
//: Adventure.java
// Multiple interfaces import java.util.*;
interface CanFight { void fight(); }
interface CanSwim { void swim(); }
interface CanFly { void fly(); }
class ActionCharacter { public void fight() {} }
class Hero extends ActionCharacter
implements CanFight, CanSwim, CanFly {
public void swim() {}
public void fly() {}
}
class Adventure {
static void t(CanFight x) {
x.fight();
}
static void u(CanSwim x) {
x.swim();
}
static void v(CanFly x) {
x.fly();
}
static void w(ActionCharacter x) {
x.fight();
}
public static void main(String[] args) {
Hero i = new Hero();
t(i); // Treat it as a CanFight
t(i); // Treat it as a CanSwim
v(i); // Treat it as a CanFly
w(i); // Treat it as an ActionCharacter
}
} ///:~
**3、接口能够继承接口**
>像这样`interface sample extends interface1,interface2,interface3`,形成更丰富的新接口
**4、接口产生枚举数组**
>就像这样,
public interface Months{
int
JANUARY = 1, FEBRUARY = 2, MARCH = 3,
APRIL = 4, MAY = 5, JUNE = 6, JULY = 7,
AUGUST = 8, SEPTEMBER = 9, OCTOBER = 10,
NOVEMBER = 11, DESEMBER = 12;
}
接口内的基本数据类型默认为***final*** **&** ***static***,可以***Months.JANUARY***的方式访问。
- 内部类
>**1、内部类,一个被定义在现有类内部的新类。**
像这样,
public class Parcel1 {
class Contents {
private int i = 11;
public int value() { return i; }
}
class Destination {
private String label;
Destination(String whereTo) {
label = whereTo;
}
String readLabel() { return label; }
}
public Contents cont(){
return new Contens();
}
public Destination to(){
return new Destination();
}
// Using inner classes looks just like
// using any other class, within Parcel1:
public void ship(String dest) {
Contents c = new Contents();
Destination d = new Destination(dest);
}
public void ship2(String dest){
Contents c = cont();
Destination d = to(dest);
}
public static void main(String[] args) {
Parcel1 p = new Parcel1();
p.ship("Tanzania");
Parcel.Contents c = p.cont();
}
}
**2、可在方法或者if语句等的作用域内内嵌一个内部类,但是这个内部类仅限在这个作用域内使用**
**3、匿名类,方法尾部return一个内部类**
像这样,
public Content cont(){
return new Content(){
private int i = 0;
public int value(){return i;};
}
}
new 表达式返回的句柄会自动上溯到Content,由此,可以重写Content的方法来隐藏实现细节1-·
**4、当一个新类继承一个外部类时,外部类内嵌的内部类不会被自动继承。因此,无法再新类中简单地覆盖内部类**
实例:
//: BigEgg.java
// An inner class cannot be overriden
// like a method
class Egg {
protected class Yolk {
public Yolk() {
System.out.println("Egg.Yolk()");
}
}
private Yolk y;
public Egg() {
System.out.println("New Egg()");
y = new Yolk();
}
}
public class BigEgg extends Egg {
public class Yolk {
public Yolk() {
System.out.println("BigEgg.Yolk()");
}
}
public static void main(String[] args) {
new BigEgg();
}
} ///:~
输出:New Egg( )
Egg.Yolk( )
**5、可以用“外部类.内部类”的方式来继承内部类,并可用这种方法来覆盖父类内部类的方法**
下面是例子:
//: BigEgg2.java
// Proper inheritance of an inner class
class Egg2 {
protected class Yolk {
public Yolk() {
System.out.println("Egg2.Yolk()");
}
public void f() {
System.out.println("Egg2.Yolk.f()");
}
}
private Yolk y = new Yolk();
public Egg2() {
System.out.println("New Egg2()");
}
public void insertYolk(Yolk yy) { y = yy; }
public void g() { y.f(); }
}
public class BigEgg2 extends Egg2 {
public class Yolk extends Egg2.Yolk {
public Yolk() {
System.out.println("BigEgg2.Yolk()");
}
public void f() {
System.out.println("BigEgg2.Yolk.f()");
}
}
public BigEgg2() { insertYolk(new Yolk()); }
public static void main(String[] args) {
Egg2 e2 = new BigEgg2();
e2.g();
}
} ///:~
输出: Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk.f()
#####八、Honding Your Objects
- continue配合标签使用,可以连跳多级循环
>```
retry:
while(true){
int t=
(int)(Math.random()*flav.length);
for(int j=0;j<i;j++)
if(picks[j]==t)continue retry;
}
- 命令行下编译运行sample.java
//cd 到com文件夹的上一级(如果是在IED(IJ)中生成的)
javac sample.java
//文件不含包名
java sample
//如果文件包含“package com.package”,则
java com.package.sample
还需要注意,“CLASSPATH=.;%JAVA_HOME%/lib/dt.jar;%JAVA_HOME%/lib/tools.jar”。其中,".;"表示当前路径
九、Strings
- StringBuilder
- 正则表达式
String mp = "\w+@(\w+\.)+[A-Za-z]{2,14}";
String mail = "vicent@fzu.edu.cn";
Pattern p = Pattern.compile(mp);
Matcher m = p.matcher(mail);