Java數據類型分為基本數據類型與引用數據類型。
1 基本數據類型
byte:Java中最小的數據類型,在內存中占1個字節(8 bit),取值范圍-128~127,默認值0
short:短整型,2個字節(16 bit),取值范圍-32768~32717,默認值0
int:整型,用於存儲整數,在內存中占4個字節,取值范圍-2147483648~2147483647,默認值0
long:長整型,在內存中占8個字節-2^63~2^63-1,默認值0L
float:浮點型,在內存中占4個字節,用於存儲帶小數點的數字(與double的區別在於float類型有效小數點只有6~7位),默認值0
double:雙精度浮點型,用於存儲帶有小數點的數字,在內存中占8個字節,默認值0
char:字符型,用於存儲單個字符,內存中占2個字節,取值范圍0~65535,默認值為空
boolean:布爾類型,占1個字節,用於判斷真或假(僅有兩個值,即true、false),默認值false
2 引用類型
Java語言本身不支持C++中的結構(struct)或聯合(union)數據類型,它的復合數據類型一般都是通過類或接口進行構造,類提供了捆綁數據和方法的方式,同時可以針對程序外部進行信息隱藏。引用類型分3種:類,接口,數組;
類(Class):所有的類,無論是Java自身已經存在的,還是用戶后來創建的;
Objec類:它是所有類的父類,每個類都實現這個類的方法;用Object 可以定義所有的類;
String:String類代表字符串,Java
接口(interface): 系統自帶或者用戶創建的
數組(array): 系統自帶或者用戶創建的
3 Java中的數據類型在內存的存儲原理
Java的數據類型存儲原理要根據其為局部變量還是成員變量來區分,局部變量與成員變量根據定義變量的位置區分:
局部變量:方法中的變量;
成員變量:類中方法外;
局部變量數據類型存儲原理:
(1) 基本數據類型的存儲原理:所有的簡單數據類型不存在“引用”的概念,基本數據類型都是直接存儲在內存中的內存棧上的,數據本身的值就是存儲在棧空間里面,Java語言里面八種數據類型是這種存儲模型;
(2) 引用類型的存儲原理:引用類型繼承於Object類(也是引用類型)都是按照Java里面存儲對象的內存模型來進行數據存儲的,使用Java內存堆和內存棧來進行這種類型的數據存儲,簡單地講,“引用”(存儲對象在內存堆上的地址)是存儲在有序的內存棧上的,而對象本身的值存儲在內存堆上的;
基本數據類型和引用類型的區別主要在於基本數據類型是分配在棧上的,而引用類型是分配在堆上的
舉例說明
我們分析一下 == 和equals()的區別
首先,定義兩個String 數組對象
String[] a={"latiny1","latiny2"};
String[] b={"latiny1","latiny2"};
然后比較
if(a==b)
{
System.out.println("a==b");
}
else
{
System.out.println("a!=b");
}
程序輸出a!=b
原因:a和b的地址是不相同的,a==b比較的是兩個變量的地址,數據a與b的地址不一樣
對於局部變量來說,不論是基本數據類型還是引用類型,他們都會先在棧中分配一塊內存,對於基本類型來說,這塊區域包含的是基本類型的內容;而對於引用類型來說,這塊區域包含的是指向真正內容的指針,真正的內容被手動的分配在堆上。
對於成員變量來說,不論是基本數據類型還是引用類型,他們都會存儲在堆內存或者方法區中;成員變量可細分為靜態成員變量和普通成員變量,靜態成員變量類屬於類,類可以直接訪問,存儲在方法區中;普通成員變量屬於類對象,必須聲明對象之后,通過對象才能訪問,存儲在堆中。
4 基本類型轉換
(1)自動類型轉換
Java所有的數值類型變量都可以互相轉換,如果系統把某種基本類型的值直接賦給另一種基本類型的變量,則這種方式被稱為自動類型轉換。
int e = 1;
double d =e;
以上代碼不會報錯,系統會自動轉換。
(2) 強制類型轉換
當把一個范圍大的數值或變量賦給另一個范圍小的變量時,需要進行強制轉換。
double d =1.5;
int e = d;
以上代碼會報錯,把大范圍的數值賦給小范圍的變量,需要強制轉換,這樣才能通過編譯,且大范圍的數值會丟失精度。
int e = (int) d;
5 == 與 equals 方法
判斷兩個變量是否相等有兩種方式:一種是利用 == 運算符,另一種是利用equals方法。
① 比較java基本類型:
比較基本類型只能用"==",不能用"equals",這里的"=="比較的是兩個基本類型的值;
② 比較包裝類:這里拿Integer,Character 來舉例
1 2 Character a = new Character('A'); 3 Character b = new Character('A'); 4 5 System.out.println(a == b); 6 System.out.println(a.equals(b)); 7 8 Integer i1 = new Integer(10); 9 Integer i2 = new Integer(10); 10 11 System.out.println(i1 == i2); 12 System.out.println(i1.equals(i2));
輸出結果:
false
true
false
true
這邊"=="比較的是對象的內存地址,new了兩個不同的對象所存放的地址是不一樣的,這邊的"equals"比較的就是值,這里為什么比較的是值呢,equals里的重寫了equals的方法。附上源碼:
1 public boolean equals(Object obj) { 2 if (obj instanceof Integer) { 3 return value == ((Integer)obj).intValue(); 4 } 5 return false; 6 }
③ 比較String:
"=="比較的是內存地址,"equals"比較的是值
1 String s1 = "latiny"; 2 String s2 = "latiny"; 3 4 System.out.println(s1 == s2); 5 System.out.println(s1.equals(s2)); 6 7 String s3 = new String("latiny"); 8 String s4 = new String("latiny"); 9 10 System.out.println(s3 == s4); 11 System.out.println(s3.equals(s4));
輸出結果:
true true false true
補充說明:Java String 和 new String()的區別
棧區存引用和基本類型,不能存對象,而堆區存對象。==是比較地址,equals()比較對象內容。
(1) String str1 = "abcd"的實現過程:首先棧區創建str引用,然后在String池(獨立於棧和堆而存在,存儲不可變量)中尋找其指向的內容為"abcd"的對象,如果String池中沒有,則創建一個,然后str指向String池中的對象,如果有,則直接將str1指向"abcd"";如果后來又定義了字符串變量 str2 = "abcd",則直接將str2引用指向String池中已經存在的“abcd”,不再重新創建對象;當str1進行了賦值(str1=“abc”),則str1將不再指向"abcd",而是重新指String池中的"abc",此時如果定義String str3 = "abc",進行str1 == str3操作,返回值為true,因為他們的值一樣,地址一樣,但是如果內容為"abc"的str1進行了字符串的+連接str1 = str1+"d";此時str1指向的是在堆中新建的內容為"abcd"的對象,即此時進行str1==str2,返回值false,因為地址不一樣。
(2) String str3 = new String("abcd")的實現過程:直接在堆中創建對象。如果后來又有String str4 = new String("abcd"),str4不會指向之前的對象,而是重新創建一個對象並指向它,所以如果此時進行str3==str4返回值是false,因為兩個對象的地址不一樣,如果是str3.equals(str4),返回true,因為內容相同。
④ 比較對象:
這里"=="比較的是內存地址,"equals"比較的也是地址,沒有重寫equals方法的類都是調用的Object的equals的方法。
1 Person p1 = new Person(1001, "latiny1"); 2 Person p2 = new Person(1001, "latiny1"); 3 4 System.out.println(p1 == p2); 5 System.out.println(p1.equals(p2));
輸出結果:
false
false