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字串,一種特殊的包裝類資料。