這是一個經過對《Java編程思想》(Think in java)第四版進行閱讀同時對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
基本數據類型在沒有初始化的時候會得到一個默認值。ide
基本數據類型 | 默認值 | 大小 |
---|---|---|
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
p45
在自定義的對象中使用equals方法時須要覆蓋此方法,不然默認是比較引用。ui
p47
其現象本質爲:當已經肯定一個邏輯表達式的結果時不會再計算剩餘的部分。this
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,因此後面部分不會被調用。code
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關鍵詞,在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});
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
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)調用導出類(本體)的構造器主體。