Обобщения Java: несколько общих параметров? - PullRequest
58 голосов
/ 19 ноября 2009

Мне было интересно, можно ли написать функцию, которая принимает несколько универсальных типов, следующим образом:

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, что и универсальный?

Спасибо!

Ответы [ 6 ]

104 голосов
/ 19 ноября 2009

Да - это возможно (хотя и не с вашей подписью метода), и да, с вашей подписью типы должны быть одинаковыми.

С подписью, которую вы дали, 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 из функции, хотя вы можете сделать это, если хотите!

9 голосов
/ 08 августа 2013

Более того, вы можете наследовать дженерики:)

@SuppressWarnings("unchecked")
public <T extends Something<E>, E extends Enum<E> & SomethingAware> T getSomething(Class<T> clazz) {
        return (T) somethingHolderMap.get(clazz);
    }
9 голосов
/ 19 ноября 2009

Вы можете объявить переменные нескольких типов для типа или метода. Например, используя параметры типа для метода:

<P, Q> int f(Set<P>, Set<Q>) {
  return 0;
}
4 голосов
/ 04 июля 2017

Вы можете следовать одному из следующих подходов:

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 голосов
/ 19 ноября 2009

В определении вашей функции вы ограничиваете наборы a и b одним и тем же типом. Вы также можете написать

public <X,Y> void myFunction(Set<X> s1, Set<Y> s2){...}
2 голосов
/ 19 ноября 2009

a и b оба должны быть наборами одного типа. Но ничто не мешает вам писать

myfunction(Set<X> a, Set<Y> b)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...