1. 程式人生 > >JDK 1.5 新特性

JDK 1.5 新特性

前言:為什麼會出現新特性呢?

     新的技術的出現就是為了解決老的問題,Java語言隨著自身的不斷髮展,對那些不利於提高開發率的技術進行了改進。

1.靜態匯入

  靜態匯入可以匯入靜態方法,這樣就不必寫類名而可以直接省略類名呼叫靜態方法了。

  語法:import static 包名.類名.靜態方法;

  也可以直接匯入某個類中的所以靜態方法。

  語法:import static 包名.類名.*;

  Java 5.0 程式碼示例:

package com.tolvgx.day01;
import static java.lang.Math.*;
import static java.lang.System.out;

public class StaticImport {
    public static void main(String[] args) {
        out.println("接近數最小值: "+floor(PI));
        out.println("接近數最大值: "+ceil(PI));
        out.println("2的3次冪:"+pow(2, 3));
        out.println("四捨五入:"+round(PI));
    }
}

  好處:

    使用靜態匯入可以簡化程式對類靜態屬性和方法的呼叫,並且簡化了程式程式碼的書寫。

  弊端:

雖然JDK中出現了這個新特性,但是如果我們在自己的類中定義 了一個方法,與匯入的類中的靜態方法一樣。

    那Java虛擬機器怎麼知道用的是那個類的方法呢?所以雖然出現了這個新特性,但是建議還是別使用。

  注意:

    如果將Javac設定為了Java 5.0以下,那麼靜態匯入等JDK 1.5的特性都會報告錯誤。

2.可變引數

  可變引數的出現解決了一個方法接受的引數個數不固定的問題。

    例如:System.out.println(countScore(2,3,5));

         System.out.println(countScore(1,2,3,5));

    如果使用過載的方式解決需要寫多個過載的方法,可是程式碼過於繁雜,而使用可變引數就可以避免這種情況。

  Java 5.0 程式碼示例:

package com.tolvgx.day01;

public class VariableParameter {
    public static void main(String[] args) {
        System. out.println(add(1, 2));
        System. out.println(add(1, 2, 3));
    }

    public static int add(int x,int... args){
        int sum = x;
        for(int i = 0; i < args.length; i++){
        sum += args[i];
        }  
        return sum;
    }
}

  可變引數的原理:  

    呼叫可變引數的方法時, 編譯器將自動建立一個數組儲存傳遞給方法的可變引數。

    因此,程式設計師可以在方法體中以陣列的形式訪問可變引數可變引數只能處於引數列表的最後。

    所以一個方法最多隻能有一個可變引數。

  可變引數特點與注意事項:

    1、可變引數只能出現在引數列表的最後。 

    2、可變引數只能在引數中只能有一個。

    3、可變引數位於變數型別和變數名之間,前後有無空格都可以。

      4、呼叫可變引數的方法時,編譯器為該可變引數隱含建立一個數組,在方法體中以陣列的形式訪問可變引數。

3.增強for迴圈

引入增強for迴圈的原因:

    在JDK 1.5 以前的版本中,遍歷陣列或集合中的元素,需先獲得陣列的長度或集合的迭代器,比較麻煩!

    因此JDK 1.5 中定義了一種新的語法——增強for迴圈,以簡化此類操作。

  語法格式:

    for(修飾符 變數型別 變數  :需迭代的陣列或集合){}

  Java 5.0 程式碼示例:

package com.tolvgx.day01;

public classForeach {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        for(final int i : arr) {
            System.out.println(i);
        }
    }
}

  注意事項:

    迭代變數必須在( )中定義!

    集合變數可以是陣列或實現了Iterable介面的集合類。

  小細節:

    向集合中取元素時同時加元素,需要使用迭代器來完成,即需要傳統的for迴圈。

4.自動拆箱與裝箱

JDK 1.5的語法允許開發人員把一個基本資料型別直接賦給對應的包裝類變數, 或者賦給 Object 型別的變數,這個過程稱之為自動裝箱。

  自動拆箱與自動裝箱與之相反,即把包裝類物件直接賦給一個對應的基本型別變數。

  Java 5.0 程式碼示例:

package com.tolvgx.day01;
import java.util.List;
import java.util.ArrayList;

public class Test{
    public static void main(String[] args){
        List list = new ArrayList();
        //因為集合中不能儲存基本資料型別資料。            
        list.add(1);
        //會自動的裝箱成(new Integer(1));
        int i = (Integer)list.get(0);//自動拆箱。
    }
}

  好處:

    新特性的出現,程式設計師省去了很多不必要的麻煩,提高了開發效率。

package com.tolvgx.day01;

public class AutoBox {
    public static void main(String[] args) {
        Integer i1 = 127;
        Integer i2 =Integer.parseInt("127");
        System.out.println(i1==i2);
       
        Integer i3 = 128;
        Integer i4 = 128;
        System.out.println(i3==i4);   
    }
}

  byte常量池:

    對於這些基本資料整數要裝箱成Integer物件的時候,如果這個資料在1位元組(-128 ~ 127)之內的數字,就快取在byte常量池,下次再用到的時候,先看池子裡面有沒有,如果有直接從池子裡面拿來用。這樣節省了記憶體空間。

    這是一種設計模式叫做享元模式。(flyweight)

  享元模式:

    就是有很多個小的物件,他們有很多屬性相同,把他們封裝成一個物件,那些不同的屬性,把它們變為方法的引數,稱之為外部狀態,那些相同的屬性的稱之為這個物件的內部狀態。例如,示例中的Integer物件,在-128~127範圍內的Integer物件,用的頻率比較高,就會作為同一個物件,因此結果為true。超出這個範圍的就不是同一個物件,因此結果為false。

  享元應用:

    1、Word中輸入英文字母,可建立26物件。

      每個物件值是出現的位置不同(座標),所以可用一個物件呼叫位置的方法。

      如,字母Q:Q.zuobiao(int x,int y),將高度重複使用的char型別的字母Q封裝成一個物件使用。

    2、圖示:Window下的資料夾圖示,只是名稱這個屬性不同,包含了很多其他相同的屬性,那麼可以應用享元模式。

5.列舉

為什麼需要列舉?

一些方法在執行時,它需要的資料不能是任意的,而必須是一定範圍內的值。

    此類問題在JDK 1.5 以前採用自定義帶有列舉功能的類解決,Java 5.0以後可以直接使用列舉予以解決。

    JDK 1.5 新增的Enum 關鍵字用於定義一個列舉類。

  自定義類實現列舉功能:

1、私有的構造方法。

    2、每個元素分別用一個公有的靜態成員變量表示。

     3、可以自定義若干個公有方法或抽象方法。

       程式碼示例:

package com.tolvgx.day01;

public class WeekDay {
    
    private WeekDay() {}

    public static finalWeekDay SUN = new WeekDay();
    public static final WeekDay MON = new WeekDay();

    public WeekDay nextDay() {

        if (this == SUN) {
            return MON;
        } else {
            return SUN;
        }
    }

    public String toString() {

        return this == SUN ? "SUN" :"MON";
    }
}

  注意:

    可以採用抽象方法定義nextDay將大量的if...else語句轉移到一個個獨立的物件中實現。

  程式碼示例:

package com.tolvgx.day01;

public abstract class WeekDay {

    private WeekDay() {}

    public static final WeekDay SUN = new WeekDay() {

    public WeekDay nextDay() {

        return MON;
    }
};

public static final WeekDay MON =new WeekDay() {

    public WeekDay nextDay() {

        return MON;
    }
};

public abstract WeekDay nextDay();

    public String toString() {

        return this == SUN ? "SUN" :"MON";
    }
}

  程式碼測試:

package com.tolvgx.day01;

public class WeekDayTest {
  
    public static void main(String[] args) {

        WeekDay Mon = WeekDay.MON;
        System.out.println(Mon);
    }
}

  Java5列舉的定義:

    程式碼示例:

package com.tolvgx.day01;

public enum WeekDay {

    SUN,MON,TUE,WED,TUR,FRI,SAT;

}

    注意:

      最後一個列舉元素後面可以加分號,也可以不加分號。

    程式碼測試:

package com.tolvgx.day01;

public class WeekDayTest {
    public static void main(String[] args) {
        WeekDay weekDay = WeekDay.SUN;
        for(WeekDay weekday: weekDay.values()){    
            System.out.println("第一個是:"+weekday.ordinal()+" 星期:"+weekday.name());
         }

    WeekDay weekday = WeekDay.valueOf("SUN");
    System.out.println(weekday);
    System.out.println(WeekDay.values().length);
    }
}

  Java中宣告的列舉類,均是java.lang.Enum類的子類,它繼承了Enum類的所有方法。

  常用方法:

    name()

    ordinal()

    valueOf(String name)

    values() 此方法雖然在JDK文件中查詢不到,但每個列舉類都具有該方法。它遍歷列舉類的所有列舉值非常方便。

  實現帶有構造方法的列舉

    Java 5.0 程式碼示例:

package com.tolvgx.day01;

public classTrafficLampTest {      
    public static void main(String[] args) {
       
         System.out.println(TrafficLamp.YELLOW);
    }

    public enum TrafficLamp{

        RED(60),YELLOW(5),GREEN(30);

        private TrafficLamp(){

            System.out.println("First");
            System.out.println(this.name());
        }

        private TrafficLamp(int time){

            System.out.println("Second");
            try {
                Thread.sleep(time*1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("等待了"+time+"秒"+this.name());
        }

    }
}

  實現帶有抽象方法的列舉:

    定義列舉TrafficLamp。
    實現抽象的nextTrafficLamp方法:每個元素分別是由列舉類的子類來生成的例項物件,這些子類採用類似內部類的方式進行定義。增加上表示時間的構造方法。

               Java 5.0 程式碼示例:

package com.tolvgx.day01;

public class TrafficLampTest {
    public static void main(String[] args) {

        System.out.println(Lamp.YELLOW.nextLamp());
    }

    public enum Lamp{

        RED(60){

            public Lamp nextLamp(){
    
                System.out.println("暫停60秒");

                return YELLOW;
            } 

        },YELLOW(10){

            public Lamp nextLamp(){

                System.out.println("等待10秒");
   
             return GREEN;
            } 
  
         },GREEN(30){

            public Lamp nextLamp(){

                System.out.println("放行30秒");

                return RED;

            } 
        };

        private Lamp(int time){

            System.out.println("先把列舉所有元素載入進記憶體   "+this.name());

        }

        public abstract Lamp nextLamp();

    }
}

  列舉類總結:

1、列舉類是一種特殊形式的Java類。

    2、列舉類中宣告的每一個列舉值代表列舉類的一個例項物件。

    3、列舉類與Java中的普通類一樣,在宣告列舉類時,也可以宣告屬性、方法和建構函式。

      但列舉類的建構函式必須為私有的(這點不難理解)。

    4、列舉類也可以實現介面、或繼承抽象類。

    5、JDK 1.5 中擴充套件了switch語句,它除了可以接收int, byte, char, short,String外,還可以接收一個列舉型別。

    6、若列舉類只有一個列舉值,則可以當作單例設計模式使用。

    7、列舉類的例項變數是把所以的列舉例項都載入一次的。

      如果呼叫了某個列舉類,那麼該列舉類先把列舉類裡面的所有元素都先載入一次。

  注意:

1、列舉只有一個成員時,就可以作為一種單例的實現方式。

    2、檢視生成的class檔案,可以看到內部類對應的class檔案。

      也就是列舉的元素都是一個內部類例項物件。

6.內省(IntroSpector)

  見單獨隨筆詳解。

7.泛型  

  見單獨隨筆詳解。

8.註解

見單獨隨筆詳解。