java基礎(chǔ)的自修課

數(shù)據(jù)的傳遞

1.?實(shí)參的數(shù)目命斧、數(shù)據(jù)類型和次序必須和所調(diào)用的方法聲明的形式參數(shù)列表匹配寡壮。

? ? ? 2.?return 語句終止方法的運(yùn)行并指定要返回的數(shù)據(jù)和敬。

? ? ? 3.?Java中進(jìn)行方法調(diào)用中傳遞參數(shù)時裳瘪,遵循值傳遞的原則(傳遞的都是數(shù)據(jù)的副本):

? ? ? 4.?基本類型傳遞的是該數(shù)據(jù)值的copy值。

? ? ? 5.?引用類型傳遞的是該對象引用的copy值橙凳,但指向的是同一個對象蕾殴。

遞歸的調(diào)用:

自己調(diào)用自己”,一個使用遞歸技術(shù)的方法將會直接或者間接的調(diào)用自己岛啸。

遞歸結(jié)構(gòu)包括兩個部分:

? ? ??1.定義遞歸頭钓觉。解答:什么時候不調(diào)用自身方法。如果沒有頭坚踩,將陷入死循環(huán)荡灾,也就是遞歸的結(jié)束條件。

? ? ??2.遞歸體瞬铸。解答:什么時候需要調(diào)用自身方法卧晓。

任何能用遞歸解決的問題也能使用迭代解決。當(dāng)遞歸方法可以更加自然地反映問題赴捞,并且易于理解和調(diào)試逼裆,并且不強(qiáng)調(diào)效率問題時,可以采用遞歸;

? ? ??在要求高性能的情況下盡量避免使用遞歸赦政,遞歸調(diào)用既花時間又耗內(nèi)存胜宇。


面向?qū)ο蟮膬?nèi)存:

java虛擬機(jī)的內(nèi)存可以分為三個區(qū)域: 棧stack ,堆heap,方法區(qū)method area

棧stack:

1, 棧描述的是方法執(zhí)行的內(nèi)存模型,每個方法被調(diào)用都會創(chuàng)建一個棧幀(存儲局部變量恢着,操作數(shù)桐愉,方法出口等)

2. JVM為每個線程創(chuàng)建一個棧,用于存放該線程執(zhí)行方法的信息(實(shí)際參數(shù)掰派,局部變量等)

3. 棧的存儲特性私有从诲,不能實(shí)現(xiàn)線程間共享

4.棧的存儲特性是“先進(jìn)后出,后進(jìn)先出”

5. 棧是由系統(tǒng)自動分配靡羡,速度快系洛, 棧是一個連續(xù)的內(nèi)存空間?

堆:

1 堆是用于存儲創(chuàng)建好的對象和數(shù)組(數(shù)組也是對象)

2. JVM只有一個堆俊性,被所有的線程共享

3. 堆是一個不連續(xù)的內(nèi)存空間,分配靈活描扯,速度慢

方法區(qū)(靜態(tài)區(qū)):

1. JVM只有一個方法區(qū)定页,被所有線程共享,

2.方法區(qū)實(shí)際也是堆绽诚,只是用于存儲類典徊,常量相關(guān)信息

3.用來存放程序中永遠(yuǎn)是不變或者唯一的內(nèi)容(類信息,class對象恩够,靜態(tài)變量卒落,字符串常量等)

思考:本人思考如何實(shí)現(xiàn)一個100的階乘 100!因為java的基本類型是長度是確定的蜂桶,必定會出現(xiàn)溢出情況导绷。

java中的基本數(shù)據(jù)類型存放位置

基本數(shù)據(jù)類型是放在棧中還是放在堆中,這取決于基本類型聲明的位置屎飘。

?一:在方法中聲明的變量妥曲,即該變量是局部變量,每當(dāng)程序調(diào)用方法時钦购,系統(tǒng)都會為該方法建立一個方法棧檐盟,其所在方法中聲明的變量就放在方法棧中,當(dāng)方法結(jié)束系統(tǒng)會釋放方法棧押桃,其對應(yīng)在該方法中聲明的變量隨著棧的銷毀而結(jié)束葵萎,這就局部變量只能在方法中有效的原因

????? 在方法中聲明的變量可以是基本類型的變量,也可以是引用類型的變量唱凯。

?????? ? (1)當(dāng)聲明是基本類型的變量的時羡忘,其變量名及值(變量名及值是兩個概念)是放在方法棧中

??????? ?(2)當(dāng)聲明的是引用變量時,所聲明的變量(該變量實(shí)際上是在方法中存儲的是內(nèi)存地址值)是放在方法的棧中磕昼,該變量所指向的對象是放在堆類存中的卷雕。

?? 二:在類中聲明的變量是成員變量,也叫全局變量票从,放在堆中的(因為全局變量不會隨著某個方法執(zhí)行結(jié)束而銷毀)漫雕。

?????? 同樣在類中聲明的變量即可是基本類型的變量 也可是引用類型的變量

???????(1)當(dāng)聲明的是基本類型的變量其變量名及其值放在堆內(nèi)存中的

???????(2)引用類型時,其聲明的變量仍然會存儲一個內(nèi)存地址值峰鄙,該內(nèi)存地址值指向所引用的對象浸间。引用變量名和對應(yīng)的對象仍然存儲在相應(yīng)的堆中

根據(jù)這個,我將基本棧中的數(shù)據(jù)存放在堆中吟榴,用Array 來存儲就可以解決這個問題


public class MulTest {

public static void main(String[] args) {

// System.out.println(capacity(9000));

// int num[] = numToarray(980);

// for(int i =0 ; i<num.length;i++){

// System.out.println("打印的第"+i+"位"+num[i]);

// }

int fnum[] = fn(4096);

printNum(fnum);

}

/**

* 確定一個數(shù)多少位魁蒜,為方后邊能給一個數(shù)組大小的空間

* @param n

* @return

*/

static int capacity(int num) {

int count = 0;

while (num > 0) {

num = num / 10;? //比如說240 240/10 =24 count=1 ;24/10=2 count=2; 2/10=0 count=3

count++;

}

return count;

}

/**

* 將整型數(shù)字轉(zhuǎn)換為數(shù)組

* numtoarray[0]= 0 ;第二次 num=240/10=24? ;numtoarray[1]=24%10=4;numtoarray[2]=2%10=2

* @param num

* @return

*/

static int [] numToarray(int num){

int len = capacity(num);

int numtoarray[] = new int [len];

for(int i=0;i<len;i++){

numtoarray[i] = num %10;?

num = num/10;

}

return numtoarray;

}

/**

*

* 數(shù)組相乘,每一位數(shù)組與另一位數(shù)組相乘

*

*/

public static int[] mul(int []a, int []b){

int temp = 0;

int alength =a.length;

int blength = b.length;

int retult[] = new int[alength+blength] ;

for (int i = 0; i <= alength+blength - 1; i++) {

retult[i] = 0;

}

for (int i = 0; i <= alength - 1; i++) {

for (int j = 0; j <= blength - 1; j++) {

temp = a[i] * b[j];

retult[j + i] += temp;

}

}

int len = retult.length;

int temp2;

for (int i = 0; i <= retult.length-2; i++) {

temp2 = retult[i];

if (temp2 >= 10) {

retult[i] = temp2 % 10;

retult[i + 1] = retult[i + 1] + temp2 / 10;

}

}

return retult;

}

/**

* 階乘

*/

public static int[] fn(int n){

int retult[] = {1};

int bit = capacity(n);

// System.out.println("返回多少位:"+n);

System.out.println("開始:"+n+"!? = ");

int temp[] = new int[bit];

for(int i = 1;i<=n;i++){

temp? =numToarray(i);

retult = mul(temp,retult);

}

return retult;

}

static void printNum(int a[]) {

int len = a.length;

int f = 0;

int count = 0;

for (int i = len - 1; i >= 0; i--) {

if (a[i] > 0)

f = 1;

if (f > 0) {

System.out.print(a[i]);

++count;

}

}

System.out.println();

System.out.println("----------------------------");

System.out.println("一共多少位:"+count);

}

}


構(gòu)造器:

1. 通過New關(guān)鍵字調(diào)用,

2.構(gòu)造器雖然沒有返回值兜看,但是不能定義返回值類型(返回值類型肯定是本類)锥咸,不能在構(gòu)造器里使用return返回某個值,但可以使用return結(jié)束

3.如果我們沒有定義構(gòu)造器铣减,編譯器會幫我們自動定義一個無參的構(gòu)造器

如果已定義則編譯器不會自動創(chuàng)建

4. 構(gòu)造器的方法名必須和類名一致她君。

內(nèi)存泄漏:

· 創(chuàng)建大量無用對象

  比如脚作,我們在需要大量拼接字符串時葫哗,使用了String而不是StringBuilder。

String?str?=?"";

for?(int?i?=?0;?i?<?10000;?i++)?{???

????str?+=?i;?????//相當(dāng)于產(chǎn)生了10000個String對象

}

靜態(tài)集合類的使用

  像HashMap球涛、Vector劣针、List等的使用最容易出現(xiàn)內(nèi)存泄露,這些靜態(tài)變量的生命周期和應(yīng)用程序一致亿扁,所有的對象Object也不能被釋放捺典。

 · 各種連接對象(IO流對象、數(shù)據(jù)庫連接對象从祝、網(wǎng)絡(luò)連接對象)未關(guān)閉

  IO流對象襟己、數(shù)據(jù)庫連接對象、網(wǎng)絡(luò)連接對象等連接對象屬于物理連接牍陌,和硬盤或者網(wǎng)絡(luò)連接擎浴,不使用的時候一定要關(guān)閉。

  · 監(jiān)聽器的使用

  釋放對象時毒涧,沒有刪除相應(yīng)的監(jiān)聽器贮预。

要點(diǎn):

  1. 程序員無權(quán)調(diào)用垃圾回收器。

  2. 程序員可以調(diào)用System.gc()契讲,該方法只是通知JVM仿吞,并不是運(yùn)行垃圾回收器。盡量少用捡偏,會申請啟動Full GC唤冈,成本高,影響系統(tǒng)性能银伟。

  3. finalize方法务傲,是Java提供給程序員用來釋放對象或資源的方法,但是盡量少用枣申。

垃圾回收過程:

? ? 1售葡、新創(chuàng)建的對象,絕大多數(shù)都會存儲在Eden中忠藤,

? ? 2挟伙、當(dāng)Eden滿了(達(dá)到一定比例)不能創(chuàng)建新對象,則觸發(fā)垃圾回收(GC),將無用對象清理掉尖阔,

???????????然后剩余對象復(fù)制到某個Survivor中贮缅,如S1,同時清空Eden區(qū)

? ? 3介却、當(dāng)Eden區(qū)再次滿了谴供,會將S1中的不能清空的對象存到另外一個Survivor中,如S2齿坷,

? ? ? ? ??同時將Eden區(qū)中的不能清空的對象桂肌,也復(fù)制到S1中,保證Eden和S1永淌,均被清空崎场。

? ? 4、重復(fù)多次(默認(rèn)15次)Survivor中沒有被清理的對象遂蛀,則會復(fù)制到老年代Old(Tenured)區(qū)中谭跨,

? ? 5、當(dāng)Old區(qū)滿了李滴,則會觸發(fā)一個一次完整地垃圾回收(FullGC)螃宙,之前新生代的垃圾回收稱為(minorGC)

 在對JVM調(diào)優(yōu)的過程中,很大一部分工作就是對于Full GC的調(diào)節(jié)所坯。有如下原因可能導(dǎo)致Full GC:

  1.年老代(Tenured)被寫滿

  2.持久代(Perm)被寫滿

  3.System.gc()被顯式調(diào)用(程序建議GC啟動谆扎,不是調(diào)用GC)

  4.上一次GC之后Heap的各域分配策略動態(tài)變化



多態(tài):

1.多態(tài)是方法的多態(tài),不是屬性的多態(tài)(多態(tài)與屬性無關(guān))

2.多態(tài)的存在要有3個必要的條件:繼承包竹,方法重寫燕酷,父類引用指向子類對象。

3.父類引用指向子類重寫的方法周瞎,此時多態(tài)就出現(xiàn)了苗缩。

package com.test;

class Animal {

? ? public? void shout() {

? ? ? ? System.out.println("叫了一聲!");

? ? }

}

class Dog extends Animal {

? ? public void shout() {

? ? ? ? System.out.println("旺旺旺声诸!");

? ? }

? ? public void seeDoor() {

? ? ? ? System.out.println("看門中....");

? ? }

}

class Cat extends Animal {

? ? public void shout() {

? ? ? ? System.out.println("喵喵喵喵酱讶!");

? ? }

}

public class TestPolym {

? ? public static void main(String[] args) {

? ? ? ? Animal a1 = new Cat(); // 向上可以自動轉(zhuǎn)型

? ? ? ? //傳的具體是哪一個類就調(diào)用哪一個類的方法。大大提高了程序的可擴(kuò)展性彼乌。

? ? ? ? animalCry(a1);

? ? ? ? Animal a2 = new Dog();

? ? ? ? animalCry(a2);//a2為編譯類型泻肯,Dog對象才是運(yùn)行時類型。


? ? ? ? //編寫程序時慰照,如果想調(diào)用運(yùn)行時類型的方法灶挟,只能進(jìn)行強(qiáng)制類型轉(zhuǎn)換。

? ? ? ? // 否則通不過編譯器的檢查毒租。

? ? ? ? Dog dog = (Dog)a2;//向下需要強(qiáng)制類型轉(zhuǎn)換

? ? ? ? dog.seeDoor();

? ? }

? ? // 有了多態(tài)稚铣,只需要讓增加的這個類繼承Animal類就可以了。

? ? static void animalCry(Animal a) {

? ? ? ? a.shout();

? ? }

? ? /* 如果沒有多態(tài),我們這里需要寫很多重載的方法惕医。

? ? * 每增加一種動物耕漱,就需要重載一種動物的喊叫方法。非常麻煩抬伺。

? ? static void animalCry(Dog d) {

? ? ? ? d.shout();

? ? }

? ? static void animalCry(Cat c) {

? ? ? ? c.shout();

? ? }*/

}


package com.test;

public class HttpServer {

public void service(){

System.out.println("httpserver service");

doGet();

}

public void doGet(){

System.out.println("httpserver doGet");

}

}

package com.test;

public class MyServlet extends HttpServer{//繼承

//方法重寫

@Override

public void doGet() {

System.out.println("MyServlet doGet");

}

public static void main(String[] args) {

? ? ? ? ? //父類引用指向子類重寫的方法螟够,此時多態(tài)就出現(xiàn)了

HttpServer MyServlet = new MyServlet();//父類引用指向子類對象

MyServlet.service();

}

}

final關(guān)鍵字的作用:

? ? ? 1. 修飾變量: 被他修飾的變量不可改變。一旦賦了初值峡钓,就不能被重新賦值妓笙。

final??int???MAX_SPEED?=?120;

? ? ??2. 修飾方法:該方法不可被子類重寫。但是可以被重載!

final??void??study(){}

? ? ??3. 修飾類: 修飾的類不能被繼承椒楣。比如:Math给郊、String等。

抽象類:

抽象類是一種模板,抽象類為所有的子類提供一個通用的模板芜壁,子類可以在這個模板的基礎(chǔ)上進(jìn)行擴(kuò)展

通過抽象類梳庆,可以避免子類設(shè)計的隨意性,通過抽象類奔则,我們就可以做到嚴(yán)格限制子類餓設(shè)計,是子類之間更加通用。

要點(diǎn):

1. 有抽象方法的類只能定義成抽象類

2. 抽象類不能實(shí)例化煌寇,及不能用new來實(shí)例化抽象類

3. 抽象方法可以包含屬性、方法逾雄、構(gòu)造方法阀溶。但是構(gòu)造方法不能用來new實(shí)例,只能被子類調(diào)用鸦泳。

4. 抽象方法只能用來繼承

5. 抽象方法必須被子類實(shí)現(xiàn)

接口:

[訪問修飾符]??interface?接口名???[extends??父接口1银锻,父接口2…]??{

常量定義;??

方法定義做鹰;

}

interface MyInterface4extends MyInterface,MyInterface2,MyInterface3{

}

定義接口的詳細(xì)說明:

? ? ? 1. 訪問修飾符:只能是public或默認(rèn)击纬。

? ? ??2. 接口名:和類名采用相同命名機(jī)制。

? ? ??3. extends:接口可以多繼承钾麸。

? ? ??4. 常量:接口中的屬性只能是常量更振,總是:public static final 修飾。不寫也是饭尝。

? ? ??5. 方法:接口中的方法只能是:public abstract肯腕。 省略的話,也是public abstract钥平。

要點(diǎn)

? ? ??1. 子類通過implements來實(shí)現(xiàn)接口中的規(guī)范实撒。

? ? ??2. 接口不能創(chuàng)建實(shí)例,但是可用于聲明引用變量類型。

? ? ??3. 一個類實(shí)現(xiàn)了接口奈惑,必須實(shí)現(xiàn)接口中所有的方法吭净,并且這些方法只能是public的。

? ? ??4. JDK1.7之前肴甸,接口中只能包含靜態(tài)常量寂殉、抽象方法,不能有普通屬性原在、構(gòu)造方法友扰、普通方法。

? ? ??5. JDK1.8后庶柿,接口中包含普通的靜態(tài)方法村怪。



內(nèi)部內(nèi):

?1. 內(nèi)部類提供了更好的封裝。只能讓外部類直接訪問浮庐,不允許同一個包中的其他類直接訪問甚负。

? ? ??2. 內(nèi)部類可以直接訪問外部類的私有屬性,內(nèi)部類被當(dāng)成其外部類的成員审残。 但外部類不能訪問內(nèi)部類的內(nèi)部屬性梭域。

? ? ??3. 接口只是解決了多重繼承的部分問題,而內(nèi)部類使得多重繼承的解決方案變得更加完整搅轿。

內(nèi)部類的使用場合:

? ? ??1. 由于內(nèi)部類提供了更好的封裝特性病涨,并且可以很方便的訪問外部類的屬性。所以璧坟,在只為外部類提供服務(wù)的情況下可以優(yōu)先考慮使用內(nèi)部類既穆。

? ? ??2. ?使用內(nèi)部類間接實(shí)現(xiàn)多繼承:每個內(nèi)部類都能獨(dú)立地繼承一個類或者實(shí)現(xiàn)某些接口,所以無論外部類是否已經(jīng)繼承了某個類或者實(shí)現(xiàn)了某些接口雀鹃,對于內(nèi)部類沒有任何影響幻工。

在Java中內(nèi)部類主要分為成員內(nèi)部類(非靜態(tài)內(nèi)部類、靜態(tài)內(nèi)部類)褐澎、匿名內(nèi)部類会钝、局部內(nèi)部類。

. 成員內(nèi)部類(可以使用private工三、default迁酸、protected、public任意進(jìn)行修飾俭正。 類文件:外部類$內(nèi)部類.class)

a) 非靜態(tài)內(nèi)部類(外部類里使用非靜態(tài)內(nèi)部類和平時使用其他類沒什么不同)

? ? ? i. 非靜態(tài)內(nèi)部類必須寄存在一個外部類對象里奸鬓。因此,如果有一個非靜態(tài)內(nèi)部類對象那么一定存在對應(yīng)的外部類對象掸读。非靜態(tài)內(nèi)部類對象單獨(dú)屬于外部類的某個對象串远。

? ? ??ii. 非靜態(tài)內(nèi)部類可以直接訪問外部類的成員宏多,但是外部類不能直接訪問非靜態(tài)內(nèi)部類成員。

? ? ??iii. 非靜態(tài)內(nèi)部類不能有靜態(tài)方法澡罚、靜態(tài)屬性和靜態(tài)初始化塊伸但。

? ? ??iv. 外部類的靜態(tài)方法、靜態(tài)代碼塊不能訪問非靜態(tài)內(nèi)部類留搔,包括不能使用非靜態(tài)內(nèi)部類定義變量更胖、創(chuàng)建實(shí)例。

? ? ??v. 成員變量訪問要點(diǎn):

? ? ? ??1. 內(nèi)部類里方法的局部變量:變量名隔显。

? ? ? ??2. 內(nèi)部類屬性:this.變量名却妨。

? ? ? ??3. 外部類屬性:外部類名.this.變量名。

注意

? ? ??內(nèi)部類只是一個編譯時概念括眠,一旦我們編譯成功彪标,就會成為完全不同的兩個類。對于一個名為Outer的外部類和其內(nèi)部定義的名為Inner的內(nèi)部類掷豺。編譯完成后會出現(xiàn)Outer.class和Outer$Inner.class兩個類的字節(jié)碼文件捞烟。所以內(nèi)部類是相對獨(dú)立的一種存在,其成員變量/方法名可以和外部類的相同萌业。


String:

String 類是不可改變的坷襟,所以你一旦創(chuàng)建了 String 對象奸柬,那它的值就無法改變了(詳看筆記部分解析)生年。

如果需要對字符串做很多修改,那么應(yīng)該選擇使用 StringBuffer & StringBuilder 類廓奕。

StringBuffer & StringBuilder 類

StringBuilder:線程不安全抱婉,效率高,一般用它桌粉。

StrungBuffer:線程安全蒸绩,但是效率低,一般不用铃肯。

? String一經(jīng)初始化后患亿,就不會再改變其內(nèi)容了。對String字符串的操作實(shí)際上是對其副本(原始拷貝)的操作押逼,原來的字符串一點(diǎn)都沒有改變步藕。比如:

? ? ??String s ="a"; 創(chuàng)建了一個字符串

? ? ??s = s+"b"; 實(shí)際上原來的"a"字符串對象已經(jīng)丟棄了,現(xiàn)在又產(chǎn)生了另一個字符串s+"b"(也就是"ab")挑格。 如果多次執(zhí)行這些改變串內(nèi)容的操作咙冗,會導(dǎo)致大量副本字符串對象存留在內(nèi)存中,降低效率漂彤。如果這樣的操作放到循環(huán)中雾消,會極大影響程序的時間和空間性能灾搏,甚至?xí)斐煞?wù)器的崩潰。

? ? ??相反立润,StringBuilder和StringBuffer類是對原字符串本身操作的狂窑,可以對字符串進(jìn)行修改而不產(chǎn)生副本拷貝或者產(chǎn)生少量的副本。因此可以在循環(huán)中使用桑腮。

String源碼中數(shù)組是final固定的

StringBuilder源碼中繼承了抽象類AbstractStringBuilder蕾域,數(shù)組是可變的

無值的時候初始長度是16

有值的時候,默認(rèn)是參數(shù)的長度+16

超過默認(rèn)長度后到旦,會增加

使用append()方法在字符串后面追加?xùn)|西的時候旨巷,如果長度超過了該字符串存儲空間大小了就需要進(jìn)行擴(kuò)容:構(gòu)建新的存儲空間更大的字符串,將舊的的復(fù)制過去添忘;


再進(jìn)行字符串a(chǎn)ppend添加的時候采呐,會先計算添加后字符串大小,傳入一個方法:ensureCapacityInternal 這個方法進(jìn)行是否擴(kuò)容的判斷搁骑,需要擴(kuò)容就調(diào)用expandCapacity方法進(jìn)行擴(kuò)容:

? ? char[] value;

? ? int count;


嘗試將新容量擴(kuò)為 大懈隆:變成2倍+2,容量如果還不夠仲器,直接擴(kuò)充到需要的容量大忻郝省;

1.String

1)類定義

public final class String

??? implements java.io.Serializable, Comparable<String>, CharSequence

String類是個final類乏冀,實(shí)現(xiàn)了序列化接口蝶糯,比較大小接口和只讀字符序列接口。String和其他八個基本數(shù)據(jù)類型的包裝類共同為不可變類辆沦。

(2)主要變量

private final char value[];

String類的底層基本是char類型數(shù)組昼捍,String的一些基本方法也是調(diào)用char數(shù)組的基本方法。

(3)主要構(gòu)造方法

public String() {

  this.value = "".value;

}

String的默認(rèn)值為"";

(4)String常量池

jvm在啟動時就會加載的一塊空間肢扯,符串常量池的特點(diǎn)就是有且只有一份相同的字面量妒茬,如果有其它相同的字面量,jvm則返回這個字面量的引用蔚晨,如果沒有相同的字面量乍钻,則在字符串常量池創(chuàng)建這個字面量并返回它的引用。通過使用new關(guān)鍵字得對象會放在堆里铭腕,而不會加載到字符串常量池银择,intern()方法能使一個位于堆中的字符串在運(yùn)行期間動態(tài)地加入到字符串常量池中。

(5)字符串拼接

String字符串拼接一般通過用+號實(shí)現(xiàn)谨履,正常情況下有兩種形式:

String a = "ab" + "cd";

此時在JVM在編譯時就認(rèn)為這個加號是沒有用處的欢摄,編譯的時候就直接變成abcd,即使是后面添加多個字符串效率不會比StringBuiler或者StringBuffer慢笋粟。

String a = "ab";

String b = "cd";

String c = a + b;

此時字符串拼接系統(tǒng)會優(yōu)化成通過new StringBuiler怀挠,進(jìn)行兩次append操作析蝴,該操作是在堆中進(jìn)行,如果是進(jìn)行多次拼接绿淋,會產(chǎn)生多個StringBuiler對象闷畸,效率自然會降低,但是如果是在同一行代碼里做拼接操作吞滞,只是額外new了一個StringBuiler對象佑菩,效率也不會慢。

2.StringBuilder

3)主要構(gòu)造方法

public StringBuilder() {

  super(16);

}

AbstractStringBuilder(int capacity) {

  value = new char[capacity];

}

StringBuiler類的基本構(gòu)造方法是一個容量為16的字符串?dāng)?shù)組

(4)字符串拼接

public StringBuilder append(String str) {

??? super.append(str);

??? return this;

}

public AbstractStringBuilder append(String str) {

??? if (str == null)

??????? return appendNull();

??? int len = str.length();

??? ensureCapacityInternal(count + len);

??? str.getChars(0, len, value, count);

??? count += len;

??? return this;

}

private void ensureCapacityInternal(int minimumCapacity) {

??? // overflow-conscious code

??? if (minimumCapacity - value.length > 0) {

????????? value = Arrays.copyOf(value,

??????????????? newCapacity(minimumCapacity));

??? }

}

內(nèi)部的實(shí)現(xiàn)是通過char數(shù)組操作的裁赠,如果超過容量殿漠,會發(fā)生通過數(shù)組拷貝方式的擴(kuò)容操作。

(5)線程安全性

  從上面的源碼解析佩捞,count += len;并非原子操作绞幌,如果兩個線程同時訪問到這個方法,那么AbstractStringBuilder中的count是不是就是相同的一忱,所以這兩個線程都是在底層char數(shù)組的count位置開始append添加莲蜘,那么最終的結(jié)果肯定就是在后執(zhí)行的那個線程append進(jìn)去的數(shù)據(jù)會將前面一個覆蓋掉,所以StringBuilder在字符串拼接操作是線程不安全的帘营。由于String的拼接也是通過StringBuiler來實(shí)現(xiàn)票渠,所以String的字符拼接也不是線程安全的

3.StringBuffer

(1)類定義

public final class StringBuffer

??? extends AbstractStringBuilder

??? implements java.io.Serializable, CharSequence

StringBuffer其父類實(shí)現(xiàn)了只讀字符序列接口和拼接接口,與StringBuilder有公共的父類AbstractStringBuilder芬迄,該類是可變類问顷。

(2)主要變量

StringBuffer的底層基本實(shí)現(xiàn)和StringBuilder是一致的。

(3)構(gòu)造方法

StringBuffer的構(gòu)造方法和StringBuilder是一致的薯鼠。

4)字符串拼接

public synchronized StringBuffer append(String str) {

??? toStringCache = null;

??? super.append(str);

??? return this;

}


StringBuffer字符串拼接基本與StringBuilder內(nèi)部實(shí)現(xiàn)是一致的择诈,主要是區(qū)別是在方法體上通過synchronized關(guān)鍵字加鎖。

(5)線程安全性

  從上面的源碼解析出皇,由于在方法加上synchronize關(guān)鍵字,所以字符串拼接操作是線程安全哗戈。

備注:在正式面試時郊艘,基本回答三者的區(qū)別是:String是不可變類,StringBuffer和StringBuilder是可變類唯咬;String在多次字符串拼接時效率低纱注,且線程不安全,StringBuilsder效率最高胆胰,但是線程不安全狞贱,StringBuffer效率在前兩者其中,但是線程安全蜀涨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瞎嬉,一起剝皮案震驚了整個濱河市蝎毡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌氧枣,老刑警劉巖沐兵,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異便监,居然都是意外死亡扎谎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進(jìn)店門烧董,熙熙樓的掌柜王于貴愁眉苦臉地迎上來毁靶,“玉大人,你說我怎么就攤上這事逊移±铣洌” “怎么了?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵螟左,是天一觀的道長啡浊。 經(jīng)常有香客問我,道長胶背,這世上最難降的妖魔是什么巷嚣? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮钳吟,結(jié)果婚禮上廷粒,老公的妹妹穿的比我還像新娘。我一直安慰自己红且,他們只是感情好坝茎,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著暇番,像睡著了一般嗤放。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上壁酬,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天次酌,我揣著相機(jī)與錄音,去河邊找鬼舆乔。 笑死岳服,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的希俩。 我是一名探鬼主播吊宋,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼颜武!你這毒婦竟也來了璃搜?” 一聲冷哼從身側(cè)響起拖吼,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎腺劣,沒想到半個月后绿贞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡橘原,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年籍铁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片趾断。...
    茶點(diǎn)故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡拒名,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芋酌,到底是詐尸還是另有隱情增显,我是刑警寧澤,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布脐帝,位于F島的核電站同云,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏堵腹。R本人自食惡果不足惜炸站,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望疚顷。 院中可真熱鬧旱易,春花似錦、人聲如沸腿堤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽笆檀。三九已至忌堂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間误债,已是汗流浹背浸船。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寝蹈,地道東北人。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓登淘,卻偏偏與公主長得像箫老,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子黔州,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評論 2 361