一、==符的使
先看一段比較有趣的程式碼
Integer a = 1000,b=1000;
Integer c = 100,d=100; public void mRun(final Integer c = 100,d=100; public void mRun(final String name){ new Runnable() { public void run() { System.out.println(name); } }; }
System.out.println(a==b);
System.out.println(c==d);
如果這題你能得出正確答案,並能了解其中的原理的話。說明你基礎還可以。如果你的答案 是 true 和true的話,你的基礎就有所欠缺了。
先公佈下答案, 執行程式碼,我們會得到 false true。我們知道==比較的是兩個對象的引用,這裡的abcd都是新建出來的對象,照理說都應該輸入false才對。這就是這題的有趣之處,無論是面試題還是論壇討論區,這題的出場率都很高。原理其實很簡單,我們去看下Integer.java這個類別就了然了。
public static Integer valueOf(int i) { return i >= 128 || i 當我們宣告一個Integer c = 100;的時候。此時會進行自動裝箱操作,簡單點說,也就是把基本資料型別轉換成Integer對象,而轉換成Integer對象正是調用的valueOf方法,可以看到,Integer中把-128-127 緩存了下來。官方解釋是小的數字使用的頻率比較高,所以為了優化性能,把這之間的數緩存了下來。這就是為什麼這題的答案回事false和ture了。當宣告的Integer物件的值在-128-127之間的時候,引用的是同一個對象,所以結果是true。
二、String
接著看程式碼
String s1 = “abc”;
String s2 = “abc”;
String s3 = new String(“abc”);
System.out.print(System.
System.out.println(s1 == s3);
大家又來猜這題的答案是什麼?
依照==的語法來看, 首先s1、s2、s3是三個不同的對象,常理來說,輸出都會是false。然而程式的運行結果確實true、false。第二個輸出false可以理解,第一個輸出true就又讓人費解了。我們知道一些基本型別的變數和物件的參考變數都是在函數的堆疊記憶體中分配,而堆疊記憶體中則存放new 出來的物件和陣列。然而除此之外還有一塊區域叫做常量池。
像我們通常想String s1 = “abc”; 這樣申明的字串對象,其值就是儲存在常數池中。當我們建立String s1 = “abc”這樣一個物件之後,”abc”就儲存到了常數池(也可叫做字串池)中,當我們建立引用String s2 = “abc” 的時候,Java底層會優先在常量池中查找是否存在”abc”,如果存在則讓s2指向這個值,不會重新創建,如果常量池中沒有則創建並添加的池中。這就是為什麼答案是true 和false的原因。
三、final關鍵字
還是來看一段程式碼
public void mRun(final String name){ new Runnable() { public void run() { try { Thread.sleep(1000); } catch (InterruptedException); { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(name); } }.start(); }
這種程式碼相信大家寫過很多,當內部類別存取局部變數的時候,需要在局部變數前面加上final修飾符,不然編譯器就會報錯。通常我們也是這麼幹的。好的,第二個問題來了,為什麼要加final修飾符?相信大多數小夥伴都沒有思考過這個問題,但凡使用的時候,直接加上就得了,從來沒去深究過其中的原理。這對一個優秀的程式設計師來說是不可取,我們不只要知其然還要知其所以然。
現在我們來分析一下,為什麼要加final關鍵字。首先內部類別的生命週期是成員層級的,而局部變數的生命週期實在方法體之類。也就是說會出現這樣一種情況,當mRun方法執行,new 的執行緒運行,新執行緒裡面會睡一秒。主執行緒會繼續執行,mRun執行完畢,name屬性生命週期結束。
1秒之後,Syetem.out.printh(name)執行。然而此時name已經壽終正寢,不在內存中了。 Java就是為了杜絕這種錯誤,嚴格要求內部類別中方位局部變量,必須使用final關鍵字修飾。局部變數被final修飾之後,此時會在記憶體中保有一份局部變得的複製品,當內部類別存取的時候其實存取的是這個複製品。這就好像是把局部變數的生命週期變長了。說到底還是Java工程師提前把這個坑給我們填了,不然不知道又會有多少小夥伴會為了內部類局部變數而發愁了。
四、Integer與int那些事
看下面程式碼
Integer a = new Integer(1000);
int b = 1000;
Integer c = new Integer(10); System.out.println(a == b);
System.out.println(c == d);
這題是繼第一題的後續,如果這題你能很快速的得出答案,那恭喜你,==比較符你就算掌握的比較透徹了。
——————————————————分割線————————————————————————————— –
正確答案: true 、false
看到這個答案很多小夥伴又會不解,先來說下第二個,以第一題來說Integer不是把-128-127緩存起來了嗎?這不是應該是true嘛,但你仔細看,這裡的Integer是我們自己new出來的,並不是用的緩存,所以結果是false。
現在來看第一個為啥又是true了呢? 首先這裡的值為1000,肯定跟我們所知的Integer快取沒有關係。既然跟緩存沒有關係,a是新new出來的對象,照理說輸入應該是false才對。但是注意b這裡是int型別。當int和Integer進行==比較的時候,Java會把Integer進行自動拆箱,也就是把Integer轉成int型,所以這裡比較的是int型別的值,所以結果就是true。