Featured image of post Java中回傳值前的泛型標識符是什麼意思呢

Java中回傳值前的泛型標識符是什麼意思呢

常在一些專案中看到的<T>究竟是什麼意思呢?來解答一下吧

前一陣子在寫DiscordBot的時候,曾經在教學中看過這種寫法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class GymBotConfiguration {
@Bean
    public <T extends Event>GatewayDiscordClient gatewayDiscordClient(final List<EventListener<T>> eventListeners){
     final  GatewayDiscordClient client = DiscordClientBuilder.create(token)
                .build()
                .login()
                .block();

        for (EventListener<T> listener : eventListeners) {
            client.on(listener.getEventType())
                    .flatMap(listener::execute)
                    .onErrorResume(listener::handleError)
                    .subscribe();
        }
        return client;
    }
}

對於其中的寫法感到非常困惑,不知道為什麼回傳值前還會有泛型符號,直到最近在研究一些OpenSource的框架時,才又更了解這件事情。

如何宣告泛型

在講這件事情之前,要先有個基礎知識,就是關於Java是如何宣告一個泛型Class的,其實就是在Class後面加上<T>就可以了

1
2
3
public class Link<E> {

}

如此一來,就可以在其他地方創建一個泛型的Link類

1
Link link=new Link<Integer>;

現在我們在這個Link類裡新增一個方法

1
2
3
4
5
6
7
public class Link<E> {
  public List<E> addToList(E t){
        List<E> list = new ArrayList<>();
        list.add(t);
        return list;
    }
}

這個方法會把傳進來的值,包裝成一個ArrayList並回傳出去,而它參數的型別則是與Link的泛型一致,比如說

1
2
3
4
public static main(String[] arg){
    Link link=new Link<String>;
    List<String> list=link.add("早安");
}

image-20230401002712243

也就是說addToList這個方法的型別和Link的泛型型別是綁定在一起的。

何謂回傳型別前的泛型

承上,因為方法的參數型別與類的泛型型別基本上綁定在一起,如果我宣告了一個Link<Integer>,我的addToList就只能吃Integer的參數,那為了要解決這種問題,就有了在回傳型別前的泛型的寫法,釋例如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class Link<E> {
    public List<E> addToList(E t){
        List<E> list = new ArrayList<>();
        list.add(t);
        return list;
    }

    public<E>List<E> addToList2(E t){
        List<E> list = new ArrayList<>();
        list.add(t);
        return list;
    }

}

可以看到addToList2這個方法的回傳值List<E>前,我加了一個<E>,先別管這個到底能做什麼,我們現在先使用這個方法看看

image-20230401003453849

這時候你發現了,addToList2能吃的參數變成Object類了,當我們輸入一個String

image-20230401003608198

輸入一個Double

image-20230401003718395

也可以輸入一個自定義的類

image-20230401013130560

可以感受到addToList跟addToList2的差異了嗎?沒錯,addToList2的泛型不受Link的影響,可以自己有自己的泛型

應用

這樣的用法不只可以拿來用在泛型類裡的方法,也可以用在一個非泛型類,比如說

1
2
3
4
5
6
7
public class Student {
    public List<Student> addPeopleList(Student student){
        ArrayList<Student> list = new ArrayList<>();
        list.add(student);
        return list;
    }
}

今天我們希望這個addPeopleList的方法可以吃任何型別的參數,我們如果這樣寫是會報錯的

image-20230401004844813

原因就在於我們並沒有一個地方告訴編譯器,什麼是T,因為我們的Student類並不是一個泛型類,但實務上,我們又不太可能去修改原有的類,避免破壞掉一些東西,所以我們修改addPeopleList,讓它變成這樣

image-20230401005044108

如此一來,addPeopleList就可以吃任何型別的參數了,以上就是所謂的泛型方法約束。

Licensed under CC BY-NC-SA 4.0