Java generics: multiple generic parameters?

JavaGenericsParameters

Java Problem Overview


I was wondering if it's possible to write a function that accepts multiple generic types as follows:

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);

Will that work? Does the generic in each parameter mean that each parameter must have the same type T that's generic?

Java Solutions


Solution 1 - Java

Yes - it's possible (though not with your method signature) and yes, with your signature the types must be the same.

With the signature you have given, T must be associated to a single type (e.g. String or Integer) at the call-site. You can, however, declare method signatures which take multiple type parameters

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

Note in the above signature that I have declared the types S and T in the signature itself. These are therefore different to and independent of any generic types associated with the class or interface which contains the function.

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
}

You might like to take a look at some of the method signatures of the collection classes in the java.util package. Generics is really rather a complicated subject, especially when wildcards (? extends and ? super) are considered. For example, it's often the case that a method which might take a Set<Number> as a parameter should also accept a Set<Integer>. In which case you'd see a signature like this:

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

There are plenty of questions already on SO for you to look at on the subject!

Not sure what the point of returning an int from the function is, although you could do that if you want!

Solution 2 - Java

You can declare multiple type variables on a type or method. For example, using type parameters on the method:

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

Solution 3 - Java

Even more, you can inherit generics :)

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

Solution 4 - Java

You can follow one of the below approaches:

  1. Basic, single type :

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

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

    }

  2. Multiple Types :

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

     return val1+" "+val2;
     
    

    }

  3. Below will raise compiler error as 'T3 is not in the listing of generic types that are used in function declaration part.

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

Correct : Compiles fine

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

Sample Class Code :

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"));
	
}

}

// class definition ends

Sample Output:

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

Solution 5 - Java

a and b must both be sets of the same type. But nothing prevents you from writing

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

Solution 6 - Java

In your function definition you're constraining sets a and b to the same type. You can also write

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionatpView Question on Stackoverflow
Solution 1 - Javaoxbow_lakesView Answer on Stackoverflow
Solution 2 - JavaericksonView Answer on Stackoverflow
Solution 3 - JavakingolegView Answer on Stackoverflow
Solution 4 - Javachirag nayakView Answer on Stackoverflow
Solution 5 - JavaDmitryView Answer on Stackoverflow
Solution 6 - JavaSteve B.View Answer on Stackoverflow