java包装_Java基础之神奇的包装类(一)
1. 導讀
JAVA中針對八種基本數據類型提供了相對應的包裝類, 今天主要基于幾個問題來分享下個人對于包裝類的理解, 本期先分享下面兩個問題:
.1 什么是包裝類? 有了基本類型, 為什么還需要有包裝類;
.2 包裝類干了什么?
2. 什么包裝類
眾所周知, JAVA提供了八種基本類型, 同時也對這八種基本類型做了相應的封裝, 形成了八種包裝類:
table.jpg
其實void在JAVA也是一種數據類型, 也有對應的包裝類Void, 只是我們無法對其進行操作, 也就沒有放在上面的表格中了;
3. 為什么需要包裝類
JAVA是面相對象的編程語言; 那么要理解面相對象, 首先需要知道這個對象是什么? 我的理解是:
.1 對象具有自己的屬性以及行為;
.2 對象可以通過自己的行為或者動作向外界傳遞信息;
那么面相對象就是通過對象之間的信息交互來實現整個程序的功能; 而封裝, 繼承 和 多態是基于語言層面的約束;
有了面相對象編程的概念, 我們再來看為什么JAVA需要包裝類;
.1 包裝類在基本類型的基礎上做了封裝, 使其有了自身的行為; 那么有了行為有什么好處呢? 我們舉個例子來說明:
封裝類
通過int和Integer舉例, 展示了基本類型和包裝類型的判斷和轉String的區別:為什么達到同一個目的, 基本類型需要借助其他手段來實現; 而包裝類卻可以通過自身的動作達到, 這就是基本類型和包裝類型的不同, 這也是面相過程與面相對象的區別: 面相過程需要自己實現需求, 面相對象則是調用目標對象對應的方法即可;
.2 初始化的不同: 未賦值時, 基本數據類型默認是0, 而封裝類型默認是null; 當需要區分賦值與未賦值時, 封裝類型就顯得十分友好了; 比如在構建更新實體時, 有個字段是0, 就需要判斷他的原始值是0還是需要更新成0; 而null則沒有這種煩惱了;
.3 前面說過JAVA是面相對象的語言, 其很多設計都是針對對象來的, 比如HashMap的設計, 在插入時, 需要先調用插入key的Object::equals, 但是基本數據類型是沒有行為的, 意味著基本數據類型無法作為HashMap的key; 如果沒有封裝類, 我們就無法實現用數值類型作為key了;
故而為何需要封裝類?
.1 JAVA是面相對象的語言, 其語言設計初衷就需要"萬物皆對象", 故需要對基本數據類型再次封裝;
.2 JAVA內部很多實現需要調用對象相對應的動作, 而基本數據類型不是對象, 為了使用這些實現, 需要封裝對象;
4. 包裝類干了什么
這8個包裝類大同小異, 我們以比較特殊的Integer來舉例;
public final class Integer extends Number implements Comparable {
@Native public static final int MIN_VALUE = 0x80000000;
@Native public static final int MAX_VALUE = 0x7fffffff;
...
private final int value;
從上面的代碼可看出, Integer的一些設計:
.1 Integer類是final的, 其底層存值的value也是final的; 這個設計和String是一樣的, Integer也就是不可變的;
.2 Integer也設置了int相同的最大最小值, 因為Integer是基于int做的封裝, 故而仍然存在溢出問題(當賦的值大于Integer.MAX_VALUE時, 發生溢出);
再來關注下Integer::equals, Integer重寫了Object的equals方法:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
.1 如果傳入對象是Integer類型的, 比較兩者的value是相等;
.2 如果是非Integer類型的, 直接返回false;
.3 這里沒有先比對兩者的堆地址, 因為只有兩者是同一個對象時才會直接返回true; 這個概率比較小(一般沒人會自己比較自己吧), 所以直接省略了這一步;
繼續關注Integer::hashCode的實現:
public static int hashCode(int value) {
return value;
}
Integer::hashCode直接返回了當前的值(hashCode返回的是個int類型的值, 直接返回Integer的值好像也沒啥不對);
按這個邏輯, Long::hashCode是不是直接強轉成int返回的呢? 因為精度問題, Long::hashCode做了特殊處理:
public static int hashCode(long value) {
return (int)(value ^ (value >>> 32));
}
Long::hashCode并不是如我們猜想的那樣設計的:
.1 先把value右移32位, 因為long是64位的, 右移32位就把左邊邊的值都置為0了;
.2 再與原始值進行異或, 將得出的結果強轉成int類型;
.3 至于為什么這么設計, 主要是以為int是32位的, 如果采用Integer::hashCode的方法, 那么當右邊32位都是0時, 不管左邊的32位是何值, 在轉為int時, 左邊32位都被摸除, 得出的結果都是0; 這樣的方式顯然會有很大的碰撞;
.4 故而Long::hashCode采用了低位32異或高位32的方式來獲取hashCode;Double::hashCode的實現也是采用的這種方式;
Integer是實現了Compareable接口的, 我們來看下Integer::compareTo:
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
.1 使用了三目運算符; 第一層先判斷是否小于, true則返回-1;
.2 第二層判斷是否相等, true則返回0, 反之則返回1;
.3 如果兩個Integer是相等的, 那么調用Integer::equals 和 Integer::compareTo的結果是一樣的;
本期基于上面兩個問題分享了個人對于封裝類的理解, 如果上面有不當之處, 歡迎指正; 如果看了覺的有益處, 煩請點贊轉發吧, 感謝;
總結
以上是生活随笔為你收集整理的java包装_Java基础之神奇的包装类(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 哈尔滨旅游多少钱啊?
- 下一篇: 鸽子多少钱一只啊?