Java泛型:多个泛型参数?

89
我想知道是否有可能编写一个函数,可以接受多个泛型类型,代码如下:
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);

这会行吗?每个参数中的“generic”是否意味着每个参数必须具有相同的泛型类型T?

6个回答

151

是的,这是可能的(尽管不是使用您的方法签名),并且是的,使用您的签名,类型必须相同。

根据您提供的签名,T 必须与单个类型相关联(例如,String 或者 Integer)在调用时。 但是,您可以声明多个类型参数的方法签名。

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

请看上述签名,我已经在签名中声明了类型ST。因此,它们与包含函数的类或接口相关联的任何通用类型都不同且独立。
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的意义在哪里,尽管如果您想要可以这样做!


我不明白为什么两个问题的答案都是“是”(特别是,“这会起作用吗?”的答案为什么是“是”)。上面的函数(虽然是人为构造的,但有int返回值)不会接受两种不同类型,因为它期望两个参数都是相同的泛型T类型,对吧? - atp
1
抱歉 - 我的意思是“是的,这是可能的”和“是的,在您定义的签名中,类型需要相同”。 - oxbow_lakes

12
甚至更好的是,您可以继承泛型 :)
@SuppressWarnings("unchecked")
public <T extends Something<E>, E extends Enum<E> & SomethingAware> T getSomething(Class<T> clazz) {
        return (T) somethingHolderMap.get(clazz);
    }

11
你可以采用以下其中一种方法:
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

10

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

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

2
a和b必须都是相同类型的集合。但是没有任何阻止你编写以下内容:
myfunction(Set<X> a, Set<Y> b)

1
除了需要在签名中声明类型参数,就像我的答案一样。 - oxbow_lakes
你不应该接受错误的答案。@oxbow_lakes 是第一个回答正确的人。 - Paul Tomblin

2

在您的函数定义中,您将集合a和b限制为相同的类型。 您也可以编写

public <X,Y> void myFunction(Set<X> s1, Set<Y> s2){...}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接