Java里的容器存放的元素必须是1个对象.
我們經(jīng)常看到這個句話:
Java里存放的容器只能是1個對象.
一. 值類型和對象類型.
實際上, java里的變量可以分為兩種類型, 一種是值類型. 一種是對象類型.
1.1 值類型變量
所謂值類型的變量就是內(nèi)容(值)直接保存在stack(棧區(qū))或靜態(tài)區(qū)的變量.
例如
int i = 10;這個i就是值類型變量.?? 這個變量的內(nèi)容(值)存放在內(nèi)存的棧區(qū).
如上圖, 紅色部分就是值類型變量i所占的內(nèi)存, 共4個字節(jié).
在java中, 一共有八種值類型. 它們分別是
byte, short, int, long, float, double, char, boolean
可以見這些值類型變量的值要么是數(shù)字, 要么就是字符(char)
也就是說, 這8中類型之類的變量都是對象類型.
1.2 對象類型變量
所謂對象類型變量的內(nèi)容存(成員的值)放在heap(堆區(qū))(String對象除外), 然后在stack區(qū)或static區(qū)保存這個對象內(nèi)容heap區(qū)內(nèi)存的地址.假如Student是1個類, 它有兩個成員id 和 age.
那么實例化1個對象
Student s = new Student(1,20);上面的s就是1個對象類型的變量.
它的數(shù)據(jù)是這樣存放在內(nèi)存中的.
1.它成員Id 和 name 的值會存放在heap區(qū).
2.變量s本身會存放1個地址, 這個地址就是它的成員在heap區(qū)內(nèi)存的頭部地址.??
如下圖:
紫色的部分才是對象型變量s的真正內(nèi)容,
而變量s本身存放的是其真正內(nèi)容在heap區(qū)內(nèi)存的地址.
二. 為什么java容器只存放對象類型.
2.1 c語言數(shù)組只能存放單種元素
我們知道, Java是c/c++ 發(fā)展而來的.
我們回憶一下c語言對于數(shù)組的特性.
1. 數(shù)組在連續(xù)的一塊內(nèi)存空間內(nèi)存儲
2. 數(shù)組內(nèi)的元素必須是相同類型的.
例如 int[] 數(shù)組只存放int 類型元素,? char[] 數(shù)組只存放char類型元素.
為什么呢.
原因很簡單, 因為在c語言數(shù)組連續(xù)的內(nèi)存中,
如果要判斷數(shù)組內(nèi)的其中1個地址內(nèi)存是屬于第幾個元素的,
則:
1. 知道數(shù)組第1塊內(nèi)存的地址.2. 計算當前地址與第1塊內(nèi)存地址的距離
3. 知道每1個元素所占的內(nèi)存長度.
4.利用內(nèi)存除以單個元素內(nèi)存長度則可以求出當前內(nèi)存屬于第幾個元素.
也就是說, 數(shù)組內(nèi)的每個元素所占的內(nèi)存必須是一樣的.? 這樣才可以求出數(shù)組的某個地方屬于第幾個元素.
2.2 Java的數(shù)組可以存放多種屬于不同類的對象
而Java里的數(shù)組為何能存放多種種類的元素呢?
例如下面代碼是合法的:
ArrayLIst Arr = new ArrayList(0; Arr.add(new Student(1,20); Arr.add(new School(1,"No.5 school","address"); Arr.add(new City(1,"Canton","Guangdong","China");上面代碼在1個數(shù)組容器內(nèi)添加了3個對象.
這3個對象分別屬于Student, School 和City類,? 這3個對象明顯不是屬于同1個類,而且所占的內(nèi)存大小很明顯是不同的.
但是能存放在同1個數(shù)組容器中.
原因就是
上面三個對象的內(nèi)容(成員的值)所占的內(nèi)存是不同的,? 這些內(nèi)存都存放在Heap區(qū)內(nèi).
但是, 數(shù)組容器并不是直接存放上面3個對象的內(nèi)容, 而只是保存這3個對象內(nèi)容在Heap區(qū)的頭部地址.
而無論這個三個對象所占的heap區(qū)內(nèi)存相差多大, 它們的頭部地址所占的長度都是一樣的4byte(32位系統(tǒng))
所以實際上數(shù)組內(nèi)的元素都是同1種類型, 就是內(nèi)存地址類型, 它們的長度都一樣啊.
如下圖:
上圖3塊紅色內(nèi)存就是連續(xù)的, 它們都屬于存放在數(shù)組Arr內(nèi).
所以我們講: Java里的容器只存放對象類型元素, 但是實際上是存放對象內(nèi)容的頭部地址.
三. 自動裝箱(boxing) 和 自動拆箱(unboxing)
但是實際上, 我們往往在容器里直接添加值類型變量.
例如下面的代碼是合法的:
ArrayList arr = new ArrayList(); arr.add(123); arr.add("Jack"); int i; String s; i = arr.get(i); s = arr.get(2); System.out.printf("%d, %s\n",i,s);上面我們直接往1個ArrayList容器添加了值類型對象123 和 "Jack"? 不是跟上面所說的矛盾嗎?
3.1 "Jack" 是1個字符串對象類型, 而不是值類型.
本文在上面提過, java只有8中值類型.
而"Jack" 是1個字符串常量,? 它的內(nèi)容保存在static區(qū),? 它是1個對象而不是值類型.
其實對象類型和值類型的最大區(qū)別就是, 對象類型具有成員.
可以通過 ".屬性名" 或 ".方法名()"來調(diào)用對象的屬性or方法.
下面的代碼就是合法的, 它輸出了1個字符串常量對象的長度:
System.out.printf("%d\n","Jack".length());
3.2 什么是裝箱(boxing)
雖然我們執(zhí)行了代碼
arr.add(123);
但是如果數(shù)組內(nèi)直接存放數(shù)值123的值就違反了java容器只存放對象的原則了.
實際上, java里, 對于值類型來講, 都有1個對應(yīng)的對象類型.
例如 int是1個整形值類型,? 而Interger是1個整形類
Interger里有1個成員屬性, 用于存放1個整形值類型的值.
還包含很多對整形值操作的方法.
而int 整形類型本身是沒有任何成員方法的.
所以有時我們會用1個Integer對象將1個int變量包起來.
例如
上面的i就是1個整形值類型變量
而io就是1個Integer對象.
這個過程就叫做裝箱.
對于容器來講,
如果將1個值類型直接放入容器, java會將其裝箱后再放入容器.
這個過程就叫做自動裝箱.
所以下面兩句代碼是等價的.
所以實際上并沒有違反java容器只存放對象的原則.
3.3 什么是拆箱
這個也很簡單, 就是基于1個對象類型返回1個值類型就是拆箱了.
例如:
integer io = new Integer(123); int i = io.intValue()' System.out.printf("%d\n", i);上面代碼中我們用值類型變量i 獲得 Integer對象io所存放的值, 這個過程就是拆箱
如果我們利用容器的get()方法來返回1個值類型.
例如:
int i = arr.get(1);我們知道容器里存放的都是對象, 但是java會先將其拆箱再返回給1個值類型變量,
這個過程那個就是自動拆箱了.
/
總結(jié)
以上是生活随笔為你收集整理的Java里的容器存放的元素必须是1个对象.的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java里的容器 Collection
- 下一篇: Java 中 Comparable 接口