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

Java編程思想

這是一個經過對《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是什麼。其具體的內容都會在後面介紹。編程

面向基本語言的五大特性

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

第二章(一切都是對象)

1、存儲

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

2、基本類型

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

第三章(操做符)

1、別名現象

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

2、equals方法

p45
在自定義的對象中使用equals方法時須要覆蓋此方法,不然默認是比較引用ui

3、短路

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

4、e

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

5、位操做

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
*/

6、截尾

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

第四章(控制執行流程)

1、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*/

第五章(初始化與清理)

1、重載

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

2、垃圾回收機制

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

3、初始化順序

p94
全部的變量都會在任何方法(包括構造器)被調用以前獲得初始化。
p95
不管建立多少對象,靜態數據都只佔用一份存儲區域,static不能做用於局部變量。且靜態初始化動做只執行一次。

4、可變參數列表。

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

第七章(複用類)

1、toString()的自動調用

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

2、構造函數調用順序

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

3、final

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

4、組合模式

組合模式能夠看作是一顆樹,每一個枝幹均可以長出新的枝幹,它們的結構都是相同的。
將枝幹抽象爲一個類,裏面包含連接下一個節點的方法,若須要不斷的連接下一個節點只須要繼承這個方法並實現。
示例:導航菜單
組合模式,將對象組合成樹形結構以表示「部分-總體」的層次結構,組合模式使得用戶對單個對象和組合對象的使用具備一致性。

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組成了一個導航列表,這就是一個簡單的組合模式.
 */

第八章(多態)

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

1、多態缺陷

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() */

2、斷言

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

3、構造器構造順序

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()

3、構造器初始化

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

相關文章
相關標籤/搜索