Java泛型:多个泛型参数?


69

我想知道是否可以编写一个可以接受多种通用类型的函数,如下所示:

public int void myfunction(Set<T> a, Set<T> b) {
    return 5;
}

Set<Integer> setA = new HashSet<Integer>();
Set<String> setB = new HashSet<String>();
int result = myfunction(setA, setB);

那行得通吗?每个参数中的泛型是否意味着每个参数必须具有与泛型相同的类型T?

Answers:


122

是的-可能的(虽然不是使用方法签名),是的,使用签名的类型必须相同。

使用给定的签名,T必须在呼叫站点将其与单个类型(例如String Integer)关联。但是,您可以声明采用多个类型参数的方法签名

public <S, T> void func(Set<S> s, Set<T> t)

请注意,在上面的签名中,我已经声明了类型S以及T签名本身。因此,它们不同于并独立于与包含该函数的类或接口相关联的任何泛型类型。

public class MyClass<S, T> {
   public        void foo(Set<S> s, Set<T> t); //same type params as on class
   public <U, V> void bar(Set<U> s, Set<V> t); //type params independent of class
}

您可能想看看java.util包中集合类的一些方法签名。泛型确实是一个相当复杂的主题,尤其是在考虑通配符(? extends? super)时。例如,通常情况下,可能将Set<Number>用作参数的方法也应接受Set<Integer>。在这种情况下,您会看到这样的签名:

public void baz(Set<? extends T> s);

关于SO的问题已经很多,您可以就此问题进行研究!

不确定int从函数返回an的意义是什么,尽管您可以根据需要这样做!


我不明白为什么两个问题都为“是”(具体来说,为什么“工作”会为“是”)。上面的函数(我知道是用int-return构造的)不会接受两种不同的类型,因为它期望两个参数都具有相同的泛型T,对吗?
atp

1
抱歉-我的意思是“是可能的”和“是的,在您定义的签名中,类型必须相同”
oxbow_lakes

9

您可以在一个类型或方法上声明多个类型变量。例如,在方法上使用类型参数:

<P, Q> int f(Set<P>, Set<Q>) {
  return 0;
}

9

您甚至可以继承泛型:)

@SuppressWarnings("unchecked")
public <T extends Something<E>, E extends Enum<E> & SomethingAware> T getSomething(Class<T> clazz) {
        return (T) somethingHolderMap.get(clazz);
    }

6

您可以采用以下方法之一:

1)基本的单一类型:

//One type
public static <T> void fill(List <T> list, T val) {

    for(int i=0; i<list.size(); i++){
        list.set(i, val);
    }

}

2)多种类型:

// multiple types as parameters
public static <T1, T2> String multipleTypeArgument(T1 val1, T2 val2) {

    return val1+" "+val2;

}

3)下面将引发编译器错误,因为'T3不在函数声明部分使用的泛型类型列表中。

//Raised compilation error
public static <T1, T2> T3 returnTypeGeneric(T1 val1, T2 val2) {
    return 0;
}

正确:编译正常

public static <T1, T2, T3> T3 returnTypeGeneric(T1 val1, T2 val2) {
    return 0;
}

样例代码:

package generics.basics;

import java.util.ArrayList;
import java.util.List;

public class GenericMethods {

/*
 Declare the generic type parameter T in this method. 

 After the qualifiers public and static, you put <T> and 
 then followed it by return type, method name, and its parameters.

 Observe : type of val is 'T' and not '<T>'

 * */
//One type
public static <T> void fill(List <T> list, T val) {

    for(int i=0; i<list.size(); i++){
        list.set(i, val);
    }

}

// multiple types as parameters
public static <T1, T2> String multipleTypeArgument(T1 val1, T2 val2) {

    return val1+" "+val2;

}

/*// Q: To audience -> will this compile ? 
 * 
 * public static <T1, T2> T3 returnTypeGeneric(T1 val1, T2 val2) {

    return 0;

}*/

 public static <T1, T2, T3> T3 returnTypeGeneric(T1 val1, T2 val2) {

    return null;

}

public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    list.add(10);
    list.add(20);
    System.out.println(list.toString());
    fill(list, 100);
    System.out.println(list.toString());

    List<String> Strlist = new ArrayList<>();
    Strlist.add("Chirag");
    Strlist.add("Nayak");
    System.out.println(Strlist.toString());
    fill(Strlist, "GOOD BOY");
    System.out.println(Strlist.toString());


    System.out.println(multipleTypeArgument("Chirag", 100));
    System.out.println(multipleTypeArgument(100,"Nayak"));

}

}

//类定义结束

样本输出:

[10, 20]
[100, 100]
[Chirag, Nayak]
[GOOD BOY, GOOD BOY]
Chirag 100
100 Nayak

2

a和b必须都是相同类型的集合。但是没有什么可以阻止你写作

myfunction(Set<X> a, Set<Y> b)

1
除了需要像我的回答一样在签名中声明类型参数
oxbow_lakes

您不应该接受错误的答案。@oxbow_lakes是第一个正确的方法。
Paul Tomblin,2009年

2

在函数定义中,您要将a和b设置为同一类型。你也可以写

public <X,Y> void myFunction(Set<X> s1, Set<Y> s2){...}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.