春眠不觉晓,Java数据类型知多少?基础牢不牢看完本文就有数了
文編|JavaBuild
哈嘍,大家好呀!我是JavaBuild,以后可以喊我鳥哥!俺滴座右銘是不在沉默中爆發,就在沉默中滅亡,一起加油學習,珍惜現在來之不易的學習時光吧,等工作之后,你就會發現,想學習真的需要擠時間,厚積薄發啦!
我們知道Java是面向對象的靜態型編程語言,在Java的世界里萬物皆對象。但我認為是萬物皆數據,世界由各種各樣數據構建起來,我們通過程序去實現數據的增刪改查、轉入轉出、加減乘除等等,不同語言的實現方式殊途同歸。
由此可見,數據對于程序語言的重要性,而在Java中用來規范數據的標準我們將其稱之為“數據類型”,這便是我們今天的Topic!
在下圖中我們將Java中的數據類型分為三個部分:基本數據類型,包裝類型,引用數據類型
基本數據類型
在Java中“boolean、char、byte、short、int、long、float 和 double”構建起了數據結構的基礎,非常重要,也是很多公司面試的高頻考點,所以,為了方便記憶,鳥哥整理了一份表格如下:
| 類型名稱 | 位數 | 字節 | 默認值 | 取值范圍 | 包裝類 | 緩存區間 |
|---|---|---|---|---|---|---|
| byte | 8 | 1 | 0 | -128 ~ 127 | Byte | -128~127 |
| short | 16 | 2 | 0 | -32768 (-2^15) ~ 32767 (2^15-1) | Short | -128~127 |
| int | 32 | 4 | 0 | -2147483648 ~ 2147483647 | Integer | -128~127 |
| long | 64 | 8 | 0L | -2^63 ~2^63 - 1 | Long | -128~127 |
| char | 16 | 2 | '\u0000' | 0~65535 | Character | 0 ~127 |
| float | 32 | 4 | 0f | 1.4e-45 ~ 3.4e+38 | Float | 無 |
| double | 64 | 8 | 0d | 4.9e-324~1.798e+308 | Double | 無 |
| boolean | 1 | false | true(1),false(0) | Boolean | 無 |
字節與位的關系
在計算機的物理存儲中,一條電路線被稱之為1位,二進制識別中為0(低電平)或1(高電平),英文中用bit表示,而8個bit組成一個字節,英文為Byte
布爾類型的說明
對于 boolean,官方文檔未明確定義,它依賴于 JVM 廠商的具體實現。邏輯上理解是占用 1 位,但是實際中會考慮計算機高效存儲因素。
基本數據類型之間的轉換規則
基本數據類型之間也存在著轉換關系,往往發生在表達式計算的過程中,而這種轉換根據不同場景分為:自動類型轉換&強制類型轉換
自動類型轉換:Java編譯器無需顯示處理,一般由等級低的數據類型向等級高的數據類型轉換,如int -> long。很明顯,int所能存儲的數據必定是long的子集,不存在數據丟失問題。
等級由低到高
byte -> short -> int -> long -> float -> double
char -> int -> long -> float -> double
int a = 3;
double b = 1.5;
// 自動類型轉換:a 被轉換為 double 類型
double result = a * b;
System.out.println("結果: " + result); // 輸出:結果: 4.5
強制類型轉換:由高等級數據轉為低等級數據時往往存在強制類型轉換,這時候Java編譯器認為存在隱患,需要程序員介入,顯示的處理強轉,潛在風險是數據丟失或精度丟失。
由左到右需要強轉
double -> float -> long -> int -> char -> short -> byte
double c = 10.1;
// 強制類型轉換:將 double 類型轉換為 int 類型,精度丟失
int d = (int) c;
System.out.println("整數值: " + d); // 輸出:整數值: 10
轉換規則如下
= 右邊先自動轉換成表達式中*的數據類型,再進行運算。整型經過運算會自動轉化最低 int 級別,如兩個 char 類型的相加,得到的是一個 int 類型的數值。
= 左邊數據類型級別 大于 右邊數據類型級別,右邊會自動升級
= 左邊數據類型級別 小于 右邊數據類型級別,需要強制轉換右邊數據類型
char 與 short,char 與 byte 之間需要強轉,因為 char 是無符號類型
包裝類型
這八種基本類型都有對應的包裝類分別為:Byte、Short、Integer、Long、Float、Double、Character、Boolean 。
因為Java中一切皆對象,基本數據類型無法滿足這個大口號,比如泛型、序列化、類型轉換、高頻數據區間的緩存等,故為了彌補,便誕生了8種基本數據類型對應的包裝類型。
包裝類型與基本數據類型差異
- 使用場景: 在Java中除了一些常量和局部變量的定義會用到基礎數據類型外,絕大部分情況下均采用包裝類型,如方法參數,對象屬性等,且基本數據類型不能用于泛型,包裝類型可以!
- 默認值: 包裝類型比基本類型多了一個非功能值:null,在不做任何賦值的情況下,包裝類型的默認就是null,而基本數據類型都有相應的默認值,見上面表格。
- 所占內存 因為包裝類型是對象,會有一些對象頭等信息,所以占用空間上要大于基本數據類型。
- 比較方式 基本類型采用 == 號比較,比較的是值,而對于包裝類型來說,==比較的其實是對象的內存地址,對象值的比較需要通過equals()方法完成。
[注意]: 很多同學都以為基本數據類型存在棧中,包裝類型作為對象存儲在堆中,這個觀點是有失偏頗的,如果基礎數據類型的成員變量在沒有被static關鍵字修飾的情況下,是存在的堆中的,只有局部變量被存在棧的局部變量表中!而全部對象都存在堆中,也是個不完整的答案,這里涉及到HotSpot中的逃逸分析,等講到JVM時再展開說吧。
自動裝箱與拆箱
在Java中不僅僅基本類型之間存在著轉換,基本數據類型與包裝類型之間同樣存在著轉換,在JDK1.5之前是不支持自動裝箱與拆箱的,所以那時候需要通過顯示的方法調用來實現轉換,而JDK1.5開始,自動化程度提升了。
裝箱:基本類型轉變為包裝器類型的過程。
拆箱:包裝器類型轉變為基本類型的過程。
//JDK1.5之前是不支持自動裝箱和自動拆箱的,定義Integer對象,必須
Integer i = new Integer(8);
//JDK1.5開始,提供了自動裝箱的功能,定義Integer對象可以這樣
Integer i = 8;
int n = i;//自動拆箱
實現原理
裝箱是通過調用包裝器類的 valueOf 方法實現的
拆箱是通過調用包裝器類的 xxxValue 方法實現的,xxx代表對應的基本數據類型。
如int裝箱的時候自動調用Integer的valueOf(int)方法;Integer拆箱的時候自動調用Integer的intValue方法。
【需要注意的問題點】:
1、整型的包裝類 valueOf 方法返回對象時,在常用的取值范圍內,會返回緩存對象。
2、浮點型的包裝類 valueOf 方法返回新的對象。
3、布爾型的包裝類 valueOf 方法 Boolean類的靜態常量 TRUE | FALSE。
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1 == i2);//true
System.out.println(i3 == i4);//false
Double d1 = 100.0;
Double d2 = 100.0;
Double d3 = 200.0;
Double d4 = 200.0;
System.out.println(d1 == d2);//false
System.out.println(d3 == d4);//false
Boolean b1 = false;
Boolean b2 = false;
Boolean b3 = true;
Boolean b4 = true;
System.out.println(b1 == b2);//true
System.out.println(b3 == b4);//true
以上代碼中,我們已Integer為例展開解釋一下,基本數據類型的包裝類除了 Float 和 Double 之外,其他六個包裝器類(Byte、Short、Integer、Long、Character、Boolean)都有常量緩存池。而Integer的緩存區間是-128~127。
我們去看一下Integer類的緩存源碼
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
private static class IntegerCache {
static final int low = -128;
static final int high;
static {
// high value may be configured by property
int h = 127;
}
}
IntegerCache 這個靜態內部類中設置了緩存區間,當我們通過valueOf()方法獲取Integer對象時,會先去找該整數是否在緩存池中,有則直接返回,沒有則新建并存入緩存池。
這就解釋了為什么第一個 == 號結果是true,而第二個為false,因為超出了緩存區間,每次都新建一個對象,而 == 號又是比較對象地址,對于兩個不同的對象,地址肯定不一樣啦。
引用數據類型
Java的數據類型除了8種基本數據類型和對應的包裝類型外,還有一個分類為引用數據類型,在文章開頭的樹形圖中已經分好,引用類型分為:數組,類和接口。
那為什么叫他引用數據類型呢?在創建引用數據類型時,會在棧上給其引用句柄,分配一塊內存,然后對象的信息存儲在堆上,在程序調用的時候,通過棧上的引用句柄指向堆中的對象,從而獲取想要的數據。
因數組,類,接口都包含著太多內容,在后續的博客中會陸續詳解,所以本文略做介紹,粗略感受一下。
數組:
int [] arrays = {1,2,3};
System.out.println(arrays);
// 打印結果:[I@2d209079
打印結果中的一串內容,世界上是arrays的對象首地址,要想看到結果,需要調用java.lang.Object 類的 toString() 方法。
類:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
String是一個類,也是字符串的代表,所以它也是引用數據類型
接口:
List<String> list = new ArrayList<>();
System.out.println(list);
List 是一個非常典型的接口,屬于Java的一種集合,存儲的元素是有序的、可重復的。
【注意】
1、包裝類可以實現基本類型和字符串之間的轉換,字符串轉基本類型:parseXXX(String s);基本類型轉字符串:String.valueOf(基本類型)。
2、引用數據類型的默認值為 null,包括數組和接口。
3、char a = 'h'char :單引號,String a = "hello" :雙引號。
總結
以上是生活随笔為你收集整理的春眠不觉晓,Java数据类型知多少?基础牢不牢看完本文就有数了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 聊一聊如何整合Microsoft.Ext
- 下一篇: Python 潮流周刊第 35 期(摘要