简体   繁体   中英

Java Generics: using parameterized interface in method calls

I want to store a function to be applied to any instance of a class. As I want to do this for different classes, I am using an interface in my storing and applying code. But I have some problems with my type variables:

I've got an interface

public interface SomeInterface<P>

And an implementing class

public class SomeClass implements SomeInterface<Object>

As well as a handler

public class SomeHandler {
   public <R> void someMethod(Function<SomeInterface<R>,R> someFunction) {}
}

And the code

public void someTest() {
    Function<SomeClass,Object> someFunction = a -> new Object();
    SomeHandler handler = new SomeHandler();
    handler.someMethod(someFunction); //error here
}

will not work.

The error at the marked location is "No Instance(s) of type variable(s) R exist so that SomeClass conforms to SomeInterface"

I already tried to use an abstract class instead of the interface. This did not work either.

I did some research and found a bug including lambda-expressions. Removing the lambda expression did not solve the issue. Another page hints to a bug in OpenJdk recommending to change the order of the type variables. As I am using the java Function class, I am not able to do this.

I also tried to get the Oracle Jdk, but I am not allowed to do anything on this machine.

Any thought is welcomed!

Change the Function in someTest() to:

Function<SomeInterface<Object>, Object> someFunction = a -> new Object();

UPDATE depending on your comment:

You could generalise your handler method to something more of that kind:

public <R> void someMethod(Function<? extends SomeInterface<R>, R> someFunction) {}

This allows you to use something like the following as Function:

Function<SomeOtherClass, MyObject> someFunction = a -> new MyObject();
Function<SomeClass,Object> someFunction = a -> new Object();

isn't an instance of Function<SomeInterface<R>,R> .

You can either do what Georg Henkel suggests : to change the type of the someFunction variable; or you could just inline the lambda in the method call, and hide the type declaration:

handler.someMethod(a -> new Object());

Or, to keep your existing type at the call site, change the method signature to:

public <R, S extends SomeInterface<R>>
    void someMethod(Function<S, R> someFunction)

but note that in order to be able to call someFunction.apply with anything other than literal null , you will have to pass in a S (or something containing a S , like a Collection or an Optional ) as an additional method parameter.

If you don't need to call someFunction.apply (the question is then why you'd need it...), you can drop the S type variable, and just use:

public <R> void someMethod(Function<? extends SomeInterface<R>, R> someFunction)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM