概述
java 中有很多,新手經常遇到的陷阱,本文主要包含
自動裝箱與拆箱
不可變的String
記憶體洩漏
自增型別使用
使用 “==”進行物件比較
double 型別計算
不可變的String
Java String類是不可變的(不可修改)。這是因為String物件被快取在String池中。字串引用的物件可以更改,但字串物件本身不能更改。
字串是不可變的。
一旦建立了字串,以後將無法更改該字串物件。
Java使用按值傳遞
,而不是按引用傳遞。當您在方法中為分配新值時,它只會修改本地,而不是呼叫程式碼中的原始s
自動裝箱與拆箱
裝箱就是自動將基本資料型別轉換為包裝器型別;
拆箱就是自動將包裝器型別轉換為基本資料型別。
裝箱拆箱的型別有哪些?
透過上圖,可以看出,java 基本型別可以進行拆裝箱。
那拆裝箱會出現什麼問題呢?
透過例項,上面兩個程式,
計算耗時相差近10倍
,在大量存在裝箱行為時,會導致程式效能低下。
當封裝型別進行==、+、-、*、/計算時,會自動拆箱,對基礎資料型別進行運算。所以在進行計算時,使用基本資料型別。
記憶體洩漏
Java的核心優勢之一是 Java垃圾收集器,它可以管理堆上的物件記憶體。每當物件不可訪問時,它將自動釋放。
但是,對於新手和有經驗的程式設計師而言,常見的錯誤是透過允許不再使用的物件可訪問來防止釋放記憶體。這可能對專案造成很大的不利影響,因為記憶體洩漏會阻塞資源並降低應用程式效能。它甚至可能導致java。lang。OutOfMemoryError。
常見的情況是:
靜態欄位宣告。靜態欄位,並在不再需要其資料後忘記將其設定為null
未正常關閉流。 Java虛擬機器為每個開啟的連線分配記憶體。忘記關閉連線會消耗記憶體。這樣的連線可以是:輸入流,資料庫連線,會話等。
finalize() 方法。當我們覆蓋的finalize()方法,finalize()只會在物件記憶體回收前被呼叫一次,具有不確定行,只保證方法會呼叫,但不保證方法裡的任務會被執行完。所以儘量避免使用。在Java 9 中,已經宣告為過期函式,
自增型別使用
Java中運算子的計算順序是在同等級下從左到右計算,看下自增情況
第一種情況的執行上下文如下:
1。儲存運算元的先前值。
2。增加值。
3。返回上一個值
第二種情況的執行上下文如下:
1。增加值。
2。儲存運算元的值(遞增)
3。返回值
使用 “==”進行物件比較
許多新手程式設計師嘗試使用“ ==”運算子比較物件,並且當代碼的行為不符合預期時,就會感到困惑。需要注意的是,關係運算符“ ==”正在進行引用比較,它檢查兩個物件是否都指向記憶體中的相同位置。使用 。equals()方法將消除此問題,因為它會比較物件內部的值。
儘管有時“ ==”運算子會給出預期的答案:
這是什麼原因呢?同樣是字串,建立的方式不同,差距咋這麼大呢
Java語言規範的字串文字中:同一包中不同類內的文字字串表示對同一String 物件的引用
如果還不清楚那看下兩種字串建立過程
第一種new的方式
new一個字串時,做了兩件事。首先在堆中生成了該字串物件,然後去看常量池中有沒有該字串,如果有就不管了,沒有就往常量池中新增一個
第二種,直接賦值
這樣建立字串,首先會去常量池裡找有沒有這個字串,有就直接指向常量池的該字串,沒有就先往常量池中新增一個,再指向它。
上面就是兩種方式的對比情況了。
兩個Integer 對比
那為什麼100的時候就是相等200就不行了呢這是由於Integer 使用了快取。
其static塊中就一次性生成了-128到127直接的Integer型別變數儲存在cache[]中,對於-128到127之間的int型別,返回的都是同一個Integer型別物件。
整個工作過程就是:Integer。class在裝載(Java虛擬機器啟動)時,其內部型別IntegerCache的static塊即開始執行,例項化並暫存數值在-128到127之間的Integer型別物件。
當自動裝箱int型值在-128到127之間時,即直接返回IntegerCache中暫存的Integer型別物件。
為什麼Java這麼設計?應該是出於效率考慮,因為自動裝箱經常遇到,尤其是小數值的自動裝箱;而如果每次自動裝箱都觸發new,在堆中分配記憶體,就太耗時了;
其它幾種基本型別包裝類,也進行了快取
Double 型別計算
Java中的double和float在內部表示為二進位制分數,因此在表示十進位制分數時可能不夠精確(IEEE標準754)。十進位制數計算需要精度,需要使用java。math。BigDecimal
總結
Java 中還有很多小陷阱,如果你有可以寫出來吆。
String 為什麼會設計成不可改變的呢?