瘋狂Java講義 讀書筆記(一)

李剛老師的《瘋狂Java講義》(第三版)是個人啓蒙做品,前先後後一共看了3遍,每次都有新的認識。java

接下來的一段時間就將一些經典的知識記錄下來。程序員

1.計算機高級語言的執行方式分爲編譯型和解釋型,前者運行高效但不能跨平臺(C,C++,Object-C),後臺能夠跨平臺但效率不高(Ruby,Python)。Java比較特殊,先編譯生成.class,再在JVM中解釋。算法

2.垃圾回收機制:依靠垃圾回收算法,什麼時候回收對Java程序員而言具備透明性,所以要養成良好的習慣——對於不須要的對象,不要引用他們。(在堆中進行回收)spring

3.Java是強類型語言:全部類變量必須先聲明後使用,指定類型的變量只能接受與類型相匹配的值。編程

4.Java支持兩種類型:數組

  1. 基本類型:布爾類型、數值類型
  2. 引用類型:類、接口、數組。

5.強制類型轉化:形成溢出時,以前一直以爲19.745會變成19(實在汗顏),實際上是轉換成二進制後再進行截取。緩存

6.常量池:在編譯期被肯定,並已被保存在.class文件中的一些數據。包括類、方法、接口中的常量,也包括字符串常量。併發

7.switch語句:控制表達式的數據類型只能是byte,short,char,int,枚舉,String.工具

8.break和continue能夠經過標籤跳到指定的循環層測試

public class BreakTest2
{
    public static void main(String[] args)
    {
        outer:
        for (int i = 0 ; i < 5 ; i++ )
        {
            for (int j = 0; j < 3 ; j++ )
            {
                System.out.println("i的值爲:" + i + "  j的值爲:" + j);
                if (j == 1)
                {
                    break outer;
                }
            }
        }
    }
}

9.棧和堆:

  1. 當一個方法執行時,每一個方法都會創建本身的內存棧,在這個方法內定義的變量將會逐個放入這塊棧內存裏,隨着方法的執行結束,這個方法的內存棧也將自動銷燬。所以,全部在方法中定義的局部變量都是放在棧內存中;
  2. 當咱們在程序中建立一個對象是,這個對象將被保存到運行是數據區中,以便反覆利用,這個運行是數據區就是堆內存。堆內存中的對象不會因方法結束而銷燬,就算方法結束後,這個對象還可能被另外一個變量所引用,則這個對象不會銷燬,只有當一個變量沒有任何引用變量引用它,那麼系統的垃圾回收器纔會在合適的時候回收它;

10.Arrays:Java8增長的工具類,在java.util包下,支持併發編程

        // 定義一個a數組
        int[] a = new int[]{3, 4 , 5, 6};
        // 定義一個a2數組
        int[] a2 = new int[]{3, 4 , 5, 6};
        // a數組和a2數組的長度相等,每一個元素依次相等,將輸出true
        System.out.println("a數組和a2數組是否相等:"
            + Arrays.equals(a , a2));
        // 經過複製a數組,生成一個新的b數組
        int[] b = Arrays.copyOf(a, 6);
        System.out.println("a數組和b數組是否相等:"
            + Arrays.equals(a , b));
        // 輸出b數組的元素,將輸出[3, 4, 5, 6, 0, 0]
        System.out.println("b數組的元素爲:"
            + Arrays.toString(b));
        // 將b數組的第3個元素(包括)到第5個元素(不包括)賦爲1
        Arrays.fill(b , 2, 4 , 1);
        // 輸出b數組的元素,將輸出[3, 4, 1, 1, 0, 0]
        System.out.println("b數組的元素爲:"
            + Arrays.toString(b));
        // 對b數組進行排序
        Arrays.sort(b);
        // 輸出b數組的元素,將輸出[0, 0, 1, 1, 3, 4]
        System.out.println("b數組的元素爲:"
            + Arrays.toString(b));
    }

11.Java語言經過new關鍵字調用構造器。

12.this關鍵字:

  1. 讓類中的一個方法,訪問該類裏的另外一個方法或者實例變量。
  2. this所表明的對象是不肯定的,但他的類是肯定的。
  3. 在構造器中,this表明該構造器正在初始化的對象。
  4. 若是在某個方法中把this做爲返回值,則能夠屢次連續調用同一個方法。
public class ReturnThis
{
    public int age;
    public ReturnThis grow()
    {
        age++;
        // return this返回調用該方法的對象
        return this;
    }
    public static void main(String[] args)
    {
        ReturnThis rt = new ReturnThis();
        // 能夠連續調用同一個方法
        rt.grow()
            .grow()
            .grow();
        System.out.println("rt的age成員變量值是:" + rt.age);
    }
}

13.static:不要使用對象去調用static修飾的成員變量,要使用類去調用。

14.值傳遞:將實際參數的副本傳入方法內,參數自己不會受到任何影響。

15.形參可變的方法:定義方法時,在最後一個形參的類型後增長三個點(...)。多個參數值被當成數組傳入。與傳入數組相比,形參可變動加簡潔,但一個方法只能有一個可變形參。

public class Varargs
{
    // 定義了形參個數可變的方法
    public static void test(int a , String... books)
    {
        // books被當成數組處理
        for (String tmp : books)
        {
            System.out.println(tmp);
        }
        // 輸出整數變量a的值
        System.out.println(a);
    }
    public static void main(String[] args)
    {
        // 調用test方法
        test(5 , "瘋狂Java講義" , "輕量級Java EE企業應用實戰");
    }
}

16.遞歸算法:一個方法調用自身,必定要向已知方向遞歸。

17.局部變量:形參(方法簽名中定義的變量),方法局部變量(在方法內定義),代碼塊局部變量(在代碼塊內定義),局部變量不屬於任何類或者實例,它老是保存在其所在方法的棧內存中。

18.封裝:類的成員變量不直接暴露,而是經過方法實現操做和訪問,以便於在方法中添加一些限制條件

19.高內聚:儘量把模塊的內部數據、功能實現細節隱藏在模塊內部獨立完成,不容許外部直接干預;低耦合:僅暴露少許的方法給外部使用。

20.靜態導入:JDK1.5增長的導包方法,用於導入包內的靜態成員 import static package...

21.構造器:

  1. 構造器是建立Java對象的重要途徑,但這個對象並非徹底由構造器負責建立的。
  2. 子類的構造器一定會調用其父類的構造器(沒有super和this時默認調用無參的構造器)。

22.方法重寫(覆蓋)原則:

  1. 兩同:方法名、參數列表相同
  2. 兩小:子類方法返回值<=父類方法返回值
  3. 一大:子類方法訪問權限>=父類方法訪問權限

23.當程序建立一個子類對象時,系統不只會爲該類中定義的實例變量分配內存,也會爲它從父類繼承獲得的全部實例變量分配內存。

24.引用變量類型:

  1. 編譯時類型:由聲明該變量時使用的類型決定
  2. 運行時類型:由實際賦給該變量的對象決定
  3. 編譯時類型和運行時類型不一樣時,就出現了所謂的多態
  4. 引用變量在編譯階段只能調用其編譯時類型所具備的方法,但運行時則執行它運行時類型所具備的方法(可用強制類型轉換解決問題)。

25.向上轉型:把一個子類對象直接賦值給父類引用變量;強制類型轉換:把一個父類對象賦給子類引用變量

26多態:

  1. 相同類型的變量,調用同一個方法時呈現出多種不一樣的行爲特徵叫作多態
  2. 成員變量不存在多態,老是調用父類的值

27.instanceof:判斷前面的對象是不是後面的類,或者其子類、實現類的實例

String str="str";
//true
System.out.println(str instanceof Object);
Object obj=new Object();
//false
System.out.println(obj instanceof String);

28.繼承與組合:

  1. 繼承表明"is a",組合表明"has a"
  2. 建立子類對象,系統會爲其父類所定義的實例變量分配內存空間,所以繼承和組合在系統開銷上沒有太大的區別

29.初始化塊:

  1. 初始化塊在構造器以前執行(編譯後初始化塊的內容會還原到構造器中)
  2. 靜態初始化塊在普通初始化塊以前執行

30.包裝類:包裝類的實例能夠與數值類型直接比較

31.toString:自定義類時,儘可能重寫類的toString方法,便於輸出實例的值

32.==與equals:

  1. 對於引用類型,只有兩者指向同一個對象,==纔會等於true 
  2. String類型狀況以下,編譯時肯定的數據在常量池中,運行時生成的數據在堆內存中
    // s1直接引用常量池中的"瘋狂Java"
        String s1 = "瘋狂Java";
        String s2 = "瘋狂";
        String s3 = "Java";
        // s4後面的字符串值能夠在編譯時就肯定下來
        // s4直接引用常量池中的"瘋狂Java"
        String s4 = "瘋狂" + "Java";
        // s5後面的字符串值能夠在編譯時就肯定下來
        // s5直接引用常量池中的"瘋狂Java"
        String s5 = "瘋" + "狂" + "Java";
        // s6後面的字符串值不能在編譯時就肯定下來,
        // 不能引用常量池中的字符串
        String s6 = s2 + s3;
        // 使用new調用構造器將會建立一個新的String對象,
        // s7引用堆內存中新建立的String對象
        String s7 = new String("瘋狂Java");
        System.out.println(s1 == s4); // 輸出true
        System.out.println(s1 == s5); // 輸出true
        System.out.println(s1 == s6); // 輸出false
        System.out.println(s1 == s7); // 輸出false

33.重寫equals的條件:

  1. 自反性:x.equals(x)=true
  2. 對稱性:若x.equals(y)=true,則y.equals(x)=true
  3. 傳遞性:若x.equals(y)=true,y.equals(z)=true,則x.equals(z)=true
  4. 一致性:只要x.equals(y)=true且x,y不變,不管調用多少次結果都不變
  5. 對任何不適Null的x,x.equals(null)=false 6.equals相同,則hashcode相同

34.null類型的實例能夠訪問類的靜態方法和靜態變量,在底層是經過該實例的類去訪問的

35.final:

  1. final變量不是不能被賦值,而是不能被改變
  2. final變量必須由程序員顯示的指定初始值
  3. final修飾引用變量時,引用地址不能夠改變,對象能夠改變
  4. final修飾的方式不能被重寫,可是能夠被重載

36.宏變量:定義final變量時就爲該變量指定了初始值,並且能夠在編譯時就肯定下來,編譯器會把程序中全部用到改變量的地方直接替換成該變量的值(進入常量池)

37.不可變類:

  1. private final修飾全部成員變量
  2. 只有getter沒有setter

38.緩存池:先進先出緩存實例,重寫了equals和hsahcode

class CacheImmutale
{
    private static int MAX_SIZE = 10;
    // 使用數組來緩存已有的實例
    private static CacheImmutale[] cache
        = new CacheImmutale[MAX_SIZE];
    // 記錄緩存實例在緩存中的位置,cache[pos-1]是最新緩存的實例
    private static int pos = 0;
    private final String name;
    private CacheImmutale(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return name;
    }
    public static CacheImmutale valueOf(String name)
    {
        // 遍歷已緩存的對象,
        for (int i = 0 ; i < MAX_SIZE; i++)
        {
            // 若是已有相同實例,直接返回該緩存的實例
            if (cache[i] != null
                && cache[i].getName().equals(name))
            {
                return cache[i];
            }
        }
        // 若是緩存池已滿
        if (pos == MAX_SIZE)
        {
            // 把緩存的第一個對象覆蓋,即把剛剛生成的對象放在緩存池的最開始位置。
            cache[0] = new CacheImmutale(name);
            // 把pos設爲1
            pos = 1;
        }
        else
        {
            // 把新建立的對象緩存起來,pos加1
            cache[pos++] = new CacheImmutale(name);
        }
        return cache[pos - 1];

    }
    public boolean equals(Object obj)
    {
        if(this == obj)
        {
            return true;
        }
        if (obj != null && obj.getClass() == CacheImmutale.class)
        {
            CacheImmutale ci = (CacheImmutale)obj;
            return name.equals(ci.getName());
        }
        return false;
    }
    public int hashCode()
    {
        return name.hashCode();
    }
}
public class CacheImmutaleTest
{
    public static void main(String[] args)
    {
        CacheImmutale c1 = CacheImmutale.valueOf("hello");
        CacheImmutale c2 = CacheImmutale.valueOf("hello");
        // 下面代碼將輸出true
        System.out.println(c1 == c2);
    }
}

39.默認方法:

  1. JDK1.8後新增的方法,在接口中一共有三種方法,抽象方法(abstract),類方法(static),默認方法(default),後二者必須有方法實現
  2. 使用接口的實例來調用默認方法

40.抽象類:抽象類做爲多個子類的抽象父類,能夠被當成系統實現過程的中間產品,這個中間產品已經實現了系統的部分功能,但這個產品依然不能當成最終產品,必須由進一步的完善,

41.內部類:

  1. 提供更好的封裝
  2. 內部類成員能夠直接訪問外部類的私有數據
  3. 匿名內部類適用於建立只須要一次使用的類
  4. 局部內部類和匿名內部類不是類成員
  5. 包含內部類的類被稱爲外部類

42.非靜態內部類:

  1. 非靜態內部類對象裏保存了一個外部類的引用
  2. 外部類對象訪問非靜態內部類成員時,可能非靜態普通內部類對象根本不存在
  3. 不容許在非靜態內部類定義靜態成員

43.靜態內部類:

  1. 靜態內部類能夠包含靜態成員和非靜態成員
  2. 靜態內部類是外部類的類相關,靜態內部類對象寄生在外部類的類自己中,只持有外部類的類引用,沒有外部類的對象引用

44.內部類的使用:

  1. 儘可能使用靜態內部類(調用簡單)
  2. 局部內部類沒有什麼卵用 
  3. 非靜態內部類的構造器必須由其外部類的對象來調用
public class SubClass extends Out.In
{
    //顯示定義SubClass的構造器
    public SubClass(Out out)
    {
        //經過傳入的Out對象顯式調用In的構造器
        out.super("hello");
    }
}

45.匿名內部類:

  1. 必須繼承一個父類或者實現一個接口
  2. 不能是抽象類
  3. 不能定義構造器
  4. JDK1.8之前被匿名內部類訪問的局部變量必須使用final修飾,1.8之後會自動加上final修飾

46.枚舉類:可使用枚舉類來替代靜態final常量

public class Enum {
public enum Season{
    spring,summer,fall,winter;
}
public static void main(String[] args) {
    Season season=Season.spring;
    System.out.println(season);
    switch (season){
    case spring:
        System.out.println("spring");
        break;
    case summer:
        System.out.println("summer");
        break;
    case fall:
        System.out.println("fall");
        break;
    case winter:
        System.out.println("winter");
        break;
    }
    
}

47.垃圾回收:

  1. 只負責回收對象,不負責物理資源
  2. 程序沒法精確控制垃圾回收的運行
  3. 在回收對象前,會調用對象的finalize方法嘗試讓其得到新的引用以復活
  4. finalize方法什麼時候被調用具備不肯定性
public class FinalizeTest
{
    private static FinalizeTest ft = null;
    public void info()
    {
        System.out.println("測試資源清理的finalize方法");
    }
    public static void main(String[] args) throws Exception
    {
        // 建立FinalizeTest對象當即進入可恢復狀態
        new FinalizeTest();
        // 通知系統進行資源回收
//        System.gc();  //// 強制垃圾回收機制調用可恢復對象的finalize()方法
//        Runtime.getRuntime().runFinalization();   //
        System.runFinalization();   //
        ft.info();
    }
    public void finalize()
    {
        // 讓tf引用到試圖回收的可恢復對象,便可恢復對象從新變成可達
        ft = this;
    }
}

48.引用類型:

  1. 強引用(最多見的引用)
  2. 軟引用(當系統內存空間不夠時會被回收)
  3. 弱引用(比軟引用級別更低,當系統垃圾回收機制運行時,不管內存夠不夠都會被回收)
  4. 虛引用(沒什麼用)
相關文章
相關標籤/搜索