This is a bit of a contrived reproducing case, but bear with me.
Suppose you want to create an adder interface for classes capable of adding items to different types of lists with the following behavior:
// Can add items to any type of array list.
Adder<ArrayList> arrayListAdder = ...;
// Ok. Right list type and item types match.
arrayListAdder.add(new ArrayList<String>(), "test");
// Ok. Right list type and item types match.
arrayListAdder.add(new ArrayList<Integer>(), 3);
// Compile error. Item types do not match.
arrayListAdder.add(new ArrayList<Integer>(), "test");
// Compile error. Wrong list type although item types match.
arrayListAdder.add(new LinkedList<String>(), "test");
In other words, I want the interface to say:
An adder for an specific list type has a method 'add'. This method takes two arguments. The first is a list of this specific type with items of type T. The second argument is an item of type T. The method adds the item to the list.
I tried with different solutions along the lines of:
interface Adder<L extends List<?>> {
<T> void add(L<T> list, T t);
}
But the expression L<T> is illegal in its context. The error message I get is "Type 'L' does not have type parameters".
I cannot find a way of leaving the type parameter of the list open until the definition of the add method. Is there any way of specifying this interface, or does that require higher-order generics or something else which Java doesn't have?
Unfortunately, Java Generics do not support the functionality you are looking for. The closest you can get is to require a List in the method, and not use type L. Such as:
interface Adder
{
<T> void add(List<T> list, T t);
}
This isn't what you are looking for though, so the next closest thing would be to move your List declaration into the method body, however this is also incorrect:
interface Adder
{
<T, L extends List<T>> void add(List<T> list, T t);
}
The problem is you are attempting to assign a generic type to an arbitrary type (L), while L may not be genericized, despite forcing L extends List<?>. There is no good way to force the check at compile time or at run time of the list type.
interface Adder<T, L extends List<T>> {
void add(L list, T t);
}
class ArrayListAdder implements Adder<String, ArrayList<String>> {
@Override
public void add(ArrayList<String> list, String t) {
list.add(t);
}
}
I don't think binding T is possible at add definition time, since T must be known in order to declare L having a type parameter (it must be given in either bound or unbound form).
I believe you are looking for the equivalent of this C++0x code:
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
template <template <typename _ElementT, typename _AllocatorT> class CollectionT>
struct Adder {
template <typename ElementT, typename AllocatorT>
void add(CollectionT<ElementT, AllocatorT> &collection, ElementT element);
};
struct VectorAdder : public Adder<std::vector> {
template <typename ElementT, typename _Alloc>
void add(std::vector<ElementT, _Alloc> &vector, ElementT element) {
vector.push_back(element);
}
};
int main() {
std::vector<int> vi;
vi.push_back(1);
std::vector<double> vd;
vd.push_back(1.1);
VectorAdder va;
va.add(vi, 2); // instantiates VectorAdder::add<int, ...>
va.add(vd, 2.2); // instantiates VectorAdder::add<double, ...>
for_each(vi.begin(), vi.end(), [](int x) { std::cout << x << ' '; });
for_each(vd.begin(), vd.end(), [](double x) { std::cout << x << ' '; });
return 0;
}
And I'm pretty sure that's not possible in Java.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With