[转载] Java内存管理-你真的理解Java中的数据类型吗(十)
參考鏈接: Java中的字符串類(lèi)String 1
做一個(gè)積極的人?
?編碼、改bug、提升自己?
?我有一個(gè)樂(lè)園,面向編程,春暖花開(kāi)!?
?
?
?推薦閱讀?
?第一季?
?0、Java的線(xiàn)程安全、單例模式、JVM內(nèi)存結(jié)構(gòu)等知識(shí)梳理 1、Java內(nèi)存管理-程序運(yùn)行過(guò)程(一) 2、Java內(nèi)存管理-初始JVM和JVM啟動(dòng)流程(二) 3、Java內(nèi)存管理-JVM內(nèi)存模型以及JDK7和JDK8內(nèi)存模型對(duì)比總結(jié)(三) 4、Java內(nèi)存管理-掌握虛擬機(jī)類(lèi)加載機(jī)制(四) 5、Java內(nèi)存管理-掌握虛擬機(jī)類(lèi)加載器(五) 6、Java內(nèi)存管理-類(lèi)加載器的核心源碼和設(shè)計(jì)模式(六) 7、Java內(nèi)存管理-掌握自定義類(lèi)加載器的實(shí)現(xiàn)(七) 第一季總結(jié):由淺入深JAVA內(nèi)存管理 Core Story?
?
?
?第二季?
?8、Java內(nèi)存管理-愚人節(jié)new一個(gè)對(duì)象送給你(八) 【福利】JVM系列學(xué)習(xí)資源無(wú)套路贈(zèng)送 9、Java內(nèi)存管理-”一文掌握虛擬機(jī)創(chuàng)建對(duì)象的秘密”(九) 10、Java內(nèi)存管理-你真的理解Java中的數(shù)據(jù)類(lèi)型嗎(十) 11、Java內(nèi)存管理-Stackoverflow問(wèn)答-Java是傳值還是傳引用?(十一) 12、Java內(nèi)存管理-探索Java中字符串String(十二)?
?
?
?實(shí)戰(zhàn)?
?一文學(xué)會(huì)Java死鎖和CPU 100% 問(wèn)題的排查技巧?
?
分享一位老師的人工智能教程。零基礎(chǔ)!通俗易懂!風(fēng)趣幽默! 大家可以看看是否對(duì)自己有幫助,點(diǎn)擊這里查看【人工智能教程】。接下來(lái)進(jìn)入正文。?
勿在流沙筑高臺(tái),出來(lái)混遲早要還的。?
作為Java程序員,Java 的數(shù)據(jù)類(lèi)型這個(gè)是一定要知道的! 但是不管是那種數(shù)據(jù)類(lèi)型最終存儲(chǔ)都要到內(nèi)存中,本文由淺入深對(duì)數(shù)據(jù)類(lèi)型進(jìn)行介紹和講解,相信讀完本文你一定會(huì)有收獲的,會(huì)對(duì)Java數(shù)據(jù)類(lèi)型有更深的了解和認(rèn)識(shí)!?
本文地圖?
?
一、什么是位、字節(jié)、字符、字符集?
位(bit):計(jì)算機(jī)內(nèi)部存儲(chǔ)數(shù)據(jù)的最小單位,音譯為比特,每個(gè)二進(jìn)制數(shù)字0或者1就是1個(gè)位!?
字節(jié)(Byte):計(jì)算機(jī)**存儲(chǔ)容量(數(shù)據(jù)處理)**的基本單位,音譯拜特,8個(gè)位構(gòu)成一個(gè)字節(jié);即:1 byte (字節(jié))= 8 bit(位)。?
一個(gè)字節(jié)能夠存放的數(shù)字范圍用二進(jìn)制表示為00000000011111111,也就是8個(gè)bit(比特),8個(gè)比特轉(zhuǎn)換為無(wú)符號(hào)的10進(jìn)制數(shù)字范圍是0255,轉(zhuǎn)換為有符號(hào)數(shù)據(jù)一般為-128~127。?
?
字節(jié)說(shuō)明:對(duì)于存儲(chǔ)容量,我們是比較熟悉的,計(jì)算機(jī)存儲(chǔ)容量大小以字節(jié)數(shù)來(lái)度量,1024進(jìn)位制:?
1024B=1K(千)B (1024個(gè)字節(jié)等于 1KB)
1024KB=1M(兆)B
1024MB=1G(吉)B
1024GB=1T(太)B
還有PB、EB、ZB、YB 、NB、DB等
?
?
字符:字符是一種符號(hào),同以上說(shuō)的存儲(chǔ)單位不是一回事。指計(jì)算機(jī)中使用的字母、數(shù)字、字和符號(hào),包括:1、2、3、A、B、C、~!·#¥%……—*()——+等等。字符一般在不同的編碼(字符集)下面占用的字節(jié)數(shù)不同!也即占用存儲(chǔ)空間不同!?
編碼:編碼就是一個(gè)編號(hào)(數(shù)字)到字符的一種映射關(guān)系(集合),常見(jiàn)的有 ASCII、ISO-8859-1、GB2312、GBK、UTF-8、UTF-16 等。它們都可以被看作為字典,它們規(guī)定了轉(zhuǎn)化的規(guī)則,按照這個(gè)規(guī)則就可以讓計(jì)算機(jī)正確的表示我們的字符。?
# 簡(jiǎn)單舉例舉例:
在 ASCII 編碼中,一個(gè)英文字母字符存儲(chǔ)需要1個(gè)字節(jié)。
在 GB 2312 編碼或 GBK 編碼中,一個(gè)漢字字符存儲(chǔ)需要2個(gè)字節(jié)。
在UTF-8編碼中,一個(gè)英文字母字符存儲(chǔ)需要1個(gè)字節(jié),一個(gè)漢字字符儲(chǔ)存需要3到4個(gè)字節(jié)。
在UTF-16編碼中,一個(gè)英文字母字符或一個(gè)漢字字符存儲(chǔ)都需要2個(gè)字節(jié)(Unicode擴(kuò)展區(qū)的一些漢字存儲(chǔ)需要4個(gè)字節(jié))。
在UTF-32編碼中,世界上任何字符的存儲(chǔ)都需要4個(gè)字節(jié)。
?
?
tips:??
ASCII碼是最熟知字符編碼,編碼范圍為0255,屬于單字節(jié)編碼。ASCII碼編碼范圍太小了,Java為了能夠處理多字節(jié)語(yǔ)言編碼(比如中文、日文、韓文等)編碼范圍0x0000000x10FFFF,采用國(guó)際組織制定的Unicode編碼集。?
因?yàn)閁nicode編碼并非連續(xù)的,所有將Unicode轉(zhuǎn)換為具體的數(shù)值格式是又有多種不同的轉(zhuǎn)換方式。稱(chēng)為Unicode Translation Format(UTF)。?
簡(jiǎn)單總結(jié)一下UTF-8、UTF-16、UTF-32三種轉(zhuǎn)換方式,都是采用字節(jié)作為編碼的基本單位!?
轉(zhuǎn)換方式特點(diǎn)優(yōu)點(diǎn)缺點(diǎn)UTF-8變長(zhǎng)編碼,1-4字節(jié)節(jié)省空間轉(zhuǎn)換麻煩UTF-16固定編碼,2字節(jié)轉(zhuǎn)換相對(duì)簡(jiǎn)單空間相對(duì)節(jié)省UTF-32固定編碼,4字節(jié)轉(zhuǎn)換簡(jiǎn)單空間最浪費(fèi)
目前使用UTF-8還是比較多,節(jié)省空間還是很大的優(yōu)勢(shì)! 在說(shuō)明一點(diǎn)Java虛擬機(jī)內(nèi)部使用的UTF-16轉(zhuǎn)換方式,固定使用兩個(gè)字節(jié),所以java中字符char 占用 2個(gè)字節(jié)!??
?
編碼這一塊的內(nèi)容其實(shí)挺多,如需了解更多深入細(xì)節(jié),請(qǐng)自行查閱相關(guān)資料!?
二、基本數(shù)據(jù)類(lèi)型和引用數(shù)據(jù)類(lèi)型?
有學(xué)過(guò)C語(yǔ)言的伙伴知道在C語(yǔ)言中可以聲明指針類(lèi)型的變量,但是在Java語(yǔ)言中是看不到使用指針的,那么Java中有沒(méi)有指針呢?準(zhǔn)確的話(huà)是有的,因?yàn)樵贘ava底層有些類(lèi)型是封裝了指針的。在Java中根據(jù)底層是否封裝了指針可以將Java的數(shù)據(jù)類(lèi)型分為兩類(lèi),值類(lèi)型和引用類(lèi)型!?
?
2.1、值類(lèi)型?
值類(lèi)型: 也稱(chēng)為基本數(shù)據(jù)類(lèi)型和基元數(shù)據(jù)類(lèi)型。它的值就是一個(gè)數(shù)字,一個(gè)字符或一個(gè)布爾值等。?
沒(méi)有封裝指針的變量,它們?cè)贘ava中有8個(gè),包括byte、char、 short、int 、float 、long 、double、boolean。?
這些基本類(lèi)型首字母都是小寫(xiě),它們并不是類(lèi),也沒(méi)有屬性和方法。聲明值類(lèi)型變量,只會(huì)在棧中分配一塊內(nèi)存空間。?
?
這里面還有一個(gè)知識(shí)點(diǎn)是: 自動(dòng)類(lèi)型轉(zhuǎn)換和強(qiáng)制類(lèi)型轉(zhuǎn)換!?
自動(dòng)類(lèi)型轉(zhuǎn)換:?
一般情況下Java中會(huì)將占用內(nèi)存空間較低的類(lèi)型轉(zhuǎn)換為較高類(lèi)型,如 int型的變量和 long型的變量進(jìn)行計(jì)算的時(shí)候,會(huì)將int型轉(zhuǎn)換為long型;?
如果兩個(gè)變量占用內(nèi)存空間一樣,但是一個(gè)是整型,一個(gè)是浮點(diǎn)型,則會(huì)將整型轉(zhuǎn)換為浮點(diǎn)型。如int型變量與float型變量進(jìn)行計(jì)算,會(huì)將int型轉(zhuǎn)換為float型。?
強(qiáng)制類(lèi)型轉(zhuǎn)換:?
第一種情況:提升變量的類(lèi)型級(jí)別,以獲取精度更高的計(jì)算結(jié)果! 比如 兩個(gè)整型int變量進(jìn)行除法運(yùn)算,為了精度更高,強(qiáng)制轉(zhuǎn)為long類(lèi)型!?
第二種情況:需要用占用空間較小的變量類(lèi)型接受占用空間較大的變量類(lèi)型。比如 int轉(zhuǎn)為byte等,但是要注意 轉(zhuǎn)換過(guò)程中產(chǎn)生溢出截?cái)嗟那闆r!?
上面圖中內(nèi)容中沒(méi)有boolean類(lèi)型變量進(jìn)行說(shuō)明,因?yàn)閎oolean類(lèi)型比較特殊。boolean類(lèi)型變量只有兩個(gè)值,true或者false,它不參與數(shù)學(xué)運(yùn)算,也不能與其他類(lèi)型變量進(jìn)行轉(zhuǎn)換(不管自動(dòng)轉(zhuǎn)換還是強(qiáng)制轉(zhuǎn)換),只是用來(lái)進(jìn)行邏輯判斷。?
boolean類(lèi)型變量的內(nèi)存空間占用具有一定的不確定性,理論上一個(gè)比特就可以保存boolean類(lèi)型變量的值,當(dāng)因?yàn)閮?nèi)存使用的最小單位是字節(jié),那么變量不可能僅占用1/8個(gè)字節(jié)。實(shí)際中,根據(jù)編譯器的不同,**Java會(huì)使用1~4字節(jié)來(lái)保存boolean變量。**字節(jié)內(nèi)容均為0表示false。只要有字節(jié)為非0值表示true。?
面試一定要注意 :String 不是基本類(lèi)型!?
2.2、引用類(lèi)型?
引用類(lèi)型: 就是底層封裝指針的數(shù)據(jù)類(lèi)型。這部分包含的比較多,比如我們自定義或者系統(tǒng)的類(lèi)、抽象類(lèi)、接口,以及數(shù)組。它們?cè)趦?nèi)存中分配兩塊空間,首先要在棧上給其引用(句柄)分配一塊內(nèi)存(不存放具體數(shù)值),然后對(duì)象的具體信息都存儲(chǔ)在堆內(nèi)存上(如對(duì)象的屬性值等),最后由棧上面的引用指向堆中對(duì)象的地址。?
2.3、簡(jiǎn)單示例?
示例代碼:?
public class PrettyGirl {
? ? /**
? ? ?* 姑娘姓字名誰(shuí)
? ? ?*/
? ? String name;
?
? ? /**
? ? ?* 芳齡幾何
? ? ?*/
? ? int age;
?
? ? public static void main(String[] args) {
? ? ? ? //? PrettyGirl是自定義類(lèi),是引用類(lèi)型,分配兩塊內(nèi)存空間
? ? ? ? PrettyGirl prettyGirl = new PrettyGirl();
?
? ? ? ? // String類(lèi)是系統(tǒng)類(lèi),也是引用類(lèi)型,分配兩塊內(nèi)存空間
? ? ? ? String name = new String("Java ok");
?
? ? ? ? // int,float 是值類(lèi)型,只分配一塊內(nèi)存空間
? ? ? ? int num = 10;
? ? ? ? float price = 110.10f;
?
? ? ? ? // 對(duì)象名.屬性名訪問(wèn)對(duì)象的屬性,訪問(wèn)包括賦值和取值
? ? ? ? prettyGirl.name = "Alice";
? ? ? ? prettyGirl.age = 25;
?
? ? }
?
}
?
通過(guò)類(lèi)名 對(duì)象名 = new 類(lèi)名()創(chuàng)建對(duì)象, 在 PrettyGirl prettyGirl = new PrettyGirl();這行代碼在內(nèi)存中就創(chuàng)建了兩塊內(nèi)存空間,第一塊在棧中,名字叫 prettyGirl,它是一個(gè)引用地址,并不放具體的數(shù)值,第二塊堆中的內(nèi)存才存放具體的數(shù)值,如name,age等信息。?
?
其實(shí)數(shù)組內(nèi)部也是封裝引用(指針),即便是基本類(lèi)型的數(shù)組,也是如此! **數(shù)組也是引用類(lèi)型!**比如?
int[] nums = new int[]{1,4,7,3,9};
?
?
說(shuō)明 :0x001 是我隨便寫(xiě)的一個(gè)值,真實(shí)的內(nèi)存地址并不是這個(gè),這個(gè)值只是為了我畫(huà)圖方便!?
在多強(qiáng)調(diào)一點(diǎn),在引用類(lèi)型中,對(duì)于類(lèi)來(lái)說(shuō),要?jiǎng)?chuàng)建對(duì)象其實(shí)包括兩步,第一是聲明對(duì)象,第二是創(chuàng)建對(duì)象!?
public static void main(String[] args) {
? ? // 聲明對(duì)象,相當(dāng)分配指針類(lèi)型變量,在棧中分配內(nèi)存
? ? PrettyGirl alice;
? ? // 創(chuàng)建對(duì)象,創(chuàng)建具體內(nèi)存空間,在堆中分配內(nèi)存
? ? alice = new PrettyGirl();
}
?
聲明對(duì)象:就相當(dāng)于在棧中聲明引用類(lèi)型的變量,它的內(nèi)存不存放具體的數(shù)值,而只存放另一塊堆中內(nèi)存的地址!如?
PrettyGirl alice;
?
創(chuàng)建對(duì)象:一般使用new關(guān)鍵字,如下代碼?
alice = new PrettyGirl();
?
上面這一行代碼做了兩件事情,首先在堆中分配一塊存放具體數(shù)值的內(nèi)存,然后將這個(gè)內(nèi)存的首地址賦給上面聲明的引用變量!?
?
其實(shí)很多時(shí)候,對(duì)象的聲明和創(chuàng)建是放在一行的,如下:?
PrettyGirl mary = new PrettyGirl();
?
三、 八種基本類(lèi)型的包裝類(lèi)和常量池?
以下內(nèi)容摘自:參考資料1 中 8種基本類(lèi)型的包裝類(lèi)和常量池部分內(nèi)容!?
Java 基本類(lèi)型的包裝類(lèi)的大部分都實(shí)現(xiàn)了常量池技術(shù),即Byte,Short,Integer,Long,Character,Boolean;這5種包裝類(lèi)默認(rèn)創(chuàng)建了數(shù)值[-128,127]的相應(yīng)類(lèi)型的緩存數(shù)據(jù),但是超出此范圍仍然會(huì)去創(chuàng)建新的對(duì)象。?
兩種浮點(diǎn)數(shù)類(lèi)型的包裝類(lèi) Float,Double 并沒(méi)有實(shí)現(xiàn)常量池技術(shù)。?
Integer i1 = 33;
Integer i2 = 33;
System.out.println(i1 == i2);// 輸出true
Integer i11 = 333;
Integer i22 = 333;
System.out.println(i11 == i22);// 輸出false
Double i3 = 1.2;
Double i4 = 1.2;
System.out.println(i3 == i4);// 輸出false, 無(wú)緩存!
?
Integer 緩存源代碼:?
/**
*此方法將始終緩存-128到127(包括端點(diǎn))范圍內(nèi)的值,并可以緩存此范圍之外的其他值。
*/
public static Integer valueOf(int i) {
? ? if (i >= IntegerCache.low && i <= IntegerCache.high)
? ? ? ? return IntegerCache.cache[i + (-IntegerCache.low)];
? ? return new Integer(i);
}
?
對(duì)于Integer類(lèi)型來(lái)說(shuō),值在-128-127,用==比較是一致的,超過(guò)這個(gè)區(qū)間就不行了。?
應(yīng)用場(chǎng)景:?
Integer i1=40;Java 在編譯的時(shí)候會(huì)直接將代碼封裝成Integer i1=Integer.valueOf(40);,從而使用常量池中的對(duì)象。Integer i1 = new Integer(40);這種情況下會(huì)創(chuàng)建新的對(duì)象。?
Integer i1 = 40;
Integer i2 = new Integer(40);
System.out.println(i1==i2);//輸出false
?
最后在貼出阿里巴巴Java手冊(cè)中對(duì)包裝類(lèi)使用的建議:?
?
四、本文總結(jié)?
本文整體內(nèi)容相對(duì)基礎(chǔ),但是在java開(kāi)發(fā)中還是非常重要,注重細(xì)節(jié)和基礎(chǔ),讓寫(xiě)出的每一行代碼都是最優(yōu)的!朝著這個(gè)方向努力! 下一篇整理一下值傳遞和引用傳遞! 敬請(qǐng)期待!?
備注: 由于本人能力有限,文中若有錯(cuò)誤之處,歡迎指正。?
五、參考資料?
1、可能是把Java內(nèi)存區(qū)域講的最清楚的一篇文章?
2、Java語(yǔ)言中一個(gè)字符占幾個(gè)字節(jié)??
?
謝謝你的閱讀,如果您覺(jué)得這篇博文對(duì)你有幫助,請(qǐng)點(diǎn)贊或者喜歡,讓更多的人看到!祝你每天開(kāi)心愉快!?
?
?
?Java編程技術(shù)樂(lè)園:一個(gè)分享編程知識(shí)的公眾號(hào)。跟著老司機(jī)一起學(xué)習(xí)干貨技術(shù)知識(shí),每天進(jìn)步一點(diǎn)點(diǎn),讓小的積累,帶來(lái)大的改變!
?
?
?
?掃描關(guān)注,后臺(tái)回復(fù)【資源】,獲取珍藏干貨! 99.9%的伙伴都很喜歡
?
?
?
?
???
?每天都在變得更好的阿飛云
總結(jié)
以上是生活随笔為你收集整理的[转载] Java内存管理-你真的理解Java中的数据类型吗(十)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: oracle不要重复记录,Oracle中
- 下一篇: php ci框架 实例化类,php框架C