一、Java高級特性(泛型)

一、爲什麼要使用泛型?

當我們在創建某個方法的時候,參數、返回值類型未知,創建某個類中的成員的時候,類型也是未知的,此時我們可以使用泛型,在我們實際調用方法的時候,或者創建具體的類對象的時候,再設置具體的類型。
或者當我們的方法在考慮到複用性的時候使用泛型。例如不同類型參數都可以接受。

二、泛型類

  • 在類中聲明泛型
public class GenericClass<T> {
    private T data;

    public void setData(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }
}
  • 創建泛型類對象
       GenericClass<String> genericClass = new GenericClass<>();
        genericClass.setData("泛型類");
        System.out.println(genericClass.getData());

三、泛型接口

(1)創建泛型接口

public interface GenericInterface<T> {

    T getData();

    void setData(T t);
}

(2)實現泛型接口

public class GenericInterfaceImpl<T> extends implements GenericInterface<T> {
    private T t;

    @Override
    public T getData() {
        return t;
    }

    @Override
    public void setData(T t) {
        this.t = t;
    }
}

(3)創建泛型接口對象

  GenericInterface<String> genericInterface = new GenericInterfaceImpl<>();
        genericClass.setData("泛型接口");
        System.out.println(genericClass.getData());

四、泛型類的繼承

(1)創建泛型父類


public abstract class GenericAbstarctClass<T> {
    abstract T getData();
    abstract void setTata(T t);

}

(2)泛型子類的繼承

package com.it.test.generic;

public class GenericClassExtends<T> extends GenericAbstarctClass<T> {
    private T t;

    @Override
    T getData() {
        return t;
    }

    @Override
    void setTata(T s) {
        this.t = s;

    }
}

(3)泛型類繼承對象的創建

    GenericAbstarctClass<String> genericAbstarctClass = new GenericClassExtends<>();
        genericAbstarctClass.setTata("繼承使用泛型");
        System.out.printf(genericAbstarctClass.getData());

  • 注意
    我們來看以下代碼,User繼承了Person,但是userGener 和personGener 是兩個獨立的關係,不存在繼承關係。而GenericClassExtends和GenericAbstarctClass纔是繼承關係
   GenericAbstarctClass<User> userGener = new GenericClassExtends<>();
GenericAbstarctClass<Person> personGener = new GenericClassExtends<>();

五、泛型方法

(1)創建泛型方法

   /**
     * 泛型方法
     *
     * @param t
     * @param <T>
     * @return
     */
    static <T> T function(T t) {
        return t;

    }

(2)使用泛型方法
此時function方法的參數和返回類型都是泛型,因此此時可以傳遞任意類型。

   System.out.println(function("泛型方法"));

六、限定類型變量

當我們希望設置泛型的類型必須要包含某個類的行爲時候,可以使用限定類型變量extends。
例如我們希望泛型類中設置的泛型必須包含compareTo方法和add方法
此時我們讓我們的泛型<T extends ArrayList & Comparable>。如果extends中包含了類,則類放在第一位,接口放在後面,接口可以有多個,類和接口直接都用&符號連接。
如下代碼:

/**
 * 如果我們希望泛型包含指定類的方法
 * 我們需要添加限定類型變量
 * extends指定派生類,當有多個派生類的時候
 * 第一個爲類,&符號後面爲接口
 *
 * @param <T>
 */
public class GenericClass2<T extends ArrayList & Comparable> {

    int function(T t) {
        return t.compareTo("a");
    }

    void function2(T t) {
        System.out.println("add= "+t.add("a"));
    }

}

七、通配符類型

通配符類型使用:
? extends Person 限制了類型的上界
? super Person 限制了類型的下界
(1)personGenericType 和userGenericType 中雖然Student繼承了User。但是調用function3(GenericType<Person> type)方法的時候,只能接受personGenericType 。不能接受userGenericType 。因爲userGenericType 和personGenericType 不存在繼承關係。
(2)所以我們需要通配符? extends Person 或者? super Person

  • ? extends Person 的意思指的是GenericType類設置的泛型只要是Person 以下的類都可以接受
  • ? super Person 的意思指的是GenericType類設置的泛型只要是Person 之上的類都可以接受
    我們可以看function4和function5方法
    如下代碼:
  static void function5(GenericType<? super User> type) {
        //? super 可以獲取數據
        type.setData(new User());
        type.setData(new Student());
    }

    static void function3(GenericType<Person> type) {


    }

    static void function4(GenericType<? extends Person> type) {
        //  //? super 可以設置數據
        Person person = type.getData();


    }

  GenericType<Person> personGenericType = new GenericType<>();
        GenericType<User> userGenericType = new GenericType<>();
        GenericType<Student> studentGenericType = new GenericType<>();
        //類型匹配
        function3(personGenericType);
        //類型不匹配,不能編譯
        //類型必須是Person的子類
        function3(userGenericType);
        //使用? extends通配符
        //類型匹配
        function4(personGenericType);
        //類型匹配
        function4(userGenericType);

        //類型匹配
        function5(personGenericType);
        //類型不匹配類型必須是User的超類
        function5(studentGenericType);

八、泛型中的一些約束

(1)不能實例化泛型變量
(2)泛型類中的泛型,不能使用在靜態方法上
(3)泛型方法可以使用在靜態方法中


public class Restric<T> {
    /**
     * 不能實例化泛型變量
     *
     * @return
     */
    T getData() {
        return new T();
    }

    /**
     * 泛型類中的泛型,不能使用在靜態方法上
     *
     * @param t
     * @return
     */
    static T function(T t) {
        return t;

    }

    /**
     * 泛型方法可以使用在靜態方法中
     * @param e
     * @param <E>
     * @return
     */
    static <E> E funtionc2(E e) {
        return e;
    }

}

(4)泛型不能使用在基本類型中
(5)泛型不能使用instance of

      if(genericAbstarctClass instanceof GenericAbstarctClass<String> ){
      }

(6) 可以聲明泛型數組,但是不能實例化

        //沒問題
 GenericAbstarctClass<String>[]arrays;
        //有問題
 GenericAbstarctClass<String>[]arrays2 = new  GenericAbstarctClass<String>[10];

(7)泛型類不能派生Excetion/Throw

 class GenericInterfaceImpl<T> extends Exception  有問題

(8)不能捕獲泛型類型的異常,可以拋出泛型異常

  /**
     * 不能捕獲泛型類型的異常
     *
     * @param <T>
     * @return
     */
    <T extends Exception> T function() {
        try {

        } catch (T e) {

        }
    }

    /**
     * 可以拋出泛型異常
     *
     * @param e
     * @param <T>
     * @return
     * @throws T
     */
    <T extends Exception> T function2(T e) throws T {
        throw e;
    }

九、虛擬機如何實現泛型

泛型擦除。字節碼中實際上是擦除了泛型,而在實際執行期間是根據泛型進行了強轉、在虛擬機有有一個變量實現了弱記憶功能,記住泛型的類型。

通過匿名內部類來獲取泛型類型

package com.example.myapplication;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 自定義一個泛型類
 * @param <T>
 */
public  class TypeClass<T> {

    public Type getType() {
        //獲取泛型類型
        Type type = getClass().getGenericSuperclass();
        ParameterizedType parameterizedType = (ParameterizedType) type;
        //因爲泛型可能有多個,所以是一個數組
        Type[] types = parameterizedType.getActualTypeArguments();
        //測試獲取第一個泛型類型
        return types[0];
    }
}

      //通過反射獲取泛型類型
        //通過匿名內部類來實現,獲取泛型的類型
        TypeClass<String> typeClass = new TypeClass<String>() {
        };
        Log.e("ResultActivity", "getType =  "+typeClass.getType());
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章