《Java編程思想》閱讀筆記一


Java編程思想

這是一個通過對《Java編程思想》(Think in java)第四版進行閱讀同時對java內容查漏補缺的系列。一些基礎的知識不會被羅列出來,這里只會列出一些程序員經常會忽略或者混淆的知識點。

所列知識點全部都是針對自己個人而言,同時也歡迎大家進行補充。


第一章(對象導論)

public class HelloWorld {
    public static void main(String[] args) {
		System.out.println("Hello every one,I'm cpacm");
	}
}

這一章是java的整體介紹,讓我們先熟悉了java是什么。其具體的內容都會在后面介紹。

面向基本語言的五大特性

  • 萬物皆為對象。
  • 程序是對象的集合,它們通過發送消息來告知彼此所要做的。
  • 每個對象都擁有其類型。
  • 某一特定類型的所有對象都可以接收同樣的消息。

第二章(一切都是對象)

一、存儲

p22
棧(堆棧):存放基本類型變量和對象引用變量。位於RAM區
堆:存放new得到的對象和數組。也位於RAM區
常量存儲:存放常量,包括靜態變量。

二、基本類型

p26
基本數據類型在沒有初始化的時候會獲得一個默認值。

基本數據類型 默認值 大小
boolean false 未確定
char null 16bits
byte 0 8bits
short 0 16bits
int 0 32bits
float 0f 32bits
long 0L 64bits
double 0d 64bits

tip1:String不是基本數據類型
tip2:上面的初始默認值並不適用於方法內部變量。其默認初始化值未知。當使用未初始化的變量編譯器會返回錯誤

public class BaseType {
	static boolean b;
	static char c;
	static byte bt;
	static short s;
	static int i;
	static float f;
	static long l;
	static double d;
	
	public static void main(String[] args) {
		System.out.println("類變量——"+"boolean:"+b+" char:"+c+" byte:"+bt+" short:"+s+" int:"+i+" float:"+f+" long:"+l+" double:"+d);
	}
	
}
//類變量——boolean:false char:  byte:0 short:0 int:0 float:0.0 long:0 double:0.0

第三章(操作符)

一、別名現象

p40
當兩個變量包含的是同一個引用時,修改其中一個變量的值另一個變量的值也同時改變。記住new出來的對象的=賦值都是只傳遞引用。
Tip:減少為對象賦值。

class T{
	int i;
}

public class Assigment {

	public static void main(String[] args) {
		T t1 = new T();
		T t2 = new T();
		t1.i = 5;
		t2.i = 8;
		t1 = t2;
		t1.i = 10000;
		System.out.println(t2.i);
	}

}
//10000

二、equals方法

p45
在自定義的對象中使用equals方法時需要覆蓋此方法,否則默認是比較引用

三、短路

p47
其現象本質為:當已經確定一個邏輯表達式的結果時不會再計算剩余的部分。

public class ShortCircuit {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		boolean flag1 = test1()&&test2()||test3()&&test4();
		System.out.println("\n");
		boolean flag2 = test1()&&test3()||test2()&&test4();
	}
	
	static boolean test1(){
		System.out.println("test1");
		return true;
	}
	static boolean test2(){
		System.out.println("test2");
		return false;
	}
	static boolean test3(){
		System.out.println("test3");
		return true;
	}
	static boolean test4(){
		System.out.println("test4");
		return false;
	}

}
/*
test1
test2
test3
test4

test1
test3
*/

boolean flag2 = test1()&&test3()||test2()&&test4();
若test1為true,test3為true時,因為前面這部分已經確定為true,所以后面部分不會被調用。

四、e

p49
科學與工程領域中,"e"代表自然對數的基數,為2.718。
而在C,C++和java(或者更多的語言)中,"e"代表“10的冪次”
$1.39e-43f = 1.39*10^{-43}$

五、位操作

p49
與,或,異或,非 &,|,^,~
與:所有的位都為1則輸出1,否則輸出0;
或:只要有一個位是1就輸出1;
異或:兩個位值相等時輸出1;
非:1輸出0,0輸出1.
位運算不會出現短路現象。
p50
移位操作符:
$<<$:操作數向左移動,低位補0;
$>>$:操作數向右移動,(1)符號為正時,高位補0,(2)符號為負時,高位補1;
$>>>$:java獨有操作符,操作數向右移動,高位統一補0。
char,byte,short進行移位操作時先會轉成int類型,即32位

public class URShift {

	public static void main(String[] args) {
		int i = 1024;
		System.out.println(Integer.toBinaryString(i));
		i >>= 10;
		System.out.println(Integer.toBinaryString(i));
		i = -1;
		System.out.println(Integer.toBinaryString(i));
		i >>>= 10;
		System.out.println(Integer.toBinaryString(i));
		i <<= 1;
		System.out.println(Integer.toBinaryString(i));
		short s = -1;
		s >>>= 10;//s移位后得到的結果在賦值時會強行轉為int,所以移位后的s已經是int型
		System.out.println(Integer.toBinaryString(s));
		s = -1;
		System.out.println(Integer.toBinaryString(s>>>10));
	}

}
/*
10000000000
1
11111111111111111111111111111111
1111111111111111111111
11111111111111111111110
11111111111111111111111111111111
1111111111111111111111
*/

六、截尾

p55
將float或double轉型為整數值時,總是對數字進行截尾,不會進行四舍五入。如果想要得到舍入的結果可以使用Math.round()

public class CastingNumbers {
	
	public static void main(String[] args) {
		double d = 1.7d;
		int i = (int)d;
		System.out.println(i);
		i = (int) Math.round(d);
		System.out.println(i);
	}
}
//1
//2

第四章(控制執行流程)

一、goto 標簽

goto關鍵詞,在java中則是使用標簽代替臭名昭著的goto。其實在java中也是最好不要用標簽來跳轉語句,太傷智商。。
寫法
outer:
並放在迭代語句前。
(1)continue 標簽
跳出所有循環,並到標簽位置的語句,但會重新進入緊接后面的循環里。
(2)break 標簽
跳出所有循環,且不再進入緊接后面的循環里。

public class LabeledFor {

	public static void main(String[] args) {
		System.out.println("測試continue————————————");
		label:
		for(int i=0;i<3;i++){
			System.out.println("外部for循環"+i);
			for(int j=0;j<3;j++){
				if(j==1){
					continue label;
				}
				System.out.println("內部循環"+j);
			}
		}
		System.out.println("測試break————————————————");
	    label2:
		for(int m=0;m<3;m++){
			System.out.println("外部for循環"+m);
			for(int n=0;n<3;n++){
				if(n==1){
					break label2;
				}
				System.out.println("內部循環"+n);
			}
		}
	}

}
/*
 測試continue————————————
外部for循環0
內部循環0
外部for循環1
內部循環0
外部for循環2
內部循環0
測試break————————————————
外部for循環0
內部循環0*/

第五章(初始化與清理)

一、重載

p81
重載主要以傳入參數及順序來區別。不能通過返回值來區別
以基本數據類型傳入時:自動包裝機制
(1)若傳入的數據類型小於方法中聲明的形式參數類型,實際數據類型就會提升。
byte->short->int->long->float->double
(2)如果傳入的實際參數較大,就得通過類型轉換執行窄化轉換。

二、垃圾回收機制

p91
標記-清掃(Android中使用這個技術)
從堆棧和存儲區出發,遍歷所有的引用,進而找出所有存活的對象,並給與標記。遍歷完成后,清理所有未被標記的對象。
停止-復制
先暫停程序的運行,然后將所有存活的對象復制到另一個堆,而沒有復制的是可回收的內存。

三、初始化順序

p94
所有的變量都會在任何方法(包括構造器)被調用之前得到初始化。
p95
無論創建多少對象,靜態數據都只占用一份存儲區域,static不能作用於局部變量。且靜態初始化動作只執行一次。

四、可變參數列表。

p102
void method(Object... args){}
調用 method();或method(new Object[]{1,2,3,4});

第七章(復用類)

一、toString()的自動調用

p126
有時候編譯器會自動幫你調用toString()方法。
"source"+ source;這時候會自動調用source對象的toString方法。

二、構造函數調用順序

p130
構造函數總是從基類開始。

class Insert{
	Insert(){
		System.out.println("Insert");
	}
	
}

public class Beetle extends Insert{
	
	Beetle(){
		System.out.println("Beetle");
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Beetle b = new Beetle();
	}

}
//Insert
//Beetle

三、final

p140
對於基本類型,final使數值恆定不變;而用於對象引用,final使引用恆定不變,但對象本身是可以改變的。
private 屬於 final 方法
static final是屬於類屬性,即能被類調用,不用實例化
final則需要實例化。

四、組合模式

組合模式可以看做是一顆樹,每個枝干都可以長出新的枝干,它們的結構都是相同的。
將枝干抽象為一個類,里面包含鏈接下一個節點的方法,若需要不斷的鏈接下一個節點只需要繼承這個方法並實現。
示例:導航菜單
組合模式,將對象組合成樹形結構以表示“部分-整體”的層次結構,組合模式使得用戶對單個對象和組合對象的使用具有一致性。

public abstract class Tab {
	private String title;

	public Tab(String title) {
		this.title = title;
	}
	
	protected abstract void add(Tab tab);  
	  
    protected abstract void romove(Tab tab);  
}

public class CardTab extends Tab{
	
	public CardTab(String title) {
		super(title);
		// TODO Auto-generated constructor stub
	}

	private List<Tab> tabs;

	@Override
	protected void add(Tab tab) {
		// TODO Auto-generated method stub
		tabs.add(tab);
	}

	@Override
	protected void romove(Tab tab) {
		// TODO Auto-generated method stub
		tabs.remove(tab);
	}

}

public class TabView {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		CardTab rootTab = new CardTab("roottab");
		CardTab tab1 = new CardTab("tab1");
		CardTab tab2 = new CardTab("tab2");
		CardTab tab3 = new CardTab("tab3");
		rootTab.add(tab1);
		rootTab.add(tab2);
		rootTab.add(tab3);
		CardTab tab4 = new CardTab("tab1-1");
		CardTab tab5 = new CardTab("tab1-2");
		tab1.add(tab4);
		tab1.add(tab5);
	}
}

/**
 * 這樣子Tab組成了一個導航列表,這就是一個簡單的組合模式.
 */

第八章(多態)

多態是一項讓程序員“將改變的事物與未變的事物分離開來”的重要技術。

一、多態缺陷

p156
缺陷1:只有非private方法才可以被覆蓋

class Super{
    public int field = 0;
    public int getField(){return field;};
}

class Sub extends Super {
      public int field = 1;
      public int getField() { return field; }
      public int getSuperField() { return super.field; }
    }

public class FiledAccess {
      public static void main(String[] args) {
        Super sup = new Sub(); // Upcast
        System.out.println("sup.field = " + sup.field +
          ", sup.getField() = " + sup.getField());
        Sub sub = new Sub();
        System.out.println("sub.field = " +
          sub.field + ", sub.getField() = " +
          sub.getField() +
          ", sub.getSuperField() = " +
          sub.getSuperField());
      }
} 

輸出:
sup.field = 0, sup.getField() = 1
sub.field = 1, sub.getField() = 1, sub.getSuperField() = 0

缺陷2:域和靜態方法直接在編譯時候進行解析,所以多態不會對其產生作用。

class StaticSuper {
  public static String staticGet() {
    return "Base staticGet()";
  }
  public String dynamicGet() {
    return "Base dynamicGet()";
  }
}

class StaticSub extends StaticSuper {
  public static String staticGet() {
    return "Derived staticGet()";
  }
  public String dynamicGet() {
    return "Derived dynamicGet()";
  }
}

public class StaticPolymorphism {
  public static void main(String[] args) {
    StaticSuper sup = new StaticSub(); // Upcast
    System.out.println(sup.staticGet());
    System.out.println(sup.dynamicGet());
  }
} /* Output:
Base staticGet()
Derived dynamicGet() */

二、斷言

p153
@Override作用:
斷言,如果我們使用了這種annotation在一個沒有覆蓋父類方法的方法時,java編譯器將以一個編譯錯誤來警示

三、構造器構造順序

p158
構造器在多態時的構造順序:

class Meal {
    Meal() {
        P.print("Meal()");
    }
}

class Bread {
    Bread() {
        P.print("Bread()");
    }
}

class Cheese {
    Cheese() {
        P.print("Cheese()");
    }
}

class Lettuce {
    Lettuce() {
        P.print("Lettuce()");
    }
}

class Lunch extends Meal {
    Lunch() {
        P.print("Lunch()");
    }
}

class PortableLunch extends Lunch {
    PortableLunch() {
        P.print("PortableLunch()");
    }
}

public class Sandwich extends PortableLunch {
    private Bread b = new Bread();
    private Cheese c = new Cheese();
    private Lettuce l = new Lettuce();

    public Sandwich() {
        P.print("Sandwich()");
    }

    public static void main(String[] args) {
        new Sandwich();
    }

}

class P {
    public static void print(String s){
        System.out.println(s);
    }
}
輸出:
Meal()
Lunch()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()

解釋說明:
一個繼承類實例化的時候必須要確保所使用的成員已經構建完畢,所以必須先調用基類的構造器,所以當實例化Sandwich對象時先調用其基類的構造方法:
Meal()
Lunch()
PortableLunch()
其次對成員變量進行初始化
Bread()
Cheese()
Lettuce()
最后調用構造器
Sandwich()

三、構造器初始化

p163
初始化的過程:
(1)在所有事物發生之前,將分配給對象的存儲空間初始化為二進制的零。
(2)調用基類構造器。
(3)按照聲明順序調用成員的初始化方法。
(4)調用導出類(本體)的構造器主體。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM