Reputation: 1872
This is related to java generic wild card. I need to understand how this happens and need solution.
Ex : I have a interface names Processer.
public interface Processer<X> {
<P> void process(P parent, X result);
}
I want to make P as wildcard. but it is not allowed to use wildcard ( ? ) when defining.
When I implement this interface and let IDE to generate implemented methods it generate as follow.
public class FirstProcesser implements Processer<String> {
@Override
public <P> void process(P parent, String result) {
}
}
I want to modify this implementation as this.
public class FirstProcesser implements Processer<String> {
@Override
public void process(User parent, String result) {
}
}
But it gives compile errors that FirstProcesser should be abstract or implement all the abstract methods.
I need to know why this is happening and a solution.
Upvotes: 1
Views: 2263
Reputation: 3956
You can't override a method (generic or not) with one that takes a narrower parameter type. If you could, it would be impossible for the compiler to tell whether any given method call would be (future tense) legal.
An example without any generics at all, which will fail with exactly the same error:
public class X {
public void f(Object o) {
}
}
class Y extends X {
@Override
public void f(String s) {
}
}
Compiling this fails with:
X.java:8: error: method does not override or implement a method from a supertype
@Override
^
1 error
If it were legal, then it would be impossible to reliably compile even very simple methods like:
public static void f(X x) {
x.f(5);
}
If x
were an actual X
object, that code would work fine, but if x
were a Y
subtype, it would fail, because 5
is not a String
.
This is why the above definition of Y.f
is not allowed to override X.f
.
By changing FirstProcesser
to accept only User
objects, you are causing the same problem.
The chain of responsibility pattern on Wikipedia doesn't look much like what you're trying to build. I can think of two things you might be trying to do...
1.
If the parent
parameter is supposed to be the previous handler in the chain, then it should be of type Processer<X>
:
public interface Processer<X> {
void process(Processer<X> parent, X result);
}
class StringProcesser implements Processer<String> {
@Override
public void process(Processer<String> parent, String result) {
}
}
2.
If the type of parent
is part of the decision-making process, each handler should store a collection of the Class
objects it can handle.
The process
method should then see if parent.getClass()
is in that collection.
A partial definition might look something like:
public interface Processer<X> {
void process(Class<?> parent, X result);
}
class StringProcesser implements Processer<String> {
private Set<Class<?>> classes = new HashSet<Class<?>>();
public StringProcesser(final Iterable<Class<?>> classes) {
for (final Class<?> c : classes) {
this.classes.add(c);
}
}
@Override
public void process(Class<?> parent, String result) {
if (this.classes.contains(parent)) {
System.err.println("Handling...");
System.out.println(result);
return;
}
System.err.println(
"Can't handle. Try next Processer."
);
// ...
}
}
Note that where the generic type parameter <X>
and where the wildcard <?>
show up depends on what you're trying to do.
PS: "Processer" should be spelled "Processor".
Upvotes: 1