一、常量與變量
1.1.常量修飾符用final,字母大寫,立即賦值茎芭,且不允許在修改
1.2變量可以隨時(shí)修改
二牧牢、數(shù)據(jù)類型
2.1原始數(shù)據(jù)類型(8個(gè))
2.1.1整數(shù)類型? :有符號(hào)看锉,分正負(fù)
byte:1個(gè)字節(jié),8bit, -2^7 ~ 2^7-1 ,-128~ 127
short:2個(gè)字節(jié)塔鳍,16bit伯铣,-2^15 ~ 2^15-1,-32768~32767
int:4個(gè)字節(jié)轮纫,32bit腔寡,-2^31 ~ 2^31-1,-2147....~2147....
long:8個(gè)字節(jié)掌唾,64bit放前,-2^63 ~ 2^63-1,-2147....~2147....
注:
1.整數(shù)取值范圍 byte->short->int->long糯彬,類型和賦值時(shí)設(shè)計(jì)類型轉(zhuǎn)換
2. 對(duì)于short?s1?=?1;?s1?=?s1?+?1;?由于s1+1運(yùn)算時(shí)會(huì)自動(dòng)提升表達(dá)式的類型凭语,所以結(jié)果是int型,再賦值給short類型s1時(shí)撩扒,編譯器將報(bào)告需要強(qiáng)制轉(zhuǎn)換類型的錯(cuò)誤似扔。對(duì)于short?s1?=?1;?s1?+=?1;由于?+=?是java語言規(guī)定的運(yùn)算符,java編譯器會(huì)對(duì)它進(jìn)行特殊處理,因此可以正確編譯炒辉。
精度小于int的數(shù)值運(yùn)算的時(shí)候都回被自動(dòng)轉(zhuǎn)換為int后進(jìn)行計(jì)算
3. long a=323482942934(超過整型最大值必須加L或l);
2.1.2浮點(diǎn)類型
用于保存小數(shù)豪墅,分單精度float和雙精度double.
1.float a=2.1231f ; double b=12.23d;當(dāng)為float時(shí),必須加f辆脸,因?yàn)槟J(rèn)小數(shù)值為double類型但校,而且d或D可省略,同樣遵從類型轉(zhuǎn)換規(guī)則啡氢,整型的可以賦值給浮點(diǎn)類型
2.float為整數(shù)+小數(shù)=4字節(jié)=32bit状囱,double為整數(shù)+小數(shù)=8字節(jié)=64bit
float:整數(shù)位數(shù)+小數(shù)位數(shù)=8位;double位 16位長(zhǎng)度
float的小數(shù)點(diǎn)后6位倘是,double的小數(shù)點(diǎn)后16位亭枷。
2.1.3字符類型
1.保存字母符號(hào)、數(shù)字符號(hào)搀崭、標(biāo)點(diǎn)符號(hào)和其他符號(hào)叨粘,單個(gè)字符占2個(gè)字節(jié)。字符-->映射成整型-->在轉(zhuǎn)成二進(jìn)制瘤睹,才能被計(jì)算機(jī)識(shí)別升敲,這種映射叫字符編碼。java中對(duì)字符采用unicode編碼轰传,使用2個(gè)字節(jié)標(biāo)識(shí)1個(gè)字符驴党,一共可以存儲(chǔ)65536個(gè)字符,且其前128個(gè)字符和ASCII嗎字符集兼容获茬,如 a,它的ASCII碼的二進(jìn)制是011000001港庄,它的unicode是00000011000001,都是十進(jìn)制的97恕曲。
轉(zhuǎn)義字符 如\n,\t等
2.1.4布爾類型 boolean?
三鹏氧、類型轉(zhuǎn)換
3.1不同類型轉(zhuǎn)換:自動(dòng)類型轉(zhuǎn)換和強(qiáng)制類型轉(zhuǎn)換
3.1.1自動(dòng)類型轉(zhuǎn)換:byte->short (char) ->int -> long ->float ->double (低到高)
a.高位轉(zhuǎn)低位需要強(qiáng)制轉(zhuǎn)換,低位轉(zhuǎn)高位自動(dòng)轉(zhuǎn)成參與運(yùn)算的最高類型
byte/char/chort 混合運(yùn)算會(huì)轉(zhuǎn)成int類型相加佩谣,最終還是int類型把还,int/long/float轉(zhuǎn)成float類型或double類型,最終還是最高類型
例子:short s1 = 1; s1 = s1 + 1;中茸俭,1 是int 型?s1 short型 通過 + 運(yùn)算后s1?自動(dòng)轉(zhuǎn)為int 型 所以錯(cuò)
s1 += 1 復(fù)合表達(dá)式會(huì)自動(dòng)將運(yùn)算后的結(jié)果進(jìn)行類型轉(zhuǎn)換成等式左側(cè)類型吊履,不會(huì)出錯(cuò)
3.1.2強(qiáng)制類型轉(zhuǎn)換:從高到低類型轉(zhuǎn)換,需要強(qiáng)制類型轉(zhuǎn)換瓣履,且是隨機(jī)截?cái)嗦食幔皇撬纳嵛迦?/p>
int a=(int)23.5 ,最終為23练俐,運(yùn)算時(shí)也需要進(jìn)行強(qiáng)制轉(zhuǎn)換
四袖迎、運(yùn)算符與表達(dá)式
4.1算數(shù)運(yùn)算符與算數(shù)表達(dá)式(二元運(yùn)算符)
分為加、減、乘燕锥、除辜贵、余
注:
a. 除法運(yùn)算符 若兩個(gè)都是整數(shù),不管是否整除归形,都為整數(shù)托慨,且是去掉小數(shù) print(8/3),為2暇榴,除以float或double則為 其最高類型的長(zhǎng)度值
b.整數(shù)直接求余運(yùn)算中厚棵,結(jié)果為余數(shù)print(8%3),結(jié)果為2
c.除法預(yù)算中蔼紧,0做除數(shù)會(huì)報(bào)錯(cuò)
4.2賦值運(yùn)算符與賦值表達(dá)式(二元運(yùn)算符婆硬,相對(duì)于操作數(shù)而言)
+=屬于復(fù)合賦值運(yùn)算符,會(huì)自動(dòng)強(qiáng)轉(zhuǎn)類型奸例,short s1=1;s1+=1;不會(huì)錯(cuò)
4.3自增和自減運(yùn)算符(一元運(yùn)算符)
++i彬犯,--i:先自增,后賦值查吊,比如int i=0; int m=++i; 輸出1
i++谐区,i--:先賦值,后自增逻卖,比如int i=0; int m=i++; 輸出0
4.4關(guān)系運(yùn)算符和關(guān)系表達(dá)式
== 和 !=
4.5邏輯運(yùn)算符合邏輯表達(dá)式
與(&宋列,&&)、或(|和||)箭阶、異或(^)虚茶、非(!)
與:&&當(dāng)左側(cè)表達(dá)式為false仇参,就不在計(jì)算后邊的表達(dá)式嘹叫,&,左右兩側(cè)都要運(yùn)算
或:||當(dāng)左側(cè)為true诈乒,就不在計(jì)算右邊的表達(dá)式罩扇,|,左右兩側(cè)都要計(jì)算
異或:當(dāng)兩側(cè)為true和false時(shí)為true怕磨,相同是為false
4.6位運(yùn)算符
對(duì)操作數(shù)以二進(jìn)制為單位進(jìn)行的運(yùn)算喂饥,運(yùn)算結(jié)果為整數(shù)。操作數(shù)->二進(jìn)制,二進(jìn)制位運(yùn)算高职,轉(zhuǎn)整數(shù)亥贸。
&:按位&與運(yùn)算 101&110=100 (二元)
|:按位或運(yùn)算 101|110=111??(二元)
^:按位異或運(yùn)算 101^110=011(二元)
~:按位取反運(yùn)算? ~101=010(一元)
<<:左移位運(yùn)算? (十進(jìn)制)5<<1 = 101(二進(jìn)制)<<1=1010(二進(jìn)制)= 5*2=10(十進(jìn)制) 相當(dāng)于乘以2^(n)方
>>:右移位運(yùn)算(帶符號(hào)) (十進(jìn)制)5>>1 = 101(二進(jìn)制)>>1=(二進(jìn)制)= 5/2=2(十進(jìn)制) 相當(dāng)于除以2^n方,左邊空位補(bǔ)0 (待符號(hào)位捞高,負(fù)數(shù)補(bǔ)1氯材,正數(shù)補(bǔ)0)
>>>:無符右移位運(yùn)算:
4.7三元運(yùn)算符
a > b? ?a :? b
五硝岗、經(jīng)典試題
5.1 ==號(hào)和equals()
區(qū)別:==號(hào)在比較基本數(shù)據(jù)類型時(shí)比較的是值氢哮,而用==號(hào)比較兩個(gè)對(duì)象時(shí)比較的是兩個(gè)對(duì)象的地址值。
equals是Object的方法型檀,沒有重寫時(shí)冗尤,底層調(diào)用==,但是大多數(shù)進(jìn)行了重寫胀溺,用于比較值
比如:String sm =new String("abc"); String sn =new String("abc"); System.out.println(sm.equals(sn)); System.out.println(sm ==sn); 返回了true,false裂七。因?yàn)镾tring 類重寫了equals 判斷兩個(gè)值,而==判斷的是引用仓坞。
但對(duì)于: String s1 = "abc";String s2 ="abc";System.out.println(s1.equals(s2));System.out.println(s1 == s2); 返回了true,true碍讯。因?yàn)閷儆诔A砍兀刂芬粯印?/p>
5.2 Java數(shù)據(jù)類型的存儲(chǔ)位置:
基本數(shù)據(jù)類型在被創(chuàng)建時(shí)扯躺,在棧上給其劃分一塊內(nèi)存捉兴,將數(shù)值直接存儲(chǔ)在棧上;
引用數(shù)據(jù)類型在被創(chuàng)建時(shí)录语,首先要在棧上給其引用(句柄)分配一塊內(nèi)存倍啥,而對(duì)象的具體信息都存儲(chǔ)在堆 內(nèi)存上,然后由棧上面的引用指向堆中對(duì)象的地址
5.3 Java數(shù)據(jù)類型的比較:
基礎(chǔ)數(shù)據(jù)類型的比較只能使用==號(hào)澎埠,比的是數(shù)據(jù)的值虽缕,而不能使用equals;引用類型兩個(gè)都可以蒲稳,當(dāng)使用 ==比較的是內(nèi)存地址氮趋,使用equals比較的是堆內(nèi)存里面的內(nèi)容
拆裝箱:
裝箱就是把byte ,int 江耀,short剩胁, long ,double祥国,float昵观,boolean,char 這些Java的基本數(shù)據(jù)類型在定義數(shù)據(jù)類型時(shí)不聲明為相對(duì)應(yīng)的引用類型舌稀,在編譯器的處理下自動(dòng)轉(zhuǎn)化為引用類型的動(dòng)作就叫做裝箱啊犬。
拆箱就是把Long,Integer壁查,Double觉至,F(xiàn)loat 等將基本數(shù)據(jù)類型的首字母大寫的相應(yīng)的引用類型轉(zhuǎn)化為基本數(shù)據(jù)類型的動(dòng)作就叫拆箱。
拆裝箱的性能:
盡管Java編譯器能夠幫組我們自動(dòng)進(jìn)行相應(yīng)基本數(shù)據(jù)與引用類型的相互轉(zhuǎn)化睡腿,但是不太建議編程中大量使 用语御,因?yàn)榇嬖诙无D(zhuǎn)化领斥,考慮性能。
盡量避免基礎(chǔ)類型與引用類型的自動(dòng)拆裝箱沃暗,損耗性能
避免 Integer integer = 10;起碼得是Integer integer = new Integer(10);
盡量不要用Integer.valueOf(String str);而要用Integer.parseInt(String str)
Integer.valueOf()把String 型轉(zhuǎn)換為Integer對(duì)象何恶。因此在int countNum = ? 的情況下用Integer.parseInt() 很好的孽锥,直接變成int類型的值,而不用再拆箱變成基礎(chǔ)類型了细层。
Integer.parseInt()把String 型轉(zhuǎn)換為Int型惜辑,
就是說Integer.valueOf(S)是針對(duì)包裝類來說的,而Integer.parseInt(s) 是針對(duì)變量而言
5.4 實(shí)例
5.4.1?
Integer f1=new Integer(3);
Integer f2=3;
int f3=3;
System.out.println(f1 ==f2); //false 兩個(gè)引用類型疫赎,==比較的內(nèi)存地址盛撑,不同
System.out.println(f2 ==f3); //true 引用類型,會(huì)將引用類型拆箱成int在和c比較
System.out.println(f1 ==f3); //true 引用類型捧搞,會(huì)將引用類型拆箱成int在和c比較
5.4.2
Integer f1=127,f2=127,f3=128,f4=128;
System.out.println(f1 ==f2); //true??IntegerCache 在
System.out.println(f3 ==f4); //false?
IntegerCache : 簡(jiǎn)單的說抵卫, 如果整型字面量的值在-128 到 127 之間,那么不會(huì) new 新的 Integer 對(duì)象胎撇,而是直接引用常量池中的Integer 對(duì)象
5.4.3 &和&&的區(qū)別介粘?
&運(yùn)算符有兩種用法: (1)按位與; (2)邏輯與晚树。 &&運(yùn)算符是短路與運(yùn)算姻采。邏輯與跟短
路與的差別是非常巨大的,雖然二者都要求運(yùn)算符左右兩端的布爾值都是true 整個(gè)表達(dá)式
的值才是true爵憎。 &&之所以稱為短路運(yùn)算是因?yàn)榭祝绻?amp;&左邊的表達(dá)式的值是 false,右邊
的表達(dá)式會(huì)被直接短路掉宝鼓,不會(huì)進(jìn)行運(yùn)算刑棵。很多時(shí)候我們可能都需要用&&而不是&,例如
在驗(yàn)證用戶登錄時(shí)判定用戶名不是 null 而且不是空字符串愚铡,應(yīng)當(dāng)寫為: username != null
&&!username.equals("")铐望,二者的順序不能交換,更不能用&運(yùn)算符茂附,因?yàn)榈谝粋€(gè)條件如果
不成立正蛙,根本不能進(jìn)行字符串的equals 比較,否則會(huì)產(chǎn)生 NullPointerException 異常营曼。注意:
邏輯或運(yùn)算符(|)和短路或運(yùn)算符(||)的差別也是如此乒验。
5.4.4String理解
java為字符串常量在字符串緩沖池中分配內(nèi)存:
? (1) 池中常量?jī)?nèi)存空間只讀不寫
? ?(2)池中字符串常量不重復(fù),相同的字符串為同一內(nèi)存空間
這也就是有道面試題:String s = new String(“xyz”);產(chǎn)生幾個(gè)對(duì)象蒂阱?一個(gè)或兩個(gè)锻全,如果常量池中原來沒有”xyz”,就是兩個(gè)狂塘。如果常量池中已有“xyz”則只是new String創(chuàng)建一個(gè)對(duì)象;如果常量池中沒有“xyz”鳄厌,則要在常量池創(chuàng)建一個(gè)荞胡,new String創(chuàng)建一個(gè),這樣就是兩個(gè)了嚎。
例如:
String s1="ab"; ? //在池中分配一塊內(nèi)存用于存放常量"ab"
?String s2="ab"; ? //由于池中存在"ab"泪漂,引用變量a指向存在的"ab"內(nèi)存空間首地址。所以s1和s2指向同一池中"ab"的內(nèi)存空間
String s3="a";//在池中新分配一塊內(nèi)存用于存放常量"a"
String s4="a"+"b";//在池中新分配用于存放"b"的臨時(shí)內(nèi)存,合并將池中的"a"和"b"為"ab"歪泳,因"ab"已存在萝勤,所以不再新分配內(nèi)存,將已存在的"ab"內(nèi)存地址賦值給引用變量s4.
String s5=s3+"b"; ?//引用變量和字符常量"b"連接運(yùn)行呐伞,在堆區(qū)分配一塊內(nèi)存存放合并后的"ab",并將其首地址賦值給引用變量d
String e=new String("ab"); ?//在堆區(qū)分配一塊內(nèi)存存放"ab",并將其首地址賦值給引用變量e.
String 類型的引用變量直接判斷“==”,比較的是引用變量其在棧內(nèi)存的內(nèi)容敌卓,即變量指向的字符串常量實(shí)例內(nèi)存的首地址。
若要判斷其指向的實(shí)例內(nèi)容是否相等伶氢,需要使用equals方法完成趟径。
5.4.5? String s =new String()分析堆與棧 創(chuàng)建了幾個(gè)對(duì)象
5.4.5.1
String str1 = “abc”;
System.out.println(str1 == “abc”);
步驟:
1) 棧中開辟一塊空間存放引用str1,
2) String池中開辟一塊空間癣防,存放String常量”abc”舵抹,
3) 引用str1指向池中String常量”abc”,
4) str1所指代的地址即常量”abc”所在地址劣砍,輸出為true
5.4.5.2
String str2 = new String(“abc”);
System.out.println(str2 == “abc”);
步驟:
1) 棧中開辟一塊空間存放引用str2惧蛹,
2) 堆中開辟一塊空間存放一個(gè)新建的String對(duì)象”abc”,
3) 引用str2指向堆中的新建的String對(duì)象”abc”刑枝,
4) str2所指代的對(duì)象地址為堆中地址香嗓,而常量”abc”地址在池中,輸出為false
5.4.5.3
String str3 = new String(”abc”);
System.out.println(str3 == str2);
步驟:
1) 棧中開辟一塊空間存放引用str3装畅,
2) 堆中開辟一塊新空間存放另外一個(gè)(不同于str2所指)新建的String對(duì)象靠娱,
3) 引用str3指向另外新建的那個(gè)String對(duì)象
4) str3和str2指向堆中不同的String對(duì)象,地址也不相同掠兄,輸出為false
5.4.5.4
String str4 = “a” + “b”;
System.out.println(str4 == “ab”);
步驟:
1) 棧中開辟一塊空間存放引用str4像云,
2) 根據(jù)編譯器合并已知量的優(yōu)化功能,池中開辟一塊空間蚂夕,存放合并后的String常量”ab”迅诬,
3) 引用str4指向池中常量”ab”,
4) str4所指即池中常量”ab”婿牍,輸出為true
5.4.5.5
final String s = “a”;
String str5 = s + “b”;
System.out.println(str5 == “ab”);
步驟:
同4
String s1 = “a”;
String s2 = “b”;
String str6 = s1 + s2;? 當(dāng)有引用類型+時(shí)侈贷,會(huì)new新的對(duì)象,如果都是常量"a"+"b"則為常量值
System.out.println(str6 == “ab”);
步驟:
1) 棧中開辟一塊中間存放引用s1等脂,s1指向池中String常量”a”俏蛮,
2) 棧中開辟一塊中間存放引用s2撑蚌,s2指向池中String常量”b”,
3) 棧中開辟一塊中間存放引用str5搏屑,
4) s1 + s2通過StringBuilder的最后一步toString()方法還原一個(gè)新的String對(duì)象”ab”争涌,因此堆中開辟一塊空間存放此對(duì)象,
5) 引用str6指向堆中(s1 + s2)所還原的新String對(duì)象辣恋,
6) str6指向的對(duì)象在堆中亮垫,而常量”ab”在池中,輸出為false
5.4.5.6
String str7 = “abc”.substring(0, 2);
步驟:
1) 棧中開辟一塊空間存放引用str7抑党,
2) substring()方法還原一個(gè)新的String對(duì)象”ab”(不同于str6所指),堆中開辟一塊空間存放此對(duì)象撵摆,
3) 引用str7指向堆中的新String對(duì)象底靠,
String str8 = “abc”.toUpperCase();
步驟:
1) 棧中開辟一塊空間存放引用str6,
2) toUpperCase()方法還原一個(gè)新的String對(duì)象”ABC”特铝,池中并未開辟新的空間存放String常量”ABC”暑中,
3) 引用str8指向堆中的新String對(duì)象
注意:字符串的+操作其本質(zhì)是創(chuàng)建了 StringBuilder 對(duì)象進(jìn)行 append 操
作,然后將拼接后的 StringBuilder 對(duì)象用 toString 方法處理成 String 對(duì)象鲫剿,這一點(diǎn)可以用
javap -c StringEqualTest.class 命令獲得 class 文件對(duì)應(yīng)的 JVM 字節(jié)碼指令就可以看出來鳄逾。
String.intern()方法就是把該對(duì)象放進(jìn)常量池,變成常量池對(duì)象
````
//測(cè)試String對(duì)象創(chuàng)建情況
String aname="a";
String bname=aname;
aname="b";
String lisi=new String("b");
System.out.println(aname);
System.out.println(bname);
System.out.println(bname==aname);
System.out.println(aname==lisi);
System.out.println(aname==lisi.intern());
````
打印結(jié)果:false灵莲、false雕凹、true
1.equals比較的值,因?yàn)镾tring對(duì)其進(jìn)行了值比較的重寫
2.過程分析: