Java 是一種強類型語言,這就意味著必須為每一個變量聲明一種類型。在 Java 中基本數據類型共有 8 種,包括 4 種整型、2 種浮點型、1 種用于表現 Unicode 編碼的字符單元的字符類型 char 和一種用于表示真值的 boolean 類型
~
本篇主要記錄內容包括:基礎數據類型、對象包裝器、字符串、數組
- 上一篇內容:Java基礎:Java基本概念
- 下一篇內容:Java基礎:Java數字類型
- 更多知識學習:全網最全的 Java 技術棧內容梳理(持續更新中)
文章目錄
- 一、基礎數據類型
- 1、整型
- 2、浮點類型
- 3、char 類型
- 4、boolean 類型
- 5、基礎類型間的轉換
- 二、對象包裝器
- 1、包裝器類
- 2、自動拆/裝箱
- 3、大數值
- 三、字符串
- 1、String 類常用的 api
- 2、StringBuffer、StringBuilder
- 四、數組
- 1、數組初始化以及匿名數組
- 2、Arrays類 API
- 3、多維數組
一、基礎數據類型
Java 是一種強類型語言,這就意味著必須為每一個變量聲明一種類型。在 Java 中基本數據類型共有 8 種,包括 4 種整型、2 種浮點型、1 種用于表現 Unicode 編碼的字符單元的字符類型 char 和一種用于表示真值的 boolean 類型。
1、整型
整型用于表示沒有小數部分的數值,它允許是負數。Java 提供了 4 種整形類型。
數據類型 | 存儲需求 | 默認值 | 取值范圍 |
---|---|---|---|
int | 4 字節,32 位 | 0 | - 2^31 ~ 2^31-1 |
short | 2 字節,16 位 | 0 | - 327,68 ~ 32,767 |
long | 8 字節,64 位 | 0L | - 2^63 ~ 2^63-1 |
byte | 1 字節,8 位 | 0 | - 128 ~127 |
在通常情況下,int 類型最常用。但如果表示星球上的居住人數,就需要使用 long 類型了。byte 和 short 類型主要用于特定的應用場合,例如,底層的文件處理或者需要控制占用存儲空間量的大數組。
在 Java 中,整型的范圍與運行 Java 代碼的機器無關。這就解決了軟件從一個平臺移植到另一個平臺,或者在同一個平臺中的不同操作系統之間進行移植給程序員帶來的諸多問題。與此相反,C 和 C++ 程序需要針對不同的處理器選擇最為高效的整型,這樣就有可能造成一個在 32 位處理器上運行很好的 C 程序在 16 位系統上運行卻發生整數溢出。由于 Java 程序必須保證在所有機器上都能夠得到相同的運行結果,所以各種數據類型的取值范圍必須固定。
長整型數值有一個后綴 L 或 l(如4000000000L)。十六進制數值有一個前綴 0x 或 0X(如 0xCAFE)。八進制有一個前綴 0,例如,010 對應八進制中的 8。很顯然,八進制表示法比較容易混淆,所以建議最好不要使用八進制常數。
從 Java 7 開始,加上前綴 0b 或 0B 就可以寫二進制數。例如,0b1001 就是 9。另外,同樣是從 Java 7 開始,還可以為數字字面量加下劃線,如用 1_000_00(0或0b1111_0100_0010_0100_0000)表示一百萬。這些下劃線只是為了讓人更易讀。Java 編譯器會去除這些下劃線。
2、浮點類型
浮點類型用于表示有小數部分的數值。在 Java 中有 2 種浮點類型。
數據類型 | 存儲需求 | 默認值 | 取值范圍 |
---|---|---|---|
float | 4 字節,32 位 | 0.0f | -2^31 ~ 2^31-1(有效位數6~7) |
double | 8 字節,64 位 | 0.0d | -2^63 ~ 2^63-1(有效位數15位) |
double 表示這種類型的數值精度是 float 類型的兩倍(有人稱之為雙精度數值)。絕大部分應用程序都采用 double 類型。在很多情況下,float 類型的精度很難滿足需求。實際上,只有很少的情況適合使用 float 類型,例如,需要單精度數據的庫,或者需要存儲大量數據。
float 類型的數值有一個后綴 F 或 f(例如,3.14F)。沒有后綴 F 的浮點數值(如3.14)默認為 double 類型。當然,也可以在浮點數值后面添加后綴 D 或 d(例如,3.14D)。
所有的浮點數值計算都遵循 IEEE 754 規范。具體來說,有三個特殊的浮點數值用于表示溢出和出錯情況的:● 正無窮大(Infinity)● 負無窮大(-Infinity)● 不是一個數字(NaN)。例如,使用一個正數除以 0 將得到正無窮大,使用一個負數除以 0 將得到負無窮大,0.0 除以 0.0 或對一個負數開方將得到一個非數。正無窮大通過 Double 或 Float 類的 POSITIVE_INFINITY 表示;負無窮大通過 Double 或 Float 類的 NEGATIVE_INFINITY 表示,非數通過 Double 或 Float 類 的NaN 表示。
警告:浮點數值不適用于無法接受舍入誤差的金融計算中。例如,命令 System.out.println(2.0-1.1)將打印出 0.8999999999999999,而不是人們想象的 0.9。這種舍入誤差的主要原因是浮點數值采用二進制系統表示,而在二進制系統中無法精確地表示分數 1/10。這就好像十進制無法精確地表示分數 1/3 一樣。如果在數值計算中不允許有任何舍入誤差,就應該使用 BigDecimal 類。
3、char 類型
char 類型原本用于表示單個字符。不過,現在情況已經有所變化。如今,有些 Unicode 字符可以用一個 char 值描述,另外一些 Unicode 字符則需要兩個 char值。
char 類型的字面量值要用單引號括起來。例如:'A’ 是編碼值為 65 所對應的字符常量。它與 “A” 不同,“A” 是包含一個字符 A 的字符串。char 類型的值可以表示為十六進制值,其范圍從 \u0000 到 \Uffff。例如:\u2122 表示注冊符號(TM), \u03C0 表示希臘字母 π。
除了轉義序列 \u 之外,還有一些用于表示特殊字符的轉義序列。
轉譯序列 | 名稱 | Unicode 轉譯序列 | 轉譯序列 | 名稱 | Unicode 轉譯序列 |
---|---|---|---|---|---|
\b | 推格 | \u0008 | \" | 雙引號 | \u0022 |
\t | 制表 | \u0009 | \’ | 單引號 | \u0027 |
\n | 換行 | \u0001 | \\ | 反斜杠 | \u005c |
\r | 回車 | \u000b |
所有這些轉義序列都可以出現在加引號的字符字面量或字符串中。
警告:Unicode 轉義序列會在解析代碼之前得到處理。例如,“\u0022+\u0022” 并不是一個由引號 (U+0022) 包圍加號構成的字符串。實際上,\u0022 會在解析之前轉換為 “,這會得到 “”+”",也就是一個空串。
4、boolean 類型
boolean(布爾)類型有兩個值:false 和 true,用來判定邏輯條件。整型值和布爾值之間不能進行相互轉換。
5、基礎類型間的轉換
基礎類型間的等級低到高:byte
< char
< short
< int
< long
< float
< double
,類型的轉換分為自動轉換與強制轉換,自動轉換:運算過程中,低級可以自動向高級轉換;強制轉換:高級需要強制轉換為低級,可能會丟失精度規則:
=
右邊先自動轉換成表達式中最高級的數據類型,再進行運算;=
左邊數據類型級別>
右邊數據類型級別,右邊會自動升級;=
左邊數據類型級別<
右邊數據類型級別,需要強制轉換右邊數據類型;- 整型常量賦值給
byte
、short
、char
、int
、long
時,超過類型最大值,超過需要強轉。
二、對象包裝器
1、包裝器類
有時,需要將 int 這樣的基本類型轉換為對象。所有的基本類型都有一個與之對應的類。例如,Integer 類對應基本類型 int。通常,這些類稱為包裝器(wrapper)。這些對象包裝器類擁有很明顯的名字:Integer、Long、Float、Double、Short、Byte、Character、Void 和 Boolean(前6個類派生于公共的超類Number)。對象包裝器類是不可變的,即一旦構造了包裝器,就不允許更改包裝在其中的值。同時,對象包裝器類還是 final,因此不能定義它們的子類。
假設想定義一個整型數組列表。而尖括號中的類型參數不允許是基本類型,也就是說,不允許寫成 ArrayList<int>
。這里就用到了 Integer 對象包裝器類。我們可以聲明一個 Integer 對象的數組列表。
警告:由于每個值分別包裝在對象中,所以 ArrayList<Integer>
的效率遠遠低于 int[ ]
數組。因此,應該用它構造小型集合,其原因是此時程序員操作的方便性要比執行效率更加重要。
2、自動拆/裝箱
幸運的是,有一個很有用的特性,從而更加便于添加 int 類型的元素到 ArrayList<Integer>
中。這個調用 list.add(3);
將自動變換成 List.add(Integer.valueOf(3));
。相反地,當將一個 Integer 對象賦給一個 int 值時,將會自動地拆箱。也就是說,編譯器將語句 int n = list.get(i);
翻譯成 int n = list.get(i).intValue();
。甚至在算術表達式中也能夠自動地裝箱和拆箱。例如,可以將自增操作符應用于一個包裝器引用。
大多數情況下,容易有一種假象,即基本類型與它們的對象包裝器是一樣的,只是它們的相等性不同。大家知道,== 運算符也可以應用于對象包裝器對象,只不過檢測的是對象是否指向同一個存儲區域,因此,下面的比較通常不會成立:
Integer a = 1000;
Integer b = 1000;
if(a==b){...}
然而,Java 實現卻有可能(may)讓它成立。如果將經常出現的值包裝到同一個對象中,這種比較就有可能成立。這種不確定的結果并不是我們所希望的。解決這個問題的辦法是在兩個包裝器對象比較時調用 equals 方法。
Ps:自動裝箱規范要求 boolean、byte、char ≤ 127,介于 -128~127 之間的 short 和 int 被包裝到固定的對象中。例如,如果在前面的例子中將 a 和 b 初始化為 100,對它們進行比較的結果一定成立。
關于自動裝箱還有幾點需要說明:
- 首先,由于包裝器類引用可以為 null,所以自動裝箱有可能會拋出一個 NullPointerException 異常;
- 另外,如果在一個條件表達式中混合使用 Integer 和 Double 類型,Integer 值就會拆箱,提升為 double,再裝箱為 Double;
- 最后,裝箱和拆箱是編譯器認可的,而不是虛擬機。編譯器在生成類的字節碼時,插入必要的方法調用。虛擬機只是執行這些字節碼。
3、大數值
如果基本的整數和浮點數精度不能夠滿足需求,那么可以使用 java.math 包中的兩個很有用的類:BigInteger 和 BigDecimal。這兩個類可以處理包含任意長度數字序列的數值。BigInteger 類實現了任意精度的整數運算,BigDecimal 實現了任意精度的浮點數運算。使用靜態的 valueOf 方法可以將普通的數值轉換為大數值:BigInteger a = BigInteger.valueOf(100);
。
遺憾的是,不能使用人們熟悉的算術運算符(如:+和*)處理大數值。而需要使用大數值類中的 add 和 multiply 方法。
三、字符串
從概念上講,Java 字符串就是 Unicode 字符序列。例如,串 Java\u2122
由 5 個 Unicode 字符 J、a、v、a 和 TM。Java 沒有內置的字符串類型,而是在標準 Java 類庫中提供了一個預定義類,很自然地叫做 String。每個用雙引號括起來的字符串都是 String 類的一個實例。
1、String 類常用的 api
Java 中的 String 類包含了 50 多個方法。令人驚訝的是絕大多數都很有用,可以設想使用的頻繁非常高。下面的匯總了一部分最常用的方法。
方法名 | 方法說明 | 方法名 | 方法說明 |
---|---|---|---|
length() | 獲取字符串的長度 | charAt(int index) | 返回下標所在的cha值(字符) |
equals(String s) | 判斷兩個字符串內容是否相同 | equalsIgnoreCase(String s) | 不區分大小寫判斷兩個字符串內容是否相同 |
indexOf(String s) | 返回字串第一次出現的位置,沒出現則返回-1 | lastIndexOf(String s) | 返回字串最后一次出現的位置,沒出現返回-1 |
starstWith(String prefix) | 判斷字符串是否以prefix為前綴開頭 | endsWith(String suffix) | 判斷字符串是否以suffix為后綴結尾 |
toLowerCase() | 返回字符串的小寫形式 | toUpperCase() | 返回字符串的大寫形式 |
substring(int startindex,int endindex) | 返回從startindex開始到endindex結束的字串 | contains(String s) | 判斷是否包含字串s |
replaceAll(String oldSrt,String newSrt) | 替換原有字符串中的字串為目標字串 | concat(String s) | 字符串拼接,相當于+ |
split(String split) | 以指定字符串分割后返回字符串數組 | tirm() | 返回字符串兩邊消除空格后的字符串 |
getBytes() | 返回字符串的字節數組 | isEmpty() | 判斷字符串是否為空 |
tocharArray() | 將此字符串轉換為一個新的字符數組 | compareTo | 將字符串與另一個對象進行比較 |
hashCode() | 返回字符串的哈希值 |
2、StringBuffer、StringBuilder
String 使用數組存儲字符串的內容,數組使用關鍵詞 final 修飾,因此數組內容不可變,使用 String 定義的字符串的值也是不可變的,因此每次對 String 的修改操作都會創建新的 String 對象,導致效率低下且占用大量內存空間。
StringBuffer 和 StringBuilder 都是 AbstractStringBuilder 的子類,同樣使用數組存儲字符串的內容,由于數組沒有使用關鍵詞 final 修飾,因此數組內容可變,StringBuffer 和 StringBuilder 都是可變類型,可以對字符串的內容進行修改,且不會因為修改而創建新的對象。
在需要經常對字符串的內容進行修改的情況下,應使用 StringBuffer 或 StringBuilder,在時間和空間方面都顯著優于 String。
StringBuffer 對定義的方法或者調用的方法使用了關鍵詞 synchronized 修飾,而 StringBuilder 的方法沒有使用關鍵詞 synchronized 修飾。由于 StringBuffer 對方法加了同步鎖,因此其效率略低于 StringBuilder,但是在多線程的環境下,StringBuilder 不能保證線程安全,因此 StringBuffer 是更優的選擇。
四、數組
數組是一種數據結構,用來存儲同一類型值的集合。通過一個整型下標可以訪問數組中的每一個值。例如,如果 a 是一個整型數組,a[i] 就是數組中下標為 i 的整數。在聲明數組變量時,需要指出數組類型(數據元素類型緊跟[])和數組變量的名字,例如:int[] a;
。
1、數組初始化以及匿名數組
數組初始化:在定義數組時只指定數組的長度,由系統自動為元素 賦初值 的方式稱作動態初始化。
格式:
數據類型[] 數組名 = new 數據類型[長度]; int[] arr = new int[4];
類型[] 數組名 = new 類型[]{元素,元素,……}; int[] arr = new int[]{1,2,3,4};
類型[] 數組名 = {元素,元素,元素,……}; int[] arr = { 1, 2, 3, 4 };
2、Arrays類 API
數組的工具類:java.util.Arrays,由于數組對象本身并沒有什么方法可以提供我們調用,但是API中提供了一個工具類Arrays供我們使用,從而可以對數據對象進行一些基本的操作。Arrays 類中的方法都是 static 修飾的靜態方法,使用的時候可以直接使用類名進行調用,而不用使用對象來調用。例如:Arrays.toString(string);
。下面的匯總了一部分最常用的方法。
方法名 | 方法說明 | 方法名 | 方法說明 |
---|---|---|---|
System.out.println(Arrays.toString(ints)); | 返回數組的字符串格式 | Arrays.sort(ints); | 數組按照升序排序 |
Arrays.sort(ints,0,4); | 排序其他用法,對指定下標范圍進行排序 | Arrays.fill(ints,1); | 給數組元素填充相同的值 |
Arrays.deepToString(ints) | 返回多維數組的字符串格式 | Arrays.equals(ints[0],ints[1])) | 比較兩個數組的元素是否相等 |
3、多維數組
多維數組將使用多個下標訪問數組元素,它適用于表示表格或更加復雜的排列形式。
二維數組定義格式:
//第一種定義格式
//相當于定義了一個3*4的二維數組,即二維數組的長度為3,二維數組中的每個元素又是一個長度為4的數組
- int[][] arr = new int[3][4];//不推薦
//第二種定義格式
//第二種方式和第一種類似,只是數組中每個元素的長度不確定,必須要new:arr[0] = new int[5];...
int[][] arr = new int[3][];
//第三種定義格式
//二維數組中定義了三個元素,這三個元素都是數組,分別為{1,2}、{3,4,5,6}、{7,8,9}
int[][] arr = {{1,2},{3,4,5,6},{7,8,9}};
二維數組內存:比如,int[][] arr = new int[3][2];
,外層數組長在內存開辟連續的 3 個大的內存空間,每一個內存空間都對應的有地址值,每一個大內存空間里又開辟連續的兩個小的內存空間。