JAVA基礎整理(三)

1.包裝類與自動拆箱裝箱

int a1= 1000;int a2=1000;if(a1==a2){System.out.println("yes");}
java

  ==的比較,基本數據類型看的是值是否相等,引用數據類型是看是不是一個對象(地址是否相等)程序員

     Integer a=1377;面試

Integer b=1377;
    if(a==b){
        System.out.println("yes");
    }


在裝箱的時候自動調用的是Integer的valueOf(int)方法。而在拆箱的時候自動調用的是Integer的intValue方法。數組

public static Integer valueOf(int i) {緩存

if (i >= IntegerCache.low && i <= IntegerCache.high)
    return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);

}
安全

由裝箱函數valueof可知,-128~127之間的整數有一個 IntegerCache緩存,不會建立新的對象。多線程

面試題app

public class Main {函數

public static void main(String[] args) {

    Double i1 = 100.0;
    Double i2 = 100.0;
    Double i3 = 200.0;
    Double i4 = 200.0;

    System.out.println(i1==i2);
    System.out.println(i3==i4);
}

}
優化

若是是int型的,100不會建立新對象,200會,可是浮點型的就不同了,看一下double的valueof源碼:

public static Double valueOf(String s) throws NumberFormatException {

return new Double(parseDouble(s));
}

直接new了一個新對象了。(由於double的數表示範圍太大了,-128~127之間幾乎有無數的數字)

總結

     Integer、Short、Byte、Character、Long這幾個類的valueOf方法的實現是相似的。

     Double、Float的valueOf方法的實現是相似的。

    當 "=="運算符的兩個操做數都是 包裝器類型的引用,則是比較指向的是不是同一個對象,而若是其中有一個操做數是表達式(即包含算術運算)則比較的是數值(即會觸發自動拆箱的過程)。

public class Main {

public static void main(String[] args) {

    Integer a = 1;
    Integer b = 2;
    Integer c = 3;
    Integer d = 3;
    Integer e = 321;
    Integer f = 321;
    Long g = 3L;
    Long h = 2L;

    System.out.println(c==d); //在緩存的範圍內,true
    System.out.println(e==f);//不在緩存的範圍內,false
    System.out.println(c==(a+b));//a+b拆箱了,比較的是值,true
    System.out.println(c.equals(a+b));equals比較的是對象,因此拆箱後又裝箱了,可是在緩存以內,仍是同一個對象 true
    System.out.println(g==(a+b));true 比較的是值
    System.out.println(g.equals(a+b));比較的是對象,兩者都不是同一個數據類型的天然new出來不是一個對象,false
    System.out.println(g.equals(a+h));兩者都是long型的,也就是longvalueof方法,也是有-128~127的緩存機制的,true
}

}

2.string,stringbuilder,stringbuffer

2.1String類:(不可變序列)

(1)final char value[]; 由一個字符串數組構成,final修飾,因此不可變。

(2)裏面的一些字符串操做方法其實都是返回了一個新串:看一個源碼函數substring

public String substring(int beginIndex, int endIndex) {

if (beginIndex < 0) {
        throw new StringIndexOutOfBoundsException(beginIndex);
    }
    if (endIndex > value.length) {
        throw new StringIndexOutOfBoundsException(endIndex);
    }
    int subLen = endIndex - beginIndex;
    if (subLen < 0) {
        throw new StringIndexOutOfBoundsException(subLen);
    }
    return ((beginIndex == 0) && (endIndex == value.length)) ? this
            : new String(value, beginIndex, subLen);//new了一個新的string返回了
}


在這裏要永遠記住一點:

「對String對象的任何改變都不影響到原對象,相關的任何change操做都會生成新的對象」。

     String s1="hello";

String s2="hello";
    System.out.println(s1==s2);// true,hello是字符串常量,放在常量池裏
    String s3=new String("hello");
    System.out.println(s1==s3);//false//new後是一個新的對象。

(2)stringbuilder類

public StringBuilder append(String str) {

super.append(str);
    return this;//在原有基礎上作變化的。
}

  StringBuilder和StringBuffer類擁有的成員屬性以及成員方法基本相同,區別是StringBuffer類的成員方法前面多了一個關鍵字:synchronized,不用多說,這個關鍵字是在多線程訪問時起到安全保護做用的,也就是說StringBuffer是線程安全的。因此通常stringbuilder用的居多。

  對於直接相加字符串,效率很高,由於在編譯器便肯定了它的值,也就是說形如」I」+」love」+」java」; 的字符串相加,在編譯期間便被優化成了」Ilovejava」。

  對於間接相加(即包含字符串引用),形如s1+s2+s3; 效率要比直接相加低,由於在編譯器不會對引用變量進行優化。

  String、StringBuilder、StringBuffer三者的執行效率:

StringBuilder > StringBuffer > String

固然這個是相對的,不必定在全部狀況下都是這樣。

好比String str = 「hello」+ 「world」的效率就比 StringBuilder st = new StringBuilder().append(「hello」).append(「world」)要高。

所以,這三個類是各有利弊,應當根據不一樣的狀況來進行選擇使用:

當字符串相加操做或者改動較少的狀況下,建議使用 String str=」hello」這種形式;

當字符串相加操做較多的狀況下,建議使用StringBuilder,若是採用了多線程,則使用StringBuffer。

幾個面試題:

1. 下面這段代碼的輸出結果是什麼?

String a = 「hello2″;   String b = 「hello」 + 2;   System.out.println((a == b));

輸出結果爲:true。緣由很簡單,」hello」+2在編譯期間就已經被優化成」hello2″,所以在運行期間,變量a和變量b指向的是同一個對象。

2.下面這段代碼的輸出結果是什麼?

String a = 「hello2″;   String b = 「hello」; String c = b + 2; System.out.println((a == c));

輸出結果爲:false。因爲有符號引用的存在,因此 String c = b + 2;不會在編譯期間被優化,不會把b+2當作字面常量來處理的,所以這種方式生成的對象事實上是保存在堆上的。所以a和c指向的並非同一個對象。

3.下面這段代碼的輸出結果是什麼?

String a = 「hello2″;   final String b = 「hello」; String c = b + 2; System.out.println((a == c));

輸出結果爲:true。對於被final修飾的變量,會在class文件常量池中保存一個副本,也就是說不會經過鏈接而進行訪問,對final變量的訪問在編譯期間都會直接被替代爲真實的值。那麼String c = b + 2;在編譯期間就會被優化成:String c = 「hello」 + 2

4.下面這段代碼輸出結果爲:

public class Main { public static void main(String[] args) { String a = "hello2"; final String b = getHello(); String c = b + 2; System.out.println((a == c)); } public</code> <code>static</code> <code>String getHello() { return</code> <code>"hello"; }``}

輸出結果爲false。這裏面雖然將b用final修飾了,可是因爲其賦值是經過方法調用返回的,那麼它的值只能在運行期間肯定,所以a和c指向的不是同一個對象。

5.下面這段代碼的輸出結果是什麼?

public class Main { public static void main(String[] args) { String a = "hello"; String b = new</code> <code>String("hello"); String c = new String("hello"); String d = b.intern(); System.out.println(a==b); System.out.println(b==c); System.out.println(b==d); System.out.println(a==d); }}

這裏面涉及到的是String.intern方法的使用。在String類中,intern方法是一個本地方法,在JAVA SE6以前,intern方法會在運行時常量池中查找是否存在內容相同的字符串,若是存在則返回指向該字符串的引用,若是不存在,則會將該字符串入池,並返回一個指向該字符串的引用。所以,a和d指向的是同一個對象,其他都是false

6.String str = new String(「abc」)建立了多少個對象?

這個問題在不少書籍上都有說到好比《Java程序員面試寶典》,包括不少國內大公司筆試面試題都會遇到,大部分網上流傳的以及一些面試書籍上都說是2個對象,這種說法是片面的。

若是有不懂得地方能夠參考這篇帖子:

http://rednaxelafx.iteye.com/...

首先必須弄清楚建立對象的含義,建立是何時建立的?這段代碼在運行期間會建立2個對象麼?毫無疑問不可能。

很顯然,new只調用了一次,也就是說只建立了一個對象。

而這道題目讓人混淆的地方就是這裏,這段代碼在運行期間確實只建立了一個對象,即在堆上建立了」abc」對象。而爲何你們都在說是2個對象呢,這裏面要澄清一個概念 該段代碼執行過程和類的加載過程是有區別的。在類加載的過程當中,確實在運行時常量池中建立了一個」abc」對象,而在代碼執行過程當中確實只建立了一個String對象。

所以,這個問題若是換成 String str = new String(「abc」)涉及到幾個String對象?合理的解釋是2個。

我的以爲在面試的時候若是遇到這個問題,能夠向面試官詢問清楚」是這段代碼執行過程當中建立了多少個對象仍是涉及到多少個對象「再根據具體的來進行回答。

7.下面這段代碼1)和2)的區別是什麼?

public class Main { public static void main(String[] args) { String str1 = "I"; //str1 += "love"+"java"; 1) str1 = str1+"love"+"java"; //2)</code> <code>}``}

1)的效率比2)的效率要高,1)中的」love」+」java」在編譯期間會被優化成」lovejava」,而2)中的不會被優化。

3.Date類

4.Calendar類

5.Dateformat類

6.simpledateformat類

7.exception整理

相關文章
相關標籤/搜索