| 網(wǎng)站首頁 | 關(guān)于我們 | 開發(fā)優(yōu)勢 | 產(chǎn)品展示 |
| 合作企業(yè) | 新聞動(dòng)態(tài) | 聯(lián)系我們 | 電話聯(lián)系 |
文章作者:濟(jì)南軟件開發(fā) 時(shí)間:2016年09月27日
Java中創(chuàng)建對象的常規(guī)方式有如下5種:
1. 通過new調(diào)用構(gòu)造器創(chuàng)建Java對象;
2. 通過Class對象的newInstance()方法調(diào)用構(gòu)造器創(chuàng)建對象;
3. 通過Java的反序列化機(jī)制從IO流中恢復(fù)對象;
4. 通過Java對象提供的clone方法復(fù)制一個(gè)對象;
5. 基本類型及String類型,可以直接賦予直接量。
對于Java中的字符串直接量,JVM會(huì)使用一個(gè)字符串池來保存它們:當(dāng)?shù)谝淮问褂媚硞€(gè)直接量時(shí),JVM會(huì)將它放入字符串池中緩存,在一般情況下,字符串池中的字符串不會(huì)被Java回收器回收,當(dāng)程序再次使用該直接量時(shí),無需重新創(chuàng)建一個(gè)新的字符串,而是直接讓引用變量指向字符串池中已經(jīng)存在的字符串。
字符串池中的字符串是不會(huì)被回收的,這是Java內(nèi)存泄漏的一個(gè)原因。
如果程序需要一個(gè)字符序列會(huì)改變的字符串,那么應(yīng)該考慮使用StringBuilder或StringBuffer,當(dāng)然,最好還是使用StringBuilder,因?yàn)閷τ诰€程安全的StringBuffer,StringBuilder是線程不安全的,也就是說,StringBuffer中的絕大部分代碼都加了synchronized修飾符。
如果你的代碼所在的程序或進(jìn)程是多個(gè)線程同時(shí)運(yùn)行的,而這些線程會(huì)同時(shí)運(yùn)行這段代碼,如果每次運(yùn)行結(jié)果和單線程運(yùn)行結(jié)果一樣,而且其他變量的值也和預(yù)期的一樣,就是線程安全的,或者說,多個(gè)線程的切換不會(huì)導(dǎo)致該接口的執(zhí)行結(jié)果存在二義性,我們就說該接口是線程安全的。
Java是強(qiáng)類型語言,所謂強(qiáng)類型語言,通常具有兩個(gè)基本特征:
1. 所有變更必須先聲明才能使用,聲明變量時(shí)必須指定該變量的數(shù)據(jù)類型;
2. 一量某個(gè)變量的數(shù)據(jù)類型確定下來,那么該變量永遠(yuǎn)只能接受該類型的數(shù)據(jù),不能接受其他類型的數(shù)據(jù)。
當(dāng)一個(gè)算術(shù)表達(dá)式中包含多個(gè)基本類型時(shí),整個(gè)算術(shù)表達(dá)式的數(shù)據(jù)類型會(huì)自動(dòng)提升,這是我們已經(jīng)知道的規(guī)定。在此之外有個(gè)特例,請看以下代碼:
[java]
<span style="font-size:18px">short sv = 5;
sv = sv - 2;</span>
我們通常不能理解的一個(gè)問題是:這段代碼會(huì)報(bào)錯(cuò)。但結(jié)合數(shù)據(jù)類型的自動(dòng)提升,我們可以這樣理解:sv - 2中,2是int型,所以sv - 2的結(jié)果是一個(gè)int型,所以不能賦值給sv。
再看以下代碼:
[java]
<span style="font-size:18px">short sv = 5;
sv -= 2;</span>
如果你再用自動(dòng)類型提升來理解的話,你會(huì)解釋為這一段代碼結(jié)果也會(huì)報(bào)錯(cuò),可惜,Java中還有另一規(guī)定:復(fù)合賦值運(yùn)算符包含了一個(gè)隱式的類型轉(zhuǎn)換,sv -= 2其實(shí)等價(jià)于sv = (short)(sv - 2)。
顯然這里又出現(xiàn)了另外一個(gè)問題:將巨大的int轉(zhuǎn)化為short會(huì)出什么問題嗎?且看如下代碼:
[java]
<span style="font-size:18px">short sv = 5;
sv += 9000;</span>
我們已知,short類型的數(shù)值范圍在-32768~32767之間,所以當(dāng)把9005賦值給sv時(shí),就會(huì)出現(xiàn)高位截?cái)?,sv的最終結(jié)果為24471。
由此可見,復(fù)合賦值運(yùn)算符簡單、方便,而且具有性能上的優(yōu)勢,但復(fù)合賦值運(yùn)算符可能有一定的危險(xiǎn):它潛在的隱式類型轉(zhuǎn)換可能會(huì)不知不覺中導(dǎo)致計(jì)算結(jié)果的高位截?cái)唷?/p>
且看以下代碼:
[java]
<span style="font-size:18px">List list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
List<Integer> intList = list;
for (int i = 0; i < list.size(); i++) {
System.out.println(intList.get(i));
}</span>
當(dāng)我看到這段代碼的時(shí)候,我理所當(dāng)然的認(rèn)為這段代碼是錯(cuò)誤的,因?yàn)閘ist里面包含的是String,不能賦值給List<Integer>,而在Eclipse里面運(yùn)行這段代碼后,你會(huì)發(fā)現(xiàn)這段代碼沒有任何錯(cuò)誤,可以編譯,也可以運(yùn)行,這就是泛型里面的陷阱。在使用泛型時(shí),要注意以下幾點(diǎn):
1. 當(dāng)程序把一個(gè)原始類型的變量賦值給一個(gè)帶泛型信息的變量時(shí),總是可以通過編譯,只是會(huì)提出一些警告,如上述代碼中,List<Integer> intList = list并不會(huì)報(bào)錯(cuò);
2. 當(dāng)程序試圖訪問帶泛型聲明的集合的集合元素時(shí),編譯器總是把集合元素當(dāng)成泛型類型處理——它并不關(guān)心集合里集合元素的實(shí)際類型,如上述代碼中,intList.get(i)的結(jié)果是一個(gè)Integer類型;
3. 當(dāng)程序試圖訪問帶泛型聲明的集合的集合元素時(shí),JVM會(huì)遍歷每個(gè)集合元素自動(dòng)執(zhí)行強(qiáng)制類型轉(zhuǎn)換,如果集合元素的實(shí)際類型與集合所帶的泛型信息不匹配,運(yùn)行時(shí)將引發(fā)ClassCastException異常,假設(shè)在上述代碼的for循環(huán)中加上Integer in = intList.get(i),就會(huì)報(bào)此異常。
上面講的是把原始類型賦值給泛型類型,假如反過來呢?且看以下代碼:
[java]
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
List li = list;
for (int i = 0; i < list.size(); i++) {
System.out.println(li.get(i));
System.out.println(li.get(i).length()); // 1)
}
你會(huì)發(fā)現(xiàn)1)處的代碼編譯錯(cuò)誤,這是因?yàn)椤岩粋€(gè)帶泛型類型的Java變量賦值給一個(gè)不帶泛型類型的變量時(shí),Java程序會(huì)發(fā)生擦除,這種擦除不僅僅會(huì)擦除實(shí)際類型實(shí)參,還會(huì)擦除所有泛型信息,如上述代碼,li.get(i)是終被當(dāng)成一個(gè)Object對象使用。
Java泛型設(shè)計(jì)原則:如果一段代碼在編譯時(shí)系統(tǒng)沒有產(chǎn)生“[unchecked]未經(jīng)檢查的轉(zhuǎn)換”警告,則程序在運(yùn)行時(shí)不會(huì)引發(fā)ClassCastException異常。
從JDK1.5開始,Java提供了三種方式來創(chuàng)建、啟動(dòng)多線程:
1. 繼承Thread類來創(chuàng)建線程類,重寫run()方法作為線程執(zhí)行體;
2. 實(shí)現(xiàn)Runnable接口來創(chuàng)建線程類,重寫run()方法作為線程執(zhí)行體;
3. 實(shí)現(xiàn)Callable接口來創(chuàng)建線程類,重寫run()方法作為線程執(zhí)行體;
其中,第一種方式效果最差,它有兩點(diǎn)壞處:
1. 線程類繼承了Thread類,無法再繼承其他父類;
2. 因?yàn)槊織l線程都是一個(gè)Thread子類的實(shí)例,因此多個(gè)線程之間共享數(shù)據(jù)比較麻煩。
對于第二種和第三種,它們的本質(zhì)是一樣的,只是Callable接口里面包含的call()方法既可以聲明拋出異常,也可以擁有返回值。
無論使用哪種方式,都不要調(diào)用run()方法來啟動(dòng)線程:啟動(dòng)線程應(yīng)該使用start()方法,如果程序從未調(diào)用線程對象的start()方法來啟動(dòng)它,那么這個(gè)線程對象將一直處于新建狀態(tài)。
想要了解更多詳情歡迎來電咨詢18678812288
登陸網(wǎng)址:m.h6244.cn。
聯(lián)系人:王經(jīng)理。