
1、基本類型
Java的基本類型有整型、浮點(diǎn)型、字符型和布爾型。
整型:byte、short、int、long
浮點(diǎn)型:float、double
字符型:char
布爾型:boolean
a. 基本類型不是對(duì)象
b. 存儲(chǔ)在常量池中
c. 不能為null
2.基本類型的包裝類
a. java的8種基本類型都有對(duì)應(yīng)的包裝類
整型:Byte、Short、Interger、Long
浮點(diǎn)型:Float、Double
字符型:Character
布爾型:Boolean
b. 拆箱和裝箱
裝箱:將基本數(shù)據(jù)類型封裝為包裝類對(duì)象
拆箱:將包裝類中包裝的基本數(shù)據(jù)類型數(shù)據(jù)取出
Integer i = 12; // 自動(dòng)裝箱
int j = i; // 自動(dòng)拆箱
c. 自動(dòng)裝箱的內(nèi)存復(fù)用
自動(dòng)裝箱時(shí),若生成的對(duì)象值在-128~127的范圍內(nèi),生成的Integer實(shí)例化對(duì)象是由 IntegerCache.cache()方法產(chǎn)生,cache()方法會(huì)將位于-128~127范圍內(nèi)產(chǎn)生的Integer對(duì)象入池,下次使用的時(shí)候,從池中拿去,不會(huì)產(chǎn)生新的對(duì)象。
Integer a = 1;
Integer b = 1;
Integer c = 211;
Integer d = 211;
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
d. 浮點(diǎn)型精度丟失
計(jì)算機(jī)是利用二進(jìn)制計(jì)算的,我們輸入的十進(jìn)制的數(shù)會(huì)轉(zhuǎn)換成二進(jìn)制,但是有些數(shù)字不能完全轉(zhuǎn)換,只能無限接近于原本的值,因此會(huì)出現(xiàn)誤差
System.out.println(12.3 - 0.1); // 12.200000000000001
e. 精度丟失解決方法
BigDecimal不存在精度丟失的問題,經(jīng)常被運(yùn)用在金融方面。
BigDecimal a = BigDecimal.valueOf(12.3);
BigDecimal b = BigDecimal.valueOf(0.1);
System.out.println(a.subtract(b)); // 12.2
//四舍五入保留兩位小數(shù)
double c = 1.3181715;
BigDecimal d = BigDecimal.valueOf(c);
System.out.println(d.setScale(2, RoundingMode.HALF_UP)); // 1.32
3. 字符串類型
a. String對(duì)象創(chuàng)建方式
String s = "123"; // 通過字符串常量創(chuàng)建String對(duì)象
String s2 = new String("123"); // 通過構(gòu)造函數(shù)創(chuàng)建String對(duì)象
1、通過字符串常量創(chuàng)建String對(duì)象時(shí),JVM會(huì)首先檢查字符串常量池,如果該字符串已存在字符串常量池中,那么就將此字符串對(duì)象的引用地址賦給引用地址s;如果字符串常量不在常量池中,則會(huì)實(shí)例化該字符串并將其置于常量池中并將此字符串對(duì)象的地址賦值給引用s。
2、通過構(gòu)造函數(shù)創(chuàng)建對(duì)象時(shí),JVM會(huì)首先檢查字符串常量池,如果該字符串已經(jīng)存在常量池中,那么不再在字符串常量池創(chuàng)建該字符串對(duì)象,而直接堆中復(fù)制該對(duì)象的副本,然后將堆中對(duì)象的地址賦值給引用s2,如果字符串不存在常量池中,就會(huì)實(shí)例化該字符串并且將其放到常量池中,然后在堆中復(fù)制該對(duì)象的副本,然后將堆中對(duì)象的地址賦值給引用s2。
String s1 = "a";
String s2 = "a";
String s3 = new String("a");
String s4 = new String("a");
System.out.println(s1 == s2); // true
System.out.println(s1.equals(s2)); // true
System.out.println(s3 == s4); // false
System.out.println(s3.equals(s4)); // true
System.out.println(s1 == s3); // false
System.out.println(s1.equals(s3)); // true
b. intern()方法
interrn函數(shù)用于返回常量池中的某個(gè)字符串,如果常量池中已存在該字符串,則直接返回常量池中該對(duì)象的引用,否則,在常量池中加入該對(duì)象,然后返回引用。
String s5 = new String("b").intern();
String s6 = new String("b").intern();
System.out.println(s5 == s6); // true
c. StringBuilder優(yōu)化字符串拼接
在動(dòng)態(tài)拼接字符串時(shí),字符串+默認(rèn)會(huì)轉(zhuǎn)變?yōu)?code>StringBuilder的append()方法,這樣做可以減少對(duì)象的創(chuàng)建,提高系統(tǒng)性能。
(1) 使用常量字符串拼接
String s = "1" + "2"; // 常量字符串拼接的字符串也是常量,編譯期就能確定,直接入字符串常量池
String s2 = "12"; // 從常量池引用,所以s和s2指向同一個(gè)對(duì)象
System.out.println(s == s2); // true
(2) 含有變量字符串拼接
當(dāng)使用“+”連接字符串中含有變量時(shí),在運(yùn)行期才能確定。下面的字符串c可以看做以下過程獲得的
c = new StringBuilder("1").append("2").toString();
String a = "1";
String b = "2";
String c = a + b; // c指向堆中創(chuàng)建的字符串"12"
String d = "12"; // 指向棧中的常量字符串"12"
System.out.println(c == d); // false
再來看一個(gè)更加復(fù)雜的例子
String e = "1" + "2" + new String("3") + "4";
字符串e的創(chuàng)建過程等效于
e = new StringBuilder("12").append(new String("3")).append("4").toString();
若想要更深入的了解可以查看這篇文章 深入理解Java中的String(大坑)
d. 字符串類型不可變、不可被繼承
value[]被final修飾,String值不可變
String類被final關(guān)鍵字修飾,不可被繼承。
String被設(shè)計(jì)成不可變和不能被繼承的原因:
(1) 保證對(duì)象的安全性,不會(huì)被惡意修改。
(2)保證hash屬性不會(huì)頻繁變更,確保了唯一值。
(3)可以實(shí)現(xiàn)字符串常量值。
e. String、StringBuilder、StringBuffer
String:不可變
StringBuilder:可變、不同步
StringBuffer:可變、同步、相較于 StringBuilder速度較慢(加鎖的原因)
3. 面試題
a. 用效率最高的方法計(jì)算2 * 8
int a = 2 << 3; // 16
參考鏈接
深入理解Java中的String(大坑)