基礎篇-1.2Java世界的規章制度(上)

起飛的小火雞發表於2019-07-17

1 Java識別符號

在Java語言中,有類、物件、方法、變數、介面和自定義資料型別等等,他們的名字並不是確定的,需要我們自己命名。而Java識別符號就是用來給類、物件、方法、變數、介面和自定義資料型別命名用的。

命名規則說明:

  • 識別符號可以由字母、數字、下劃線(_)、美元符($)組成,但不包含@、#、空格等其他特殊字元,不能以數字開頭。例如:1name 是不合法的。注意:Java識別符號是可以允許中文命名的,因為Java內部使用了Unicode字符集。
  • 識別符號不能是Java關鍵字和保留字(Java預留的關鍵字,以後的Java升級版本中可能作為關鍵字),但可以包含關鍵字和保留字。例如:不可以使用 for 作為識別符號,但是 myfor 是可以的。
  • 識別符號是嚴格區分大小寫的,同時也沒有長度的限制。例如:Myfor 和 myfor 是兩個不同的識別符號。
  • 識別符號的命名也不能隨意而為,最好是能反映其作用的,做到看其名知其意。

Java語言中具有特殊用途的詞,被稱為關鍵字。Java中常用的關鍵字,如下所示:

abstract extends break byte case catch
char class continue default do double
else if boolean false true public
interface long int float short void
final finally try for static this
null return new import throw throws
switch super while do private protected
package instanceof native implements synchronized volatile

下面這個Java程式碼中的識別符號,由於錯誤命名的識別符號,導致這個Java檔案不能編譯成功,會直接報識別符號相關的錯誤。

public class MyFirst {

    /**
     * 錯誤命名的識別符號
     */
    String 1a = "test";
    String u#a = "test";
    String u@a = "test";
    String void = "test";
    String b a = "test";
    
    /**
     * 正確命名的識別符號
     */
    String _a = "test";
    String $a = "test";
    String aa = "test";
    
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }

}

 

2 Java資料型別

Java是一種強型別語言,每一個變數都必須宣告其型別。Java的資料型別分有兩大類:基本型別(又稱內建資料型別)和引用型別。

 

2.1 基本型別

Java提供了八種基本型別,其中有六種數字型別(四個整數型,long、short、int和byte,兩個浮點型,float和double),一種字元型,char,還有一種布林型,boolean。

 

2.1.1 整數型

byte

byte 資料型別是8位、有符號的,以二進位制補碼錶示的整數,預設值是0,在Java中佔用1個位元組。

其可以以8位,即8個0、1表示。8位的第一位是符號位,即0000 0001表示數字1,1000 0000表示-1。所以其最大值是0111 1111,即127(2^7-1);最小值是1111 1111,即-128(-2^7)。從而可以知道,Java中一個byte位元組的範圍是-128~127。

例子:

byte a = 10;

byte b = -10;

注意:其他的整數型,如short、int和long,也是類似的用法,都可以以位數0、1表示,均有最大值和最小值,區別就是它們的位數不同。

 

short

short 資料型別是 16 位、有符號的,以二進位制補碼錶示的整數,其預設值是0,在Java中佔用2個位元組。

其可以以16位,即16個0、1表示。最大值是32767(2^15 - 1),最小值是-32768(-2^15)。

例子:

short a = 10000;

short b = -10000;

 

int

int 資料型別是 32 位、有符號的,以二進位制補碼錶示的整數,其預設值是0,在Java中佔用4個位元組。

其可以以32位,即32個0、1表示。最大值是2,147,483,647(2^31 - 1),最小值是-2,147,483,648(-2^31)。

例子:

int a = 1000;

int b = -1000;

 

long

long 資料型別是 64 位、有符號的,以二進位制補碼錶示的整數,其預設值是0L,在Java中佔用8個位元組。

其可以以64位,即64個0、1表示。最大值是(2^63-1),最小值是(-2^63)。

注意:宣告long型別,最好是後面加上“l”或“L”,例如:

long a = 10000000;//這樣宣告不會出錯,因為在int資料型別的範圍內(21億內)
long b = 100000000000000;//這樣就肯定會報錯,因為已經超過了int的範圍,必須改成100000000000000L才不會報錯

 

2.1.2 浮點型

float

float 資料型別,又被稱為單精度型別,是單精度、32位、符合IEEE 754標準的浮點數,尾數可以精確到7位有效數字,而最後一位第八位是存在舍入誤差不精確的,其預設值是0.0f,在Java中佔用4個位元組。

float 資料型別的好處是在儲存大型浮點陣列的時候可節省記憶體空間,但是不能用來表示精確的值,如貨幣。

例子:

float f = 123.3f;

 

double

double 資料型別,又被稱為雙精度型別,是雙精度、64 位、符合IEEE 754標準的浮點數,精確程度是float的兩倍,即可精確到16位有效數字,而最後一位第17位是存在舍入誤差不精確的,其預設值是0.0d,在Java中佔用8個位元組。

例子:

double d = 222.2;

注意:浮點數的預設型別為double型別,但是double 資料型別同樣不能用來表示精確的值,如貨幣。如果需要精確的數字計算,可以使用BigDecimal類。

 

科學計數法

一種計數的方法,通常用來表示比較大的資料,其中的E或e,表示10的幾次方。如,314e2,表示314 * 10^2,即31400;314e-2,表示314 * 10^-2,即3.14。

這種方法在Java中也是適用的。

float f = 314e-2f; // 314 * 10^-2
double d = 3.14e4; // 3.14 * 10^4
System.out.println(f); // 輸出3.14
System.out.println(d); // 輸出31400.0

 

2.1.3 字元型

char

char 型別是單一的16位Unicode字元,佔2個位元組,可以儲存任何字元,最大值是 \uffff(即為65,535),最小值是 \u0000(即為0)。

例子:

char a = 'A';

注意:單引號是用來表示字元常量的,例如'A'是一個字元,它與"A"是不同的,"A"表示含有一個字元的字串。

 

char型別是可以用來計算的,因為char在ASCII等字元編碼表中是有對應的數值的。而在Java中的char型別字元運算時,是直接當做ASCII表對應的整數來對待的。

char a = 'A';
int b = 1;
int c = a+b;
System.out.println(c); // 輸出66

 

Java語言中還允許使用轉義字元'\'來將其後的字元轉位其他的含義,例如,char c = '\n';//表示換行符

下面列舉一些比較常見的轉義符。

轉義符 含義 Unicode 值
\n 換行 \u000a
\r 回車 \u000d
\t 製表符(tab鍵) \u0009
\" 雙引號 \u0022
\' 單引號 \u0027
\\ 反斜槓 \u005c

 

2.1.4 布林型

boolean 型別表示一位資訊,注意不是一個位元組。其只有兩個值,true和false,預設值是false。

例子:

boolean a = true;

boolean 型別只是用來判斷邏輯條件,一般用於if、while、do while。

 

2.2 引用型別

Java為每種基本型別都提供了對應的封裝型別(即引用型別):Byte、Short、Integer、Long、Float、Double、Character和Boolean。引用型別就是一種物件型別,它的值是指向記憶體空間的引用,即類似於c語言中指標指向地址。其實這裡的引用還跟變數、棧和堆是有關係的,但是這不是本節的關鍵,後續會有專門的一節來說明。

Java中的引用型別還分有四種,分別是強引用(StrongReference)、軟引用(SoftReference)、弱引用(WeakReference)和虛引用(PhantomReference)。其中,強引用是我們使用最普遍的引用,如果一個物件具有強引用,那垃圾回收器寧願丟擲OOM(OutOfMemoryError)也不會回收它。

 

強引用(StrongReference)

這種引用是平時開發中最常用的,例如  String strong = new String("Strong Reference") 。當一個例項物件具有強引用時,垃圾回收器不會回收該物件,當記憶體不足時,寧願丟擲OutOfMemeryError異常也不會回收強引用的物件,因為JVM認為強引用的物件是使用者正在使用的物件,它無法分辨出到底該回收哪個,強行回收有可能導致系統嚴重錯誤。

 

軟引用(SoftReference)

如果一個物件只有軟引用,那麼只有當記憶體不足時,JVM才會去回收該物件,其他情況不會回收。

如下例子,一般情況下記憶體充足的話,ss指向的物件是不會被回收,但是若記憶體不足則會把ss給回收掉。

Book ss = new Book("NONO");
SoftReference<Book> softReference = new SoftReference<>(ss);
ss = null;
System.gc();
System.out.println("物件是否被回收:"+softReference.get());

軟引用可以結合ReferenceQueue來使用,當由於系統記憶體不足,導致軟引用的物件被回收了,JVM會把這個軟引用加入到與之相關聯的ReferenceQueue中。

如下例子,當系統記憶體不足時,觸發gc,這個Book就會被回收,但reference 將不會為null。

ReferenceQueue referenceQueue = new ReferenceQueue();
SoftReference<Book> softReference = new SoftReference<>(new Book(), referenceQueue);
Book book = softReference.get();
Reference reference = referenceQueue.poll();

 

弱引用(WeakReference)

只有弱引用的物件,當JVM觸發gc時,就會回收該物件。與軟引用不同的是,不管是否記憶體不足,弱引用都會被回收。弱引用可以結合ReferenceQueue來使用,當由於系統觸發gc,導致軟引用的物件被回收了,JVM會把這個弱引用加入到與之相關聯的ReferenceQueue中,不過由於垃圾收集器執行緒的優先順序很低,所以弱引用不一定會被很快回收。

 

虛引用(PhantomReference)

虛引用是所有型別中最弱的一個。一個持有虛引用的物件,和沒有引用幾乎是一樣的,隨時可能被垃圾回收器回收。當試圖通過虛引用的get()方法取得強引用時,總是會失敗。並且,虛引用必須和引用佇列一起使用,它的作用在於跟蹤垃圾回收過程。

當垃圾回收器準備回收一個物件時,如果發現它還有虛引用,就會在垃圾回收後,銷燬這個物件,將這個虛引用加入引用佇列。程式可以通過判斷引用佇列中是否已經加入了虛引用,來了解被引用的物件是否將要被垃圾回收。如果程式發現某個虛引用已經被加入到引用佇列,那麼就可以在所引用的物件的記憶體被回收之前採取必要的行動。

 

2.3 基本資料型別轉換

2.3.1 自動型別轉換

所謂自動型別轉換,總結起來就是一句話,容量小的資料型別可以自動轉換位容量大的資料型別。

例如,byte型別可以自動轉換為其他容量比它大的數字型別(如int、short、float等等)。下面直接看一個例項,一切就清晰了。

public class MyFirst {
    
    public static void main(String[] args) {
        byte a = 5;
        short b = 5;
        int c = 5;
        long d = 5;
        float e = 5.0f;
        double f = 5.0;
        
        // 測試自動型別轉換,容量最小的是byte,容量最大的是double,從小容量自動轉換為大容量且不報錯
        double g = a + b + c + d + e + f;
        System.out.println(g);
    }

}

若在上面的例子中,把最後的輸出 g 的資料型別改為 float型別 float g = a + b + c + d + e + f; ,則肯定會編譯不通過,報錯 cannot convert from double to float 。

 

2.3.2 強制型別轉換

強制型別轉換,又稱為顯示型別轉換,即在其值符合被強制轉換的型別的情況下,我們可以將其強制轉換為該型別。下面看個例項便清楚了。

public class MyFirst {
    
    public static void main(String[] args) {
        int a = 5;
        short b = (short) a;// 此處若沒有(short)強制轉換,則肯定會編譯不通過的
        System.out.println(b);
    }

}

我們再回到2.3.1看下這個例子,把 g 的資料型別改為 float型別 float g = a + b + c + d + e + f; ,其實這裡就只是因為 f 是double型別,如果我們改成這樣 float g = a + b + c + d + e + (float)f; ,將 f 的資料型別強制轉換為float,程式就可以正常執行了。

其實強制型別轉換,還包括了引用型別的強制轉換,不過這裡不說明,後面在講類的繼承和介面實現的時候會講到。

 

2.4 Java字串(String)

String是一個特殊的包裝類資料,可以用 String str = new String("Java"); 的形式來建立,也可以用 String str = "Java"; 的形式來建立。但是,他們的建立過程是不一樣的,下面具體說明下他們不一樣的建立過程。

 String str = "Java"; 的建立過程:首先在常量池中查詢是否存在內容為"Java"的字串物件;若不存在則會在常量池中建立一個"Java"的字串物件,並讓str引用該物件;若"Java"的字串物件已經存在常量池中,則會直接讓str引用該物件。

注意:常量池屬於類資訊的一部分,而類資訊是存在於JVM記憶體模型的方法區,即常量池是存在於JVM的方法區的,當類編譯時就會被分配到記憶體中。

 String str = new String("Java"); 的建立過程:

(1)定義一個str的String型別的引用並存放在棧中;

(2)在字串常量池中判斷是否存在內容為"Java"的字串物件,若不存在的話則在常量池中建立一個,若存在則不需要建立;

(3)執行new操作,在堆中建立一個指定的物件"Java",需要注意的是,這裡堆的物件是字串常量池中"Java"物件的一個拷貝物件;

(4)讓str指向堆中的"Java"物件,即str儲存的是堆中"Java"物件的地址。

下面舉個例子,讓我們看得更加通透。

public class MyFirst {
    
    public static void main(String[] args) {
        String a = "Java";
        String b = "Java";
        String c = new String("Java");
        String d = new String("Java");
        System.out.println(a==b);        // true        因為均是指向常量池中的同一個物件
        System.out.println(a.equals(b));// true        因為他們的值相同
        System.out.println(c==d);        // false    因為他們在棧中儲存的地址不一樣,在堆中指向的物件也不一樣
        System.out.println(c.equals(d));// true        因為他們的值相同
    }

}

圖解如下:

 

字串的常用方法

返回型別 方法 說明
String concat(String str)  字串的連線,將str字串拼接到原來字串的後面,並返回。
int length()  返回字串的長度,這裡的長度是指字串中Unicode字元的數目。
char charAt(int index)  索引特定位置的字元,並返回該字元。
boolean equals(Object anObject)  字串的比較,比較兩個字串的值是否相等,若相等則返回true,否則返回false。
int compareTo(String anotherString)  字串的比較,比較兩個字串的值大小,若原有值大則返回大於0的整數,若原有值小則返回小於0的整數,若他們相等則返回0。
String

substring(int beginIndex)

substring(int beginIndex, int endIndex)

 從字串中擷取子字串,從beginIndex位置起,到endIndex位置為止,但不包括endIndex位置的字元,擷取子字串,返回子字串。
int

indexOf(int ch)

indexOf(int ch, int fromIndex)

indexOf(String str)

indexOf(String str, int fromIndex)

 從字串中獲取對應字元第一次出現的位置,若整個字串都沒有該字元,則返回-1。
String

trim()

去除原字串的前後空格並返回。

 

下面看下這些常用方法對應的例子。

public class MyFirst {
    
    public static void main(String[] args) {
        String a = "I like Java ";
        String b = "very much!";
        System.out.println(a.concat(b));// a和b字串的拼接,輸出:I like Java very much!
        
        String c = "abc123";
        System.out.println(c.length());// c字串的長度,輸出:6
        System.out.println(c.charAt(2));// 索引c字串中的2位置的字元,輸出:c
        System.out.println(c.substring(2));// 擷取從2位置開始到結尾的字串,輸出:c123
        System.out.println(c.indexOf("b"));// 獲取字元為b的第一次出現的位置,輸出:1
        
        String d = "Java";
        String e = "Java";
        String f = "Java1";
        System.out.println(d.equals(e));// 比較d和e的值,輸出:true
        System.out.println(d.equals(f));// 比較d和f的值,輸出:false
        System.out.println(d.compareTo(e));// 比較d和e的值,輸出:0
        System.out.println(d.compareTo(f));// 比較d和f的值,輸出:-1
        
        String g = "   asdfgh  ";
        System.out.println(g.trim());// 去掉g的前後空格,輸出:asdfgh
    }

}

 

3 總結

  • Java識別符號的命名,以及Java關鍵字。
  • Java資料型別,分有基本型別和引用型別。
  • 基本型別,有六種數字型別(四個整數型,long、short、int和byte,兩個浮點型,float和double),一種字元型,char,還有一種布林型,boolean。
  • 引用型別,有強引用、軟引用、弱引用和虛引用,其中我們平常普遍用到的就是強引用。
  • 基本資料型別轉換,有自動型別轉換和強制型別轉換。
  • String字串,一種特殊的包裝類資料。

 

相關文章