Reputation: 7634
My problem can be summed-up by this snippet:
public interface TheClass<T> {
public void theMethod(T obj);
}
public class A {
private TheClass<?> instance;
public A(TheClass<?> instance) {
this.instance = instance;
}
public void doWork(Object target) {
instance.theMethod(target); // Won't compile!
// However, I know that the target can be passed to the
// method safely because its type matches.
}
}
My class A
uses an instance of TheClass
with its generics type unknown. It features a method with a target passed as Object
since the TheClass
instance can be parameterized with any class. However, the compiler won't allow me to pass the target like this, which is normal.
What should I do to circumvent this issue?
A dirty solution is to declare the instance as TheClass<? super Object>
, which works fine but is semantically wrong...
Another solution I used before was to declare the instance as raw type, just TheClass
, but it's bad practice, so I want to correct my mistake.
Solution
public class A {
private TheClass<Object> instance; // type enforced here
public A(TheClass<?> instance) {
this.instance = (TheClass<Object>) instance; // cast works fine
}
public void doWork(Object target) {
instance.theMethod(target);
}
}
Upvotes: 5
Views: 148
Reputation: 80598
The reason for the compile error is that the ?
wildcard indicates the unknown type in Java. You may declare a variable with an unknown generic parameter, but you cannot instantiate one with it. Which means that the in your constructor the passed in generic class could have been created to hold types that are incompatible with what you are trying to later on use. Case in point:
public class A {
public static void main(String[] args) {
TheClass<String> stringHolder = null; // should constrain parameters to strings
A a = new A(stringHolder);
a.donot(Float.valueOf(13)) ; // this is an example of what could happen
}
private TheClass<?> instance;
public A(TheClass<?> instance) {
this.instance = instance;
}
public void do(Object target) {
instance.theMethod(target);
}
}
In this case the compiler is preventing you from writing code that would have been prone to bugs. As others have pointed out, you should add a generic parameter type to your A
class, in order to constrain the allowed types - that will remove the compile time error.
Some suggested reading: Oracle Generics Trail
Upvotes: 1
Reputation: 47637
The solution is to also type A
. Using a wildcard ?
makes you loose the type information of TheClass
and there is no way to recover it later. There are some ugly hacks you could do but your best shot is to also type A
:
public interface TheClass<T> {
public void theMethod(T obj);
}
public class A<T> {
private TheClass<T> instance;
public A(TheClass<T> instance) {
this.instance = instance;
}
public void doIt(T target) {
instance.theMethod(target);
}
}
It won't break any API either.
Upvotes: 1
Reputation: 28703
public class A {
private TheClass<Object> instance;
public A(TheClass<Object> instance) {
this.instance = instance;
}
public void do(Object target) {
instance.theMethod(target);
}
}
or
public class A<T> {
private TheClass<T> instance;
public A(TheClass<T> instance) {
this.instance = instance;
}
public void do(T target) {
instance.theMethod(target);
}
}
Upvotes: 4