博客 / 詳情

返回

java 中的泛型

先看個例子,有一個IntegerPrinter類,裏面有一個printf方法打印一個integer類型的值。

public class Main {
    public static void main(String[] args) {
        IntegerPrinter integerPrinter = new IntegerPrinter(123);
        integerPrinter.printf();
    }
}

public class IntegerPrinter {
    Integer a;
    IntegerPrinter(Integer integer) {
        this.a = integer;
    }
    void printf() {
        System.out.println("打印的值是:" + this.a);
    }
}

打印 integer類型的值是有了,現在想打印String類型的值,你會如何做呢,是創建一個打印String類型的類,還是和我一樣使用泛型。

泛型

簡單的説,泛型就是允許你編寫可以操作各種類型數據的代碼,而不需要提前指定具體的數據類型。

現在對IntegerPrinter類 進修改,

//main函數如下
Printer<Integer> integerPrinter = new Printer<Integer>(123);
        integerPrinter.printf(); //打印的值是:123

Printer<String> stringPrinter = new Printer<String>("hello,world");
        stringPrinter.printf(); //打印的值是:hello,world


public class Printer<T> {
    T data;
    Printer(T data) {
        this.data = data;
    }
    void printf() {
        System.out.println("打印的值是:" + this.data);
    }
}

再類中,多個參數的實現

Printer<String, Integer> integerPrinter = new Printer<String, Integer>("hello,world", 123);
        integerPrinter.printf();
//第一個參數打印的值是:hello,world
//第二個參數打印的值是:123

public class Printer<T, K> {
    T data;
    K data2;
    Printer(T data, K data2) {
        this.data = data;
        this.data2 = data2;
    }
    void printf() {
        System.out.println("第一個參數打印的值是:" + this.data);
        System.out.println("第二個參數打印的值是:" + this.data2);
    }
}

在方法中使用泛型

public static void main(String[] args) {
        print("張三"); //數據是:張三
        print(18); //數據是:18
        print(true);  //數據是:true
    }
    public static <T> void print(T data) {
        System.out.println("數據是:" + data);
    }

泛型上下邊界(約束)

泛型上邊界:指定泛型參數必須是某個類或接口的子類。
如:類型實參只准傳父類或父類型的子類

public class Printer<T extends Zoon> {
    T data;

    Printer(T data) {
        this.data = data;
    }
    void printf() {
        System.out.println("類是:" + this.data.getClass());
    }
}

public class Zoon {
    String color;
}

public class Dog extends Zoon {
    String name;
}

public class Cat extends Zoon {
    String name;
}

public static void main(String[] args) {
        Printer<Cat> catPrinter = new Printer<Cat>(new Cat());
        Printer<Dog> dogPrinter = new Printer<Dog>(new Dog());
        Printer<Zoon> zoonPrinter = new Printer<Zoon>(new Zoon());
        catPrinter.printf(); //類是:class Cat
        dogPrinter.printf(); //類是:class Dog
        zoonPrinter.printf(); //類是:class Zoon

//如果強行使用會出現報錯:Type parameter 'Flowers' is not within its bound; should extend 'Zoon'
Printer<Flowers> flowersPrinter = new Printer<Flowers>(new Zoon());
    }

例: 類型必須是父類中的子類,且必須實現了其中的接口

public interface Life {
}

//使Cat類 實現Life 接口
public class Cat  extends Zoon implements Life {
    String name;
}

//使Dog類,不實現 Life 接口
public class Dog  extends Zoon {
    String name;
}

// 注:類必須寫到接口前面,不然會報錯
public class Printer<T extends Zoon & Life> {
    T data;

    Printer(T data) {
        this.data = data;
    }
    void printf() {
        System.out.println("類是:" + this.data.getClass());
    }
}

public static void main(String[] args) {
        Printer<Cat> catPrinter = new Printer<Cat>(new Cat());
        catPrinter.printf(); //類是:class Cat
        //下面會報錯:Type parameter 'Dog' is not within its bound; should implement 'Life'
        Printer<Dog> dogPrinter = new Printer<Dog>(new Dog());
    }

在List 中使用

public static void main(String[] args) {
        List<Integer> lists = new ArrayList<>();
        lists.add(123);
        lists.add(456);
        print(lists); //[123, 456]
    }


    public static void print(List<Integer> lists) {
        System.out.println(lists);
    }

在上面中可以看到list類型是Integer,現在我想讓類型是String,該如何實現呢,使用Object?,或者再寫一個方法? 還是什麼,
為什麼不能使用Object:
因為String確實是Object 的子類,但是ListString 不是 List Object的子類。
重裝寫一個方法確實可以實現,但這樣太麻煩了。

此時就引出了通配符,符號: ? 來表示,代表可以配置任何類型。

public static void main(String[] args) {
        List<String> lists = new ArrayList<>();
        lists.add("hello");
        lists.add("world");
        print(lists); //[hello, world]

        List<Integer> lists2 = new ArrayList<>();
        lists2.add(123);
        lists2.add(456);
        print(lists2); //[123, 456]
    }


    public static void print(List<?> lists) {
        System.out.println(lists);
    }

泛型下邊界:指定泛型參數必須是某個類的父類。

例如:指定的類型是Cat類,
這個時候 我們就要使用到 super了,super 關鍵字允許泛型參數限制為某個類型的父類或者它本身,但不能是子類。

public static void main(String[] args) {
        List<Zoon> lists = new ArrayList<>();
        lists.add(new Zoon());
        print(lists);

        List<Cat> lists2 = new ArrayList<>();
        lists2.add(new Cat());
        print(lists2);
    }
    
    //參數的類型可以是Cat,也可以是Zoon, 不可以是Dog,因為Cat類沒有繼承Dog類,繼承代碼在上中有給出。
    public static void print(List<? super Cat> lists) {
        System.out.println(lists);
    }

總結

1,使用泛型最主要的是提高代碼的複用性。
2,當看到T, E, K, V這個符號的時候不用慌,他們都只是佔位符,當然,這只是一種約定俗成的習慣,你也可以使用26個字母中的任何一個表示泛型。

參考

https://www.baeldung.com/java-generics
https://www.bilibili.com/video/BV1H94y1a7bJ/?spm_id_from=333....

user avatar tigerandflower 頭像 buxia97 頭像 shellingfordly 頭像 lilin_5e390e08b42e4 頭像 user_kim 頭像 lllllxt 頭像 qianxiaqingkong 頭像 zhangfisher 頭像 yourena_c 頭像 shumin_5bd11c2a4b889 頭像 ke1992 頭像 yancy_5f300f5cc4004 頭像
18 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.