Here is an overview of the Java code I have:
// An interface and an implementation class:
public interface MyInterface<T1, T2> { ... }
public class MyImplementation implements MyInterface<int, String> { ... }
// Another class
public class MyClass<T3, T4> { ... }
// Function I want to call
void doStuff(MyInterface i) {
MyClass<int, String> n;
}
// I want to call the function like this:
MyInterface mi = new MyImplementation();
doStuff(mi);
What I can't figure out is if I can get MyClass<int, String> n;
to somehow use the generic types from the MyImplementation
class passed in to doStuff()
? In this case, n
would automatically use <int, String>
because that's what MyImplementation
uses.
Yes, you can.
Let's move away from nebulous hypotheticals and take real classes: Collection<T>
, Map<K, V>
, and Function<F, T>
. Let's say you want to write a method in the Map type (or interface, doesn't matter, a signature is a signature) that takes a 'key converter' (a thing that converts Ks into something else), returning a collection of the something-else, which consists of each key in the map, thrown through the converter, and added to a collection.
class MapImpl<K, V> implements Map<K, V> {
public <T> Collection<T> convertKeys(Function<K, T> converter) {
List<T> out = new ArrayList<T>();
for (K key : keySet()) out.add(converter.apply(key));
return out;
}
}
A lot of concepts are being used here:
<T>
is all about in line 2.<>
after it and put in appropriate things. Or don't put in appropriate things which means: Hey, compiler, figure it out if you can (the so called diamond operator). In your snippet, you use MyInterface i
as method param type and that's bad: MyInterface has generics, so it must have <>
behind it. In this case, you have to add things because there is no way the compiler can try to figure things out.Going back to your code, it might look like:
public <K, V> void doStuff(MyInterface<K, V> i) {
MyClass<K, V> n;
}
NB: Remember, generics link things. That final snippet is simply saying: There is a link between the first typearg of the MyInterface part of the 'i' parameter's type, and the first typearg of the MyClass part of the 'n' local variable. I don't know what that type is. I do know it is the same type. Generics are completely useless unless the typevar occurs in 2 or more places.
NB2: If you then want to get real fancy, you start thinking about co/contra/invariance. For example, in the key converter story, if you have a converter that can convert any object into something else that'd be cool too. In fact, a converter that can convert either Ks, or any supertype of Ks, that'd all be suitable. So, really, you end up with: public <T> Collection<T> convertKeys(Function<? super K, ? extends T> converter) {}
- but that kind of advanced variance engineering is a nice bonus, feel free to skip those bits in your source until you run into trouble because you didn't take it into consideration.