1. 程式人生 > 其它 >Java學習筆記123——集合—泛型

Java學習筆記123——集合—泛型

泛型

泛型的定義及優點

import java.util.ArrayList;
import java.util.Iterator;

/*
        ClassCastException:型別轉換異常
        我們按照正常的寫法,在集合中新增一些不是同類型的資料,在遍歷的時候向下轉型
        報錯了。

        為什麼呢?
            因為我們在儲存資料的時候,儲存了一些String和Integer型別的資料
            但是呢,我們遍歷的時候,預設集合中只存放String型別的資料,但是呢,又沒有在
            儲存資料的時候告訴我只能存String型別的資料,突然覺得這樣的設計很不好
            如果能在儲存的時候告訴我能儲存哪些資料型別就好了。
            就像陣列這樣:
                String[] arr = new String[3];
                arr[0] = "hello";
              //arr[1] = 20;--不能儲存
            java中集合就模仿著陣列,也有了這樣的做法,在建立集合的時候,就明確了
            元素的資料型別,建立後,再往集合中加入的元素的時候,只能是定義好的資料型別相關的
            資料了,然後再向下轉型就沒有問題了。
            這樣的技術,java中叫做:泛型

            泛型:
                把明確資料型別的工作,提前到了編譯時期,在建立集合的時候明確資料型別。
                這樣的做法有點像把資料型別當作引數一樣進行傳遞。所以泛型還有一個名字
                叫做:引數化型別。

           定義格式:  
                <引用資料型別>
                注意:尖括號中的資料型別只能是引用資料型別

           泛型的好處:
                1、將我們之前執行時候出現的問題,提前到了編譯時期
                2、不需要強制型別轉換了
                3、優化了程式碼,消除不必要的黃色警告線

           通過觀察API發現,泛型可以出現了類,介面,方法上,看到一些類似與<E>,一般來說泛型
           出現在大多使用集合中。
*/

public class GenericDemo1 {
    public static void main(String[] args) {
        //建立List集合物件        
        //報錯之後,在建立集合的時候加入泛型,明確集合的資料型別
        //賦值號右邊的尖括號裡可以不寫,因為JDK1.7之後會自動進行型別推斷
        ArrayList<String> list = new ArrayList<String>();

        list.add("hello");
        //新增泛型之後就不能存放Integer型別了
        //list.add(10);  //向上轉型 10 --> int --> Integer
        list.add("world");
        list.add("java");
        list.add("bigdata");

        //獲取迭代器物件--也要加泛型
        Iterator<String> iterator = list.iterator();

        while (iterator.hasNext()) {
          //加入泛型之後就不需要進行強轉了,因為型別已經明確下來了
            String next = iterator.next();
            System.out.println(next + "--" + next.length());
          //加入泛型之前:
//            Object next = iterator.next();
          //ClassCastException:型別轉換異常
//            String s = (String)next;
//            System.out.println(s);
        }
    }
}

泛型應用

  • 泛型類

/*
        泛型類:  把泛型定義在類上
        格式:public class 類名<泛型型別1,…>
        注意:泛型型別必須是引用型別

        這裡的<>裡面的內容僅僅表示的是一種引數資料型別,引數型別是一種變數,
        既然是一種變數,就符合變數的命名規則,可以是任意符合識別符號起名規則的名字。
*/
public class GenericTool1<T> {
    private T obj;

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}

import com.shujia.wyh.day22.Student;

/*
        泛型類的測試
*/

public class GenericTest1 {
    public static void main(String[] args) {
        //不加泛型不會報錯,預設是Object型別
//        GenericTool1 gt1 = new GenericTool1();
        //預設是Object型別的時候,我傳入什麼型別的值都可以
//        gt1.setObj("hello");
//        gt1.setObj(20);
//        gt1.setObj(12.34);
//        gt1.setObj(new Student());

      //加了泛型之後:
        GenericTool1<String> gt2 = new GenericTool1<>();
        gt2.setObj("hello");
      //加了泛型並明確了型別為String型別的時候
      //傳入String型別之外的型別就會報錯
//      gt2.setObj(20);

      //明確了String型別之後,返回值就是String型別
        String obj = gt2.getObj();
    }
}
  • 泛型方法

/*
        泛型方法
            把泛型定義在方法上
            格式:public <泛型型別> 返回型別 方法名(泛型型別 .)
*/
public class GenericTool2 <T>{//-第一種方式:在類中指定泛型
      //沒有加入泛型的時候
//    public void show(String s){
//        System.out.println(s);
//    }
//
//    public void show(int i){
//        System.out.println(i);
//    }
//
//    public void show(double d){
//        System.out.println(d);
//    }

  //第一種方式:在類中指定泛型,在引數列表裡面使用泛型
  //  public void show(T t){
  //      System.out.println(t);
  //  }
  
  //第二種方式:不在類中指定泛型
  //而是在方法中指定泛型
    public <T> void show(T t){
      System.out.println(t);
    }
}

import com.shujia.wyh.day22.Student;

/*
        泛型方法的使用
*/

public class GenericTest2 {
    public static void main(String[] args) {
      //沒有加入泛型的時候每次想要傳入一個新的資料型別
      //都要過載一遍show()方法
//        GenericTool2 gt1 = new GenericTool2();
//        gt1.show(10);
//        gt1.show("hello");
//        gt1.show(12.34);
      
//----------用泛型方法第一種方式改進之後--------
//        gt1.show(new Student());
      
      //建立泛型類物件--此時show()方法中只能傳入在初始化泛型類時被宣告的資料型別
//        GenericTool2<String> gt2 = new GenericTool2<>();
//        gt2.show("hello");
      //不能傳入int型別
//        //gt2.show(20);
      
      //那想要傳入Integer型別怎麼辦呢?只能再建立一個泛型類的物件
//        GenericTool2<Integer> gt3 = new GenericTool2<>();
//        gt3.show(20);
//
        //到目前為止,如果你能看懂,說明泛型類你是可以掌握的
        //但是有個問題,誰規定了方法的引數型別一定要和類的型別一致呢?
        //如果類上面沒有泛型的話,方法還能不能隨便傳參呢?--可以

      
//--------用泛型方法第二種方式改進之後--------
      
       //建立物件
        GenericTool2 gt = new GenericTool2();
       //可以放入任何一種資料型別
        gt.show("hello");
        gt.show(20);
        gt.show(true);
    }
}
  • 泛型介面

/*
 泛型介面
*/

public interface GenericTool3<T> {
    public abstract void show(T t);
}

//將來開發中實現介面的類名字後面加上Impl,易於區分
//實現泛型介面的類的類名後面也要加上<T>
public class GenericTool3Impl<T> implements GenericTool3<T>{
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}

/*
        泛型介面的測試
*/

public class GenericTest3 {
    public static void main(String[] args) {
      //建立實現介面的類的物件
        GenericTool3Impl<String> sgt1 = new GenericTool3Impl<>();
        sgt1.show("hello");
    }
}

泛型高階(萬用字元)

public class Animal {
}

public class Dog extends Animal {
}

public class Cat extends Animal {
}

import java.util.ArrayList;

/*
    泛型萬用字元<?>
        任意型別,如果沒有明確,那麼就是Object以及任意的Java類了
    ? extends E
        向下限定,E及其子類
    ? super E
        向上限定,E及其父類
*/

public class GenericDemo2 {
    public static void main(String[] args) {
        //如果泛型裡面的型別只用一個,並且明確資料型別的時候,前後必須要寫一致
        ArrayList<Animal> list1 = new ArrayList<Animal>();
        ArrayList<Dog> list2 = new ArrayList<Dog>();
        ArrayList<Object> list3 = new ArrayList<Object>();

        //泛型萬用字元<?>
        //任意型別,如果沒有明確,那麼就是Object以及任意的Java類了
        ArrayList<?> objects1 = new ArrayList<Animal>();
        ArrayList<?> objects2 = new ArrayList<Dog>();
        ArrayList<?> objects3 = new ArrayList<Object>();

        // ? extends E  向下限定,E及其子類
        ArrayList<? extends Animal> list4 = new ArrayList<Animal>();
        ArrayList<? extends Animal> list5 = new ArrayList<Dog>();
        ArrayList<? extends Animal> list6 = new ArrayList<Cat>();
        //向下限定,只能傳入E及其子類,不能是E的父類
        //ArrayList<? extends Animal> list7 = new ArrayList<Object>();

        // ? super E  向上限定,E及其父類
        ArrayList<? super Animal> list7 = new ArrayList<Animal>();
        ArrayList<? super Animal> list8 = new ArrayList<Object>();
        //向上限定,只能傳入E及其父類,不能是E的子類
        //ArrayList<? super Animal> list9 = new ArrayList<Dog>();
    }
}