1. 程式人生 > >java學習筆記(九)-- java新特性 ( 可變引數 & 泛型 & 靜態匯入 & 型別擦除 )

java學習筆記(九)-- java新特性 ( 可變引數 & 泛型 & 靜態匯入 & 型別擦除 )

JDK1.5新特性

  • 方法的可變引數

            設計一個方法,可以接收任意個數的整數,並返回他們的相加結果

            早期實現方式:

public class Test {
    public static void main(String[] args) {
        System.out.println(add(new int[]{1,2,3}));
        System.out.println(add(new int[]{1,2,3,4,5,6}));
        System.out.println(add(new int[]{1,2,3,4,5,6,7,8,9}));
    }
    public static int add(int []data){
        int result=0;
        for(int temp:data){
            result+=temp;
        }
        return result;
    }
}

            可變引數列表實現:

public class Test {
    public static void main(String[] args) {
        //可以直接接受內容
        System.out.println(add(1,2,3));
        //可變引數列表可以接受陣列
        System.out.println(add(new int[]{1,2,3,4,5,6}));
        System.out.println(add(new int[]{1,2,3,4,5,6,7,8,9}));
    }
    public static int add(int ... data){
        int result=0;
        for(int temp:data){
            result+=temp;
        }
        return result;
    }
}

           可變引數--語法

            資料型別 ··· 可變引數名稱

            int  ···  data 

            可變引數的本質還是陣列

            一個方法中只允許一個可變引數,並且可變引數一定是方法最後一個引數,由於可變引數中傳遞引數的數量是未知的,所以一個方法中最多隻能存在一個可變引數列表,而且當存在多類引數時,可變引數放在方法最後

public class Test {
    public static void main(String[] args) {
        //可以直接接受內容
        System.out.println(add("Hello world",1,2,3));
        //可變引數列表可以接受陣列
        System.out.println(add("Hello world",new int[]{1,2,3,4,5,6}));
        System.out.println(add("Hello world",new int[]{1,2,3,4,5,6,7,8,9}));
    }
    public static int add(String msg,int ... data){
        int result=0;
        for(int temp:data){
            result+=temp;
        }
        return result;
    }
}
  • foreach迴圈  只用於陣列,類集內容的取得,不能修改原陣列,類集內容。

            for(資料型別 臨時變數:陣列名/類集名)

            for(int temp:data)

  • 靜態匯入   import  static  (瞭解,不使用)

            將一個類的所有靜態域(包括靜態屬性,方法)

            全部匯入的使用類中,此時呼叫屬性和方法不再需要類名。

範例:定義一個util類

package www.Dyson.java;
public class util {
    public static int add(int n,int m){
        return m+n;
    }
    public static int sub(int n,int m){
        return n-m;
    }
}

範例:使用util方法,直接同過類名去呼叫

package www.Dyson.java;
import www.Dyson.java.util;
public class Test {
    public static void main(String[] args) {
        System.out.println(util.add(1,5));
        System.out.println(util.sub(5,1));
    }
}

範例:靜態匯入,不需要通過類名去呼叫

package www.Dyson.java;
import static www.Dyson.java.util.*;
public class Test {
    public static void main(String[] args) {
        System.out.println(add(1,5));
        System.out.println(sub(5,1));
    }
}
  • 泛型  (出於安全性考慮,不再有型別轉換異常)解決型別轉換異常 ClassCastException  Java語法糖

            1. 泛型類;所謂的泛型指在類定義的時候並不會設定類中屬性或方法的引數的具體型別,而是在類使用的時候在定義

            泛型類的定義

            語法:

class  Myclass<T>{
      T t;
}

<>中的T被稱為引數型別,用於指代任何型別。處於規範起見型別引數一般由單個大寫字母表示。

            T:用於泛型宣告上,指代泛型類;

            E:一般用於屬性

            K,V:鍵值對

            當泛型類中需要多個不同型別變數時,<>以,分隔宣告不同大寫字母即可

class MyClass <T,E>{
    T t;
    E e;
}

            泛型的出現徹底解決了向下轉型帶來的ClassCastException異常

            泛型只能使用引用型別,基本型別使用包裝類

範例:使用泛型類

Myclass<String> myClass1 = new MyClass<String>();
MyClass<Integer> myClass = new MyClass<Integer>();

使用範例:

package www.Dyson.java;
class Point<T>{
    private T x;
    private T y;
    public T getX() {
        return x;
    }
    public T getY() {
        return y;
    }
    public void setX(T x) {
        this.x = x;
    }
    public void setY(T y) {
        this.y = y;
    }
}
public class Test {
    public static void main(String[] args) {
        Point<String> p=new Point<String>();
        p.setX("東經20度");
        p.setY("北緯40度");
        //避免了向下轉型
        String x=p.getX();
        String y=p.getY();
        System.out.println("x="+x+" y="+y);
    }
}

            2. 泛型方法

            語法:

            泛型方法   返回值   引數

public <T> void method ( T  t ) {

}

            當泛型類與泛型方法共存時,泛型方法中的型別引數與泛型類的型別引數無關,泛型方法始終以自己的型別引數為準。

            規範起見,當泛型類與泛型方法共同使用時,請使用不同的引數型別來區別彼此。

class MyClass<T>{
    public void testMethod1(T t){
        System.out.println(t);
    }
    public <E> E testMethod2(E e){
        return e;
    }
}

                3 萬用字元   <******* 重點 *******>  面試考點

                3.1. ?萬用字元--作用於方法引數宣告

                public static void print(MyClass<?> myClass);

                此時方法可以接收任何型別的Myclass物件

                由於無法確定入參型別,因此?萬用字元下的泛型引數,只能取得類中屬性值,無法進行屬性值的修改

public class TestDemo {    
    public static void main(String[] args) {        
        Message<Integer> message = new Message() ;         
        message.setMessage(55);        
        fun(message);    
    }    
    // 此時使用萬用字元"?"描述的是它可以接收任意型別,但是由於不確定型別,所以無法修改    
    public static void fun(Message<?> temp){         
        //temp.setMessage(100); 無法修改!        
        System.out.println(temp.getMessage());  
    }  
}

                3.2.設定泛型的上限--用於泛型類的宣告,也可用於方法引數

                泛型類宣告:T extends 類 (T <= 類)

                方法引數:?extends 類

                eg:?extends Number;

                表示方法入參只能接收Number以及子類物件

                方法引數設定泛型上限仍然只能取得類中屬性值,而無法設定,因為設定父類值子類不一定能使用(父類不一定能發生向下轉型變為子類)。

package www.Dyson.java;
class Message<T extends Number> {
    // 設定泛型上限
    private T message ;
    public T getMessage() {
        return message;
    }
    public void setMessage(T message) {
        this.message = message;
    }
}
public class Test {
    public static void main(String[] args) {
        Message<Integer> message = new Message();
        message.setMessage(55);
        fun(message);
    }
    // 此時使用萬用字元"?"描述的是它可以接收任意型別,但是由於不確定型別,所以無法修改
    public static void fun(Message<? extends Number> temp) {
        //temp.setMessage(100); 仍然無法修改!
        System.out.println(temp.getMessage());
    }
}

                3.3. 設定泛型下限--只能用於方法引數

                ?super 類(>= 類)

                表示方法入參只能接收類以及其父類物件

                只有super可以設定屬性值,天然的向下轉型,不能使用extends類設定屬性值,因為不確定其子類型別

                方法引數設定泛型下限,不僅可以取得類中屬性值,還可以設定屬性值。因為子類可以天然的向上轉型變為父類。

package www.Dyson.java;
class Message<T> {
    private T message ;
    public T getMessage() {
        return message;
    }
    public void setMessage(T message) {
        this.message = message;
    }
}
public class Test {
    public static void main(String[] args) {
        Message<String> message = new Message() ;
        message.setMessage("Hello World");
        fun(message);
    }
    public static void fun(Message<? super String> temp){
        // 此時可以修改!!
        temp.setMessage("bit!");
        System.out.println(temp.getMessage());
    }
}

                4. 泛型介面

                定義一個泛型介面

interface Imessage<T>{
    public void print(T t);
}

               1. 子類實現介面時繼續保持泛型

Class MessageImp<T> implements IMessage<T>{

    public void print(T t){

        System.out.println(t);

    }
}

               2. 子類實現介面時就確定好型別

Class MessageImp<String> implements IMessage<T>{

    public void print(Strig t){
        System.our.println(t);

    }
}

                5. 型別擦除   <***** 重要 *****>  面試考點 賊重要  在JVM眼中就不存在泛型,都是確定指定型別

                便編譯資訊僅存在程式碼編譯階段,進入JVM之前,與泛型相關的資訊會被擦除掉,專業術語就叫型別擦除

                換句話說,泛型類與普通類在JVM中沒有任何區別

                泛型類進入JVM之前,會進行型別擦除,泛型類的型別引數如果沒有指定型別上限,則擦除成為Object類;如果型別引數指定型別上限,擦除為相應型別上限

                <T> -> Object

                <T extends String> -> String