I have started to work with Java recently and still got confused when dealing with generic types. The following is a simplified scenario where I am having some problems.
I have a class wich holds a Map using a Class type as Key and an Collection of objects of that class:
public class GenericListInside {
private Map<Class<?>, List<?>> mapping = new HashMap<>();
public <T> void addListing(Class<T> clazz, List<T> object) {
mapping.put(clazz, object);
}
}
I can call addListing without problems:
GenericListInside gli = new GenericListInside();
List<Foo> list = new ArrayList<>();
//add something to list
gli.addListing(Foo.class, list);
Now i decided to create a Class to provide a fluid interface. Something like:
with(Foo.class).use(list);
Then i came with:
public class FluidInserter<T> {
Class<T> clazz;
GenericListInside gli = new GenericListInside();
public FluidInserter with (Class<T> clazz) {
this.clazz = clazz;
return this;
}
public <T> void use(List<T> list) {
gli.addListing(clazz, list);
}
}
But when I try to compile I get:
Error:(18, 12) java: method addListing in class util.GenericListInside cannot be applied to given types;
required: java.lang.Class,java.util.List
found: java.lang.Class,java.util.List
reason: inferred type does not conform to equality constraint(s)
inferred: T
equality constraints(s): T,T
This message is a little bit confusing... can anyone figure out what am I doing wrong?
A parameterized type is an instantiation of a generic type with actual type arguments. A generic type is a reference type that has one or more type parameters. These type parameters are later replaced by type arguments when the generic type is instantiated (or declared ).
Type inference is a Java compiler's ability to look at each method invocation and corresponding declaration to determine the type argument (or arguments) that make the invocation applicable.
Java Generics was introduced to deal with type-safe objects. It makes the code stable. Java Generics methods and classes, enables programmer with a single method declaration, a set of related methods, a set of related types.
The generic method of your fluid builder takes a generic method parameter, but that parameter is not the same as the type of your clazz
field, despite the name overlap.
Just remove <T>
from your method declaration, while leaving List<T>
as parameter:
public void use(List<T> list) {
gli.addListing(clazz, list);
}
Off-topic note: you don't want to return a raw typed FluidInserter
in your with
method. Change the return type to:
public FluidInserter<T> with (Class<T> clazz)
The problem is with the definition of your use(List<T> list)
method:
public <T> void use(List<T> list) {
gli.addListing(clazz, list);
}
Here, you're hiding the class-scoped type-parameter T
, by introducing a method-scoped type-parameter with the same name.
It should rather be:
public void use(List<T> list) {
gli.addListing(clazz, list);
}
and it should compile just fine, as T
is already defined on class level.
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