天天看點

Java知識複習(前篇)内置資料類型包裝類型–引用資料類型(含相應内置資料類型)String參數傳遞類型轉換switch關鍵字

Java複習(一)

  • 内置資料類型
  • 包裝類型--引用資料類型(含相應内置資料類型)
    • 裝箱||拆箱
      • 裝箱
      • 拆箱
      • 自動裝箱與手動裝箱
  • String
    • 基本概要
    • String與StringBuffer和StringBuilder
    • String pool
  • 參數傳遞
    • 重點
  • 類型轉換
    • 基本概要
      • float 與double的恩怨
      • 智能整數
  • switch
    • 基本概要
  • 關鍵字
    • final
    • static
      • 類内變量和方法初始化順序

内置資料類型

  • byte/8
  • char/16
  • short/16
  • int/32
  • float/32
  • long/64
  • double/64
  • boolean/~

boolean比較特殊,隻有true和false,可以機關存儲,但不是規定。JVM編譯時會将boolean類型轉為int類型,1=true,0=false。JVM支援boolean數組,但是是通過讀寫byte數組實作。

包裝類型–引用資料類型(含相應内置資料類型)

  • Byte:byte
  • Character:char
  • Short:short
  • Integer:int
  • Float:float
  • Long:long
  • Double:double
  • Boolean:boolean

裝箱||拆箱

裝箱

具體是指将基本類型轉化為包裝類型。具體做法是通過調用valueOf方法實作的。例如,将char轉型為Character類型調用的就是Character.valueOf()。在valueOf的執行上表現為,按類型分類:

  1. 整數類型:若在常用取值範圍内(即在緩沖池中),則直接傳回該對象的引用,否則建立一個新的對象并傳回它的引用。
  2. 浮點類型:建立新對象并傳回引用。
  3. 布爾類型:直接傳回靜态常量true||false

代碼舉例:

拆箱

指将包裝類型轉換為基本類型。具體做法是通過包裝類型的xxxValue方法來實作轉換。

代碼舉例:

Character c = "c";
	char a = c;
           

自動裝箱與手動裝箱

手動裝箱是指顯式調用new的方式經行裝箱,例如:

自動裝箱指用字面值代替顯示調用new的方式進行裝箱,這種方式是jdk 1.5之後出現的特性,例如:

差別:手動裝箱每次建立新對象,自動裝箱會先判斷緩沖池中是否存在該字面量,若有則直接傳回它的引用,若無再建立新對象。在 Java 8 中,Integer 緩存池的大小預設為 -128~127。

資料:在 jdk 1.8 所有的數值類緩沖池中,Integer 的緩沖池 IntegerCache 很特殊,這個緩沖池的下界是 - 128,上界預設是 127,但是這個上界是可調的,在啟動 jvm 的時候,通過 -XX:AutoBoxCacheMax= 來指定這個緩沖池的大小,該選項在 JVM 初始化的時候會設定一個名為 java.lang.IntegerCache.high 系統屬性,然後 IntegerCache 初始化的時候就會讀取該系統屬性來決定上界。

String

基本概要

String 被聲明為final,也就是說無法被繼承,所有的包裝類型也無法被繼承。目前String内部存儲字元串的方式是使用帶final關鍵字的byte數組,是以還帶有coder辨別來識别編碼方式。由于存儲字元串的數組是final修飾的,無法被修改,也就意味着String對象一旦被建立就無法被改變。不改變就意味着有幾個好處:

  1. 可以緩存hash值
  2. String Pool 的需要
  3. 線程安全
  4. 網絡傳輸安全

String與StringBuffer和StringBuilder

String StringBuffer StringBuilder
可變性 不可變 可變 可變
線程安全性 線程安全 線程安全 線程不安全

String pool

字元串常量池儲存所有的字元串字面量,字元串池由String類私有的維護, 在建立String對象的時候有兩種建立方式,兩種的性能不大相同:

  1. 采用new的方式初始化,例如: 這種方法的執行過程如下,JVM首先拿着"a"這個字元串去String pool裡面找,如果沒找到,就先在池裡建立一個”a“對象然後再去堆裡建立一個”a"字元串對象,再把堆裡的字元串對象的引用傳回;如果找到了,pool和JVM相視一笑,JVM就直接在堆裡建立"a"字元串對象并傳回它的引用。
  2. 采用字面量直接指派的方法,例如: 這種方法會讓JVM先帶着”a"去pool裡面找有沒有一樣的,如果找到了就直接傳回pool裡的字元串對象的引用;如果找不到,JVM隻能長歎一聲然後在pool裡建立一個新的”a"字元串對象并傳回它的引用。

參數傳遞

重點

Java參數是按值傳遞,不是引用傳遞。傳對象的時候實際傳遞的是這個對象的位址。(我了解的就是進去的東西隻是一個指針,調用對象的方法的時候會自動解引用)是以,在函數内對傳進來的對象進行修改如果是使用 ” . “ 的方式(使用方法或直接修改【這不封閉】)可以修改成功。若是使用 ”=“的方式,隻是把形參的值(形參存位址)換了一個,外面的實參沒動,實參的值不變(存的位址不變)。

舉例:

public class PassByValueExample {
    public static void main(String[] args) {
        Dog dog = new Dog("A");
        System.out.println(dog.getObjectAddress()); // [email protected]
        func(dog);
        System.out.println(dog.getObjectAddress()); // [email protected]
        System.out.println(dog.getName());          // A
    }

    private static void func(Dog dog) {
        System.out.println(dog.getObjectAddress()); // [email protected]
        dog = new Dog("B");
        System.out.println(dog.getObjectAddress()); // [email protected]
        System.out.println(dog.getName());          // B
    }
}
           

類型轉換

基本概要

Java 不支援隐式向下轉型,不允許精度降低的自動操作。

float 與double的恩怨

首先,字面量的浮點數,都是double類型的。這就導緻了float不能直接寫字面量指派,即下面的例子是失敗的:

那要想成功怎麼辦,讓字面量f:

智能整數

字面量的整數,很有意思,會根據字面量的大小是不是在整數類型的取值範圍内來判斷這個語句是否有類型轉換的問題,舉個例子,下面的代碼數值在short的取值範圍内:

下面的不在取值範圍内:

switch

基本概要

Java的switch支援了一個非常令人激動的特性,可以在條件判斷中使用字元串類型,哦我的上帝,真令人高興。同時switch是不支援long的,因為設計switch的時候就沒想過可能會有那麼case,如果有,那一定是神仙。有複雜的值需要判斷,這邊建議您用if。

關鍵字

final

一言以蔽之,不許動。

  1. 修飾資料:這個變量名所代表的記憶體裡面的東西不能變,但是這個記憶體裡面的東西所指向的另一個記憶體裡的東西是可以的,也就是說用final修飾了一個引用,這個引用就不能二婚,不能指向别的對象,但你的對象依舊是自由的,它可以變。
  2. 修飾方法:你可以把它看作是private,也就是無法繼承,實際上private被隐式的指定為final了。如果你硬要杠,偏要繼承後寫個一摸一樣的方法,那這個方法是新方法,而不是重寫的。
  3. 修飾類:不準繼承,絕後了。

static

  1. 修飾變量(也叫靜态變量,下面的一樣):被修飾的變量将會是整個類一起共享的,而不是單個對象獨占的,記憶體中就一份,不管這個類你建立了多少對象。執行個體變量(沒有static修飾變量的都是)也好說,就是每個對象自己的,幾個對象就幾個執行個體變量。
  2. 修飾方法:同樣,被修飾的方法是整個類共有的,但是,這個方法裡面隻能有靜态變量,必須有方法體,不能有this和super。
  3. 修飾語句塊:整個類共有,隻在類初始化的時候運作一次。
  4. 修飾内部類:非靜态内部類需要依賴外部執行個體,沒有外部執行個體就不能建立,有了外部執行個體後使用"外部執行個體.new 内部類()"的格式建立内部類,不限量。靜态内部類不依賴外部執行個體,可以自由建立。
  5. 靜态導包:在使用靜态變量和方法時不用再指明 ClassName,進而簡化代碼,但可讀性大大降低,舉例:
    package a;// 提供靜态内部類
    
    /**
     * @author ZTL
     */
    public class JavaBlogTest {
        public static class MyInnerClass {
        }
        public static void main(String[] args) {
            MyInnerClass a = new MyInnerClass();
            MyInnerClass b = new MyInnerClass();
        }
    }
               
    package b;// 消費靜态内部類
    
    import static a.JavaBlogTest.*;
    
    /**
     * @author ZTL
     */
    public class JavaBlogTest2 {
        public static void main(String[] args) {
            MyInnerClass a = new MyInnerClass();
        }
    }
               

類内變量和方法初始化順序

  • 初始化順序:存在繼承的情況下的初始化順序,越靠前越早初始化。
    • 父類(靜态變量、靜态語句塊)
    • 子類(靜态變量、靜态語句塊)
    • 父類(執行個體變量、普通語句塊)
    • 父類(構造函數)
    • 子類(執行個體變量、普通語句塊)
    • 子類(構造函數)