Chamly Idunil
Chamly Idunil

Reputation: 1872

Use generic Wildcard in interface level java

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

Answers (1)

Kevin J. Chase
Kevin J. Chase

Reputation: 3956

Overriding

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.

Chain of Responsibility

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

Related Questions