九九热这里直有精品,1区二区三区在线播放,玖玖爱在线观看资源,国产aⅴ综合网,午夜福利男女,日本亚洲欧美三级,日韩无码黄色导航,内射少妇13区,中文字幕高清网

您身邊的軟件定制專家--9年開發(fā)經(jīng)驗(yàn)為您護(hù)航

18678812288
0531-88887250

軟件開發(fā)中Java中的陷阱

文章作者:濟(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)理。

浦北县| 沾化县| 榆社县| 吐鲁番市| 荥阳市| 浪卡子县| 驻马店市| 香港| 黎川县| 潞西市| 巴中市| 黄冈市| 农安县| 马山县| 石河子市| 扎兰屯市| 望奎县| 晋宁县| 孝昌县| 大港区| 丰顺县| 闻喜县| 白河县| 白朗县| 湘阴县| 潼南县| 上栗县| 四子王旗| 新建县| 泸定县| 武穴市| 江城| 罗定市| 吉木萨尔县| 潼南县| 临夏市| 抚顺县| 酒泉市| 廉江市| 慈利县| 苏尼特右旗|