1. 程式人生 > >【Java程式設計思想】讀書筆記(一)第一章---第五章

【Java程式設計思想】讀書筆記(一)第一章---第五章

Java程式設計思想(第四版)學習筆記 第一章---第五章


趁著現在晚上還有點自己的時間,將被遺忘在角落裡的這本經典書籍拿出來學習一下,使用部落格來記錄下來自己容易忽略的知識點,以便日後提醒自己一下。

第一章:物件導論

1.1抽象過程

類:類描述了具有相同特(資料元素)和行為(功能)的物件集合。所以一個類實際上就是一個數據型別,例如浮點型數字具有形同的特性和行為集合。

1. 2訪問控制

三個關鍵字: publicprivateprotected
這些訪問控制指定詞,決定了緊跟在其後被定義的東西可以被誰使用。

public : 表示緊隨其後的元素對任何人都是可用的。

private :表示出了型別建立者和型別的內部方法之外的任何人都不能訪問的元素 。private就像你與客戶端程式設計師之間的一堵磚牆,如果有人檢視訪問private成員,就是在編譯時得到錯誤的資訊。

protected : 與private作用相當,差別僅在於繼承的類可以訪問protected成員,但是不能訪問private成員。

還有一種預設的訪問許可權,當沒有使用前面提到的任何訪問指定詞時,它將發揮作用。這種許可權通常被稱為包訪問許可權,因為在這種許可權下,類可以訪問在同一個包(庫構件)中的其他類的成員,但是在包之外,這些成員如同制定了private一樣。

訪問控制的存在原因:
第一:讓客戶端程式設計師無法觸及他們不應該觸及的部分,這些部分對資料型別的內部操作來說是必須的,但是並不是使用者解決待定問題所需的介面的一部分。
第二:允許庫設計者可以改變類內部的工作方式而不用擔心會影響到客戶端程式設計師。

第二章:一切都是物件

2. 1用引用操縱物件

儘管一切都看作物件,但操縱的識別符號實際上是物件的一個“引用”(reference)。

可以將這一情形想象成用遙控器(引用)來操縱電視機(物件)。只要握住遙控器,就能保持與電視機的連線。當有人想改變頻道或者減小音量時,實際操控的是遙控器(引用),再由遙控器來調控電視機(物件)。如果想在房間裡四處走走,同時仍能調控電視機,那麼只需要攜帶遙控器(引用),而不是電視機(物件)。

此外,即使沒有電視機,遙控器亦可以獨立存在。也就是說,你擁有一個引用,並不一定需要有一個物件與它關關聯。

因此,如果想操縱一個詞或者局子,則可以建立一個String引用: String s;
這裡建立的只是引用,而不是物件。如果此時向s傳送一個訊息,就會返回一個執行時錯誤。這是因為此時實際上s沒有與任何事物相關聯(即,沒有電視機)。

因此一種安全的做法是:建立一個引用的同時便進行初始化。String s = "asdf";

一旦建立了一個引用,就希望它能與一個新的物件相關聯。通常使用new操作符來實現這一目的。

new關鍵字的意思是“給我一個新物件”,所以上面的例子可以寫成:String s = new String("asdf");

2. 2基本型別

其中基本型別有九種,基本資料型別有八種,另外一種基本型別是void。

基本型別 大小 最小值 最大值 包裝型別
boolean - - - Boolean
char 16-bit Unicode 0 Unicode 2^16-1 Character
byte 8 bit -128 +127 Byte
short 16 bit -2^15 +2^15-1 Short
int 32 bit -2^31 +2^31-1 Integer
long 64 bit -2^63 +2^63-1 Long
float 32 bit IEEE 754 IEEE754 Float
double 64 bit IEE754 IEE754 Double
void - - - Void
注:IEEE754表示浮點數。所有的數值型別都有正負號,不要去去尋找無符號的數值型別。

Boolean型別所佔儲存空間大小沒有明確的規定,僅定義為能夠取字面值true或false。

高精度數字:BigInteger和BigDecimal,沒有對應的基本型別。
BigInteger:支援任意精度的整數。也就是說可以準確地表示任何大小的整數值,不會丟失任何資訊。
BigDecimal:支援任何精度的定點數,例如可以進行精確的貨幣計算。

第三章:操作符

3.7.1測試物件的等價性

關係操作符生成的是一個Boolean型別的結果,其中==和!=也同大於小於等符號一樣,適用於所有的物件。
但是對於第一次接觸Java的程式設計師來說這裡有一點會感到迷惑的地方。下面是一個例子:

public class Test {
	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);
	}
}
/* Output:  false
			true*///:~ 

語句System.out.println(n1 == n2);將打印出括號內的比價的布林值的結果。讀者可能認為輸出的結果肯定先是true再是false,因為兩個Integer物件都是相同的。但是儘管物件的內容是相同的,然而物件的引用確是不相同的,而==和!= 比較的就是物件的引用。所以輸出結果實際上先是false再是true。

如果想比較兩個物件的實際內容是否相同,此時必須使用所有物件都使用的特殊的方法equals()。但是這個方法不適用於基本型別,因為基本型別直接使用==和!=即可。

public class EqualsMethod {
	public static void main(String[] args) {
		Integer n1 = new Integer(47);
		Integer n2 = new Integer(47);
		System.out.println(n1.equals(n2));
	}
}
/* Output:  true*///:~ 

結果正如我們預料的那樣,但事情並不總是那麼簡單,假設你建立了自己的類,就像下面這樣:

class Value{
	int i;
}

public class EqualsMethod2 {
	public static void main(String[] args) {
		Value v1 = new Value();
		Value v2 = new Value();
		v1.i = v2.i = 100;
		System.out.println(v1.equals(v2));
	}
}
/* Output:  false*/

事情再次令人費解了:結果又是false!這是由於equals()的預設行為是比較引用。所以除非在自己的新類中覆蓋equals()方法,否則不可能表現出我們希望的行為。

第四章:控制執行流程

4.1 switch

switch語句是實現多路選擇(也就是說從一系列執行路徑中挑選一個)的一種乾淨利落的方法。但它要求使用一個選擇因子,並且必須是int或char那樣的整數值。例如,假若將一個字串或者浮點數作為選擇因子使用,那麼它們在switch語句裡是不會工作的。對於非整數型別則必須使用一系列if語句。另外在case語句中,使用單引號引起的字元也會產生用於比較的的整數值

        Random rand = new Random(47);
        // 產生一個0-26之間的一個值,然後加上一個偏移量‘a',即可隨機產生小寫字元
        int c = rand.nextInt(26) + 'a';
        switch (c){
            case 'a' :
                System.out.println("a"); break;
            case 'e':
                System.out.println("e"); break;
            default:
                    System.out.println("default"); break;
        }

在上面的定義中,大家會注意到每個case均以一個break結尾,這樣可是執行流程跳轉至switch主體的末尾。這是構建一種傳統的switch語句,但break是可選的。若省略break會繼續執行後面的case語句,直到遇到一個break為止。

第五章:初始化與清理

5.2方法過載

  1. 過載:簡單說,就是函式或者方法有相同的名稱,但是引數列表不相同的情形,這樣的同名不同引數的函式或者方法之間,互相稱之為過載函式或者方法。(過載
  2. 區分過載方法:每個過載的方法都必須有一個獨一無二的引數型別列表。甚至引數順序的不同也足以區分兩個方法(一般不這麼用,會使程式碼難以維護)。
  3. 設計基本型別的過載:基本型別能從一個較小的型別自動提升至一個較大的型別,此過程涉及到過載可能會造成混淆。
package chart5;

public class PrimitiveOverloading {
    // boolean can't be automatically converted
    static void prt(String s) {
        System.out.println(s);
    }

    void f1(char x) {         prt("f1(char)");     }
    void f1(byte x) {         prt("f1(byte)");    }
    void f1(short x) {        prt("f1(short)");    }
    void f1(int x) {        prt("f1(int)");    }
    void f1(long x) {        prt("f1(long)");    }
    void f1(float x) {        prt("f1(float)");    }
    void f1(double x) {        prt("f1(double)");    }

    void f2(byte x) {        prt("f2(byte)");    }
    void f2(short x) {        prt("f2(short)");    }
    void f2(int x) {        prt("f2(int)");    }
    void f2(long x) {        prt("f2(long)");    }
    void f2(float x) {         prt("f2(float)");    }
    void f2(double x) {        prt("f2(double)");    }

    void f3(short x) {        prt("f3(short)");    }
    void f3(int x) {        prt("f3(int)");    }
    void f3(long x) {        prt("f3(long)");    }
    void f3(float x) {        prt("f3(float)");    }
    void f3(double x) {        prt("f3(double)");    }
    void f4(int x) {        prt("f4(int)");    }
    void f4(long x) {        prt("f4(long)");    }
    void f4(float x) {        prt("f4(float)");    }
    void f4(double x) {        prt("f4(double)");    }

    void f5(long x) {        prt("f5(long)");    }
    void f5(float x) {        prt("f5(float)");    }
    void f5(double x) {        prt("f5(double)");    }

    void f6(float x) {        prt("f6(float)");    }
    void f6(double x) {        prt("f6(double)");    }

    void f7(double x) {        prt("f7(double)");    }

    void testConstVal() {
        prt("Testing with 5");
        f1(5);  f2(5);  f3(5);  f4(5);  f5(5);  f6(5);  f7(5);
    }

    void testChar() {
        char x = 'x';
        prt("char argument:");
        f1(x);  f2(x);  f3(x);  f4(x);  f5(x);  f6(x);  f7(x);
    }

    void testByte() {
        byte x = 0;
        prt("byte argument:");
        f1(x);  f2(x);  f3(x);  f4(x);  f5(x);  f6(x);  f7(x);
    }

    void testShort() {
        short x = 0;
        prt("short argument:");
        f1(x);  f2(x);  f3(x);  f4(x);  f5(x);  f6(x);  f7(x);
    }

    void testInt() {
        int x = 0;
        prt("int argument:");
        f1(x);  f2(x);  f3(x);  f4(x);  f5(x);  f6(x);  f7(x);
    }

    void testLong() {
        long x = 0;
        prt("long argument:");
        f1(x);  f2(x);  f3(x);  f4(x);  f5(x);  f6(x);  f7(x);
    }

    void testFloat() {
        float x = 0;
        prt("float argument:");
        f1(x);  f2(x);  f3(x);  f4(x);  f5(x);  f6(x);  f7(x);
    }

    void testDouble() {
        double x = 0;
        prt("double argument:");
        f1(x);  f2(x);  f3(x);  f4(x);  f5(x);  f6(x);  f7(x);
    }

    public static void main(String[] args) {
        PrimitiveOverloading p = new PrimitiveOverloading();
        p.testConstVal();
        p.testChar();
        p.testByte();
        p.testShort();
        p.testInt();
        p.testLong();
        p.testFloat();
        p.testDouble();
    }
}
/*
Testing with 5
f1(int) f2(int)	f3(int)	f4(int)	f5(long)	f6(float)	f7(double)

char argument:
f1(char)	f2(int)	f3(int)	f4(int)	f5(long)	f6(float)	f7(double)

byte argument:
f1(byte)	f2(byte)	f3(short)	f4(int)	f5(long)	f6(float)	f7(double)

short argument:
f1(short)	f2(short)	f3(short)	f4(int)	f5(long)	f6(float)	f7(double)

int argument:
f1(int)	f2(int)	f3(int)	f4(int)	f5(long)	f6(float)	f7(double)	

long argument:
f1(long)	f2(long)	f3(long)	f4(long)	f5(long)	f6(float)	f7(double)

float argument:
f1(float)	f2(float)	f3(float)	f4(float)	f5(float)	f6(float)	f7(double)

double argument:
f1(double)	f2(double)	f3(double)	f4(double)	f5(double)	f6(double)	f7(double)
*/

可以看到常數值5被當做int值處理,所以如果有某個過載方法接受int型引數,它就會被呼叫。如果傳入的引數型別(實際引數型別)小於方法中宣告的形式引數型別,實際資料型別就會被提升。char型別略有不同,如果無法找到恰好接受char引數的方法,就會把char直接提升至int型。
如果傳入的實際引數大於過載方法宣告的形式引數,就得通過實際型別轉換類執行窄化轉換,否則編譯器會報錯。

根據方法的返回值來區分過載方法是行不通的。

5.4 this關鍵字

  1. this關鍵字
    只能在方法內部使用,表示“呼叫方法的那個物件”的引用。this的用法和其他物件引用並無不同。需要注意如果在方法內部呼叫同一個類的另一個方法,就不必使用this,直接呼叫即可。當前方法中的this引用會自動應用於同一類中的其他方法。只能在方法內部使用,表示“呼叫方法的那個物件”的引用。this的用法和其他物件引用並無不同。需要注意如果在方法內部呼叫同一個類的另一個方法,就不必使用this,直接呼叫即可。當前方法中的this引用會自動應用於同一類中的其他方法。
public class Apricot(){
    void pick(){/*    */   }
    void pit(){pick(); /*  */}
}
  1. 在構造器中呼叫構造器
    可以用this在一個構造器中呼叫另一個構造器,但是隻能呼叫一個。必須將構造器呼叫置於最起始處,否則編譯器會報錯。
  2. static的含義
    static(靜態)方法就是沒有this的方法。在static方法的內部不能呼叫非靜態方法,反過來倒是可以。而且可以在沒有建立任何物件的前提下,僅僅通過類本身來呼叫static方法。它很像全域性方法。

5.5 清理:中級處理和垃圾回收

Java有垃圾回收器負責回收無用物件佔據的記憶體資源。

Java允許在類中定義一個名為finallize()的方法。它的工作原理“假定”是這樣的:一旦垃圾回收器準備好釋放物件佔用的儲存空間,將首先呼叫其finallize(0方法,並且在下一次垃圾回收動作發生時,才會真正回收物件佔用的記憶體。

Java裡的物件並非總是被垃圾回收。換句話說:

  1. 物件可能不被垃圾回收
  2. 垃圾回收不等於析構(C++中銷燬物件必須要用到的函式)。
  3. 垃圾回收只與記憶體有關

隨著程式的退出,哪些資源也會全部交還給作業系統。

無論是“垃圾回收”還是“終結”,都不保證一定會發生。如果Java虛擬機器(JVM)並未面臨記憶體耗盡的情形,它是不會浪費時間去執行垃圾回收以恢復記憶體的

5.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   }
    }
}
/* Output:
Tag(1)
Tag(2)
Tag(3)
Card()
Tag(33)
f()*/
  1. 靜態資料的初始化
    無論建立多少個物件,靜態資料都只佔用一份儲存區域。static關鍵字不能應用於區域性變數,因此它只能作用於域。
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)
            
           

相關推薦

Java程式設計思想讀書筆記第一---

Java程式設計思想(第四版)學習筆記 第一章---第五章 第一章:物件導論 1.1抽象過程 1. 2訪問控制 第二章:一切都是物件 2. 1用引用操縱物件 2. 2基本型別 第三章:操作符

Java併發程式設計的藝術——讀書筆記 併發程式設計的挑戰

第一章 併發程式設計的挑戰 因為最近找工作,準備筆試/面試,開始嘗試閱讀這本書,我不常寫部落格,距上一次寫已經過去大概一年時間了,連CSDN密碼都忘了/衰,所以這次新開一個賬號重新開始,希望我能堅持下去。 第一章沒什麼內容,我認為其目的主要是給出足夠多的閱讀這本書的理

大話存儲學習筆記,磁盤

關註 安裝程序 參數 使用 tle 外部 相互 瓶頸 代碼 第一章 計算機的IO世界 1.1 總線 1.1.1 總線的概念 計算機中所有的IO都通過共享總線的方式來實現。 總線實際上就是一條或多條的物理導線。密密麻麻的印到電路板上,而且為了避免高頻振蕩的幹擾,一般都會分組

JavaScript動畫基礎學習筆記-- 旋轉箭頭

-- turn 我們 math class pla document new lose 隨著鼠標的移動旋轉箭頭。 requestAnimationFrame 在requestAnimationFrame之前我們可以用setInterval來實現動畫的循環:

《深入理解java虛擬機器》讀書筆記---- 類載入機制

類載入的時機 1、類從虛擬機器載入到記憶體開始,到卸載出記憶體為止,整個生命週期分為七個階段:載入、驗證、準備、解析、初始化、使用和解除安裝。其中驗證、準備和解析統稱為連線階段。 2、載入、驗證、準備、初始化和解除安裝這五個階段是按順序執行的,而解析階段卻不一定,解析可以在初始化之後

吳恩達深度學習工程師學習筆記

吳恩達【深度學習工程師】專項課程包含以下五門課程: 1、神經網路和深度學習; 2、改善深層神經網路:超引數除錯、正則化以及優化; 3、結構化機器學習專案; 4、卷積神經網路; 5、序列模型。 今天介紹《神經網路與深度學習》系列第一講:深度學習概述。 主要內容:

javajava程式設計思想讀書筆記

之前主要用的C++的比較多,之前花了快2個月的實際認真系統全面的學習了以下java的基礎語法,《java程式設計思想》這本書翻譯水平確實不是很好,很多話讀著會比較拗口。推薦讀之前,先去網上搜索 “java程式設計思想勘誤”,當然,有時間,最好還是直接讀英文版。 網上書評價這

Java程式設計思想讀書筆記1~13、16

目錄: 第1章 物件導論 1.1 伴隨多型的可互換物件   面向物件程式設計語言使用了後期繫結的概念。當向物件傳送訊息時,被呼叫的程式碼直到執行時才能確定。也叫動態繫結。   編譯器確保被呼叫方法的存在,並對呼叫引數和返回值執行型別檢查(Java是強型別的語言,無法

Java程式設計思想四版課後習題筆記

2.11練習10: 編寫一個程式:打印出從命令列獲得的三個引數。為此,需要確定命令列陣列中string的下標。 書上的答案是: public class E10 { public static void main(String[] args) { System.out.prin

Java程式設計思想讀書筆記——內部類

內部類擁有其外圍所有(即使是私有)屬性的訪問權。 public class Outer { private String s = "hello"; private void add(){ System.out.println(s

Java程式設計思想讀書筆記

2018.06.05 重新梳理下java基礎,熟悉的章節不記錄了。 第五章 初始化與清理 一、過載 定義:為了讓方法名相同而形參不同的構造器同時存在,即同名不同參。 區分:通過引數型別的差異。(注意:不要用返回值區分過載方法 ) 型別提升(向上提升): int —

Java程式設計思想12.通過異常處理錯誤

Java 的基本理念是“結構不佳的程式碼不能執行”。 異常處理是 Java 中唯一正式的錯誤報告機制,並且通過編譯器強制執行。 12.1 概念 異常機制會保證能夠捕獲錯誤,並且只需在一個地方(即異常處理程式中)處理錯即可。 12.2 基本異常 異常情形(exceptional conditio

Java程式設計思想10.內部類

將一個類的定義放在另一個類的定義內部,這就是內部類。 10.1 建立內部類 內部類的名字是巢狀在外部類裡面的 外部類可以有方法,返回一個指向內部類的呼叫。(外部類中可以呼叫內部類) 如果在外部類中,希望能在除了靜態方法之外的任意位置建立某個內部類物件,那麼可以向下面這樣指明物件型別。

Java程式設計思想11.持有物件

如果一個程式只包含固定數量的且生命週期都是已知的物件,那麼這是一個非常簡單的程式。 Java 類庫中提供一套容器類,來儲存比較複雜的一組物件。其中有 List、Set、Queue、Map 等。這些類也被稱為集合類,Java 的類庫中使用 Collection 這個名字指代該類庫的一個特殊子集(其實 Java

Java程式設計思想9.介面

介面和內部類為我們提供了一種將介面與實現分離的更加結構化的方法。 9.1 抽象類和抽象方法 Java 提供抽象方法機制,這種方法時不完整的,僅有宣告,沒有方法體。 包含抽象方法的類叫做抽象類。如果一個類包含一個或多個抽象方法,那麼該類必須被限定為是抽象的(否則編譯器報錯)。 一個抽象類不完整的時候,

Java程式設計思想8.多型

在面向物件的程式設計語言中,多型是繼資料抽象和繼承之後的第三種基本特徵。 多型分離了“做什麼”和“怎麼做”,讓介面和實現分離開,改善了程式碼的可讀性和組織結構,建立了可拓展的程式。 封裝,通過合併特徵和行為來建立新的資料型別。 實現隱藏,通過將細節“私有化”把介面和實現分離開來。 多型,消除型

Java程式設計思想13.字串

字串操作是計算機程式設計中最常見的行為。 13.1 不可變 String String 物件是不可變的。String 類中每一個看起來會修改 String 值的方法,實際上都是建立了一個全新的 String 物件去包含修改後的字串內容;而最初的 String 物件則沒有改變。 每當吧 Stirng 物

Java併發程式設計讀書筆記

  前幾天整理電腦檔案的時候,突然發現了之前還在kindle儲存了關於併發程式設計的書,剛好自己在這方面挺薄弱的,故整理一波讀書筆記,繼續加強學習。   1.上下文切換 1.1 時間片分配演算法 時間片是CPU分配給各個執行緒的時間,CPU通過不停地切換執行緒執行,使各個執行緒彷彿是”同

Java程式設計思想讀書筆記——淺析==與equals()

我們知道,==操作符在Java中被用來判斷兩個值是否相等,但是,當我們用它來判斷兩個物件是否相等時,得到的結果卻出乎了我們的意料。 public class Test { public static void main(String[] args) {

Java程式設計思想讀書筆記——位運算子、邏輯運算子以及短路

我們將布林型別作為一種單位元值對待,所以它多少有些獨特。我們可以對它執行按位“與”、按位“或”、按位“異或”運算,但不能執行按位“非”。對於布林值,按位操作符具有與邏輯操作符相同的效果。 上面這段話摘自《程式設計思想》,意思就是&和|在邏輯判斷中,能