1. 程式人生 > >Java泛型的應用

Java泛型的應用

---恢復內容開始---

在開發中,我們有時候會用到泛型來寫工具類,為了使方法更通用,以前,沒有完全弄懂,今天,就這個機會把泛形寫一寫

泛型是Java SE 1.5的新特性,泛型的本質是引數化型別,也就是說所操作的資料型別被指定為一個引數。這種引數型別可以用在類、介面和方法的建立中,分別稱為泛型類、泛型介面、泛型方法。泛型的引入,讓JAVA更安全。之前沒有引入泛型,各種的型別轉換錯誤。

泛型的好處是在編譯的時候檢查型別安全,並且所有的強制轉換都是自動和隱式的,以提高程式碼的重用率。

我們見不各種泛型的字母萬用字元TEKV等等還有?,其實這些字母只約定,實際中使用什麼字母都可以,以下是約定:

 

  •  表示不確定的java型別
  • T (type) 表示具體的一個java型別
  • K V (key value) 分別代表java鍵值中的Key Value
  • E (element) 代表Element

 


 import java.util.ArrayList;

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


    }

    public <T>  void aa(T t){
        ArrayList<?> al=new ArrayList<T>();
    }
}

 

這種方式 正確

 ArrayList<?> al=new ArrayList<T>();

但是這樣就不行了,後面只能是具體型別,不能是萬用字元,前邊是可以的

 ArrayList<?> al=new ArrayList<?>();

?和T都表示不確定的型別 ,但如果是T的話,函式裡面可以對T進行操作,比方 T car = getCar(),而不能用? car = getCar()

Class<T>在例項化的時候,T要替換成具體類

Class<?>它是個通配泛型,?可以代表任何型別,主要用於宣告時的限制情況

 

public class Test {
    public static <T> T createInstance(Class<T> clazz) throws IllegalAccessException, InstantiationException {
        return clazz.newInstance();
    }

    public static void main(String[] args)  throws IllegalAccessException, InstantiationException  {
            Fruit fruit= createInstance(Fruit .class);
            People people= createInstance(People.class);
    }
}

class Fruit{
    
}
class People{
    
}

 

上面的類使用Class<T>泛型後,newInstance不用強轉

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
 
//雖然Test<T1,T2>,但類名字仍為Test。T1,T2只是告訴我們new的時候要加入泛型,更方便通用
//T1,T2可以任意定義,比如改成K,V都可以
//他們不會關聯到其他類,只是在本類中通用
public class Test<T1, T2> {
    public static void main(String[] args) {
        System.out.println(new Test().getT1());
        System.out.println(new Test().getT2());
        new Test<String, String>().getClassName("");//T1,T2在new的時候用到,這裡都為String
        new Test().getClassAndList(Integer.class);
        //HashMap的括號裡面不能是T,E,T1,T2等不確定的東西,但可以是?
        HashMap<?, ?> map = new HashMap<Object, String>();
        List<?> list = new ArrayList<String>();
    }
 
    public T1 getT1() {
        //這裡的“T1”替換成1或1.0都會報錯
        return (T1) "T1";
 
    }
 
    T2 getT2() {
        //將自動轉型為String
        return (T2) "T2";
 
    }
 
    public <T> void getClassName(T x) {
        //<T>必須放在void或者返回型別的前面
        System.out.println(x.getClass().getName());
    }
 
    public <T> Class<?> getClassAndList(Class<?> a) {
        //Class<T>前面缺少<T>必須定義,否則將出現編譯錯誤
        //T改成其他字母都可以,但一定要宣告
        // 返回型別和引數中的型別:Class<T>和Class<?>都可以。因為返回的a的型別為Class<T>,Class<?>可以通配
        //當兩個都是Class<?>,引數中的?自動通配成T
        System.out.println(a.getClass().getName());//傳入的a是一個類,Class型別
        //引數裡面的Class<T>最大的好處是如果方法裡面定義了泛型,可以自動獲取型別值,比如如下的List<T>可以自動獲取到a的型別,不必強調死
        List<?> aa = new ArrayList<T>();
        //List<?> aa = new ArrayList<?>();會報錯,以為ArrayList必須是一種型別,List<>起到通配的作用
        //List<T> aa = new ArrayList<T>();當然正確
        System.out.println(aa);
        return a;
    }
}

這個例子說明泛型可以是任何字母

 

public class GenericTest {

     public static void main(String[] args) {

         Box<String> name = new Box<String>("corn");
         Box<Integer> age = new Box<Integer>(712);
         Box<Number> number = new Box<Number>(314);

         getData(name);
         getData(age);
         getData(number);

         //getUpperNumberData(name); // 1
         getUpperNumberData(age);    // 2
         getUpperNumberData(number); // 3
     }

     public static void getData(Box<?> data) {
         System.out.println("data :" + data.getData());
     }

     public static void getUpperNumberData(Box<? extends Number> data){
         System.out.println("data :" + data.getData());
     }

 }
class Box<T> {

 private T data;

 public Box() {

 }

 public Box(T data) {
  setData(data);
 }

 public T getData() {
  return data;
 }

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

}

 

Box<? extends Number> 問號也可以通過這種方式代表,傳入的都是Nubmber的子類