简体   繁体   English

将通配符与通用方法一起使用

[英]Using wildcard with Generic method

Would like to get some advise on it想得到一些建议

My class structure is like this我的班级结构是这样的

public abstract class Base {}
public class Derived1 extends Base {}
public class Derived2 extends Base {}

public class ServiceClass {
    public String method1(Derived1 derived1) {
        return "derived1";
    }
    public String method2(Derived2 derived2) {
        return "derived2";
    }
}

In my main code (MainProg),I am trying to use the same function to refer to the 2 methods in service class and seeing the compilation error as put in the comment在我的主代码(MainProg)中,我尝试使用相同的函数来引用服务类中的 2 个方法,并看到注释中的编译错误

public class MainProg {
    public static void main(String[] args) {
        ServiceClass serviceClass = new ServiceClass();

        //Incompatible types: Base is not convertible to Derived1
        Function<? extends Base,String> function1 = serviceClass::method1; 

        //Incompatible types: Object is not convertible to Derived1            
        Function<?,String> function2 = serviceClass::method1;
            
        //Incompatible types: Base is not convertible to Derived2
        Function<? super Base,String> function3 = serviceClass::method2;
    }
}

Is there a way to declare my function object so that same function object can be used to refer to methods taking different type of arguments?有没有办法声明我的函数对象,以便可以使用相同的函数对象来引用采用不同类型参数的方法?

Yes, by using an intermediary variable:是的,通过使用中间变量:

    Function<Derived1, String> function1 = serviceClass::method1;
    Function<Derived2, String> function2 = serviceClass::method2;        
    Function<? extends Base, String> function = condition ? function1 : function2;

That said, you won't be able to invoke function , because you don't know whether to pass a Derived1 or a Derived2 , or as the compiler puts it:也就是说,您将无法调用function ,因为您不知道是传递Derived1还是Derived2 ,或者像编译器所说的那样:

    function.apply(new Derived2()); 
    // error: The method apply(capture#1-of ? extends Base) in the type Function<capture#1-of ? extends Base,String> is not applicable for the arguments (Derived2)

You could, however, use generics to abstract over the argument type:但是,您可以使用泛型对参数类型进行抽象:

<T extends Base> invokeSafely(Function<T, String> function, T argument) {
    function.apply(argument);
}

which would allow you to write这将允许你写

invokeSafely(serviceClass::method1, new Derived1());
invokeSafely(serviceClass::method2, new Derived2());

but not但不是

invokeSafely(function, new Derived1()); // same error as before
//Incompatible types: Base is not convertible to Derived1
Function<? extends Base,String> function1 = serviceClass::method1; 

It's some weird quirk of type inference that I don't fully understand.这是我不完全理解的类型推断的一些奇怪的怪癖。 It's inferring Function<Base,String> from the left-hand side and trying to apply it to the right-hand-side.它从左侧推断Function<Base,String>并尝试将其应用于右侧。

You can fix it like this.你可以像这样修复它。 The cast is safe:演员是安全的:

Function<? extends Base,String> function1 = (Function<Derived1, String>) serviceClass::method1;

or this:或这个:

Function<Derived1, String> tmp = serviceClass::method1;
Function<? extends Base,String> function1 = tmp;

It's worth noting that you can never invoke this function (except with null ), since you have thrown away the knowledge of what type of argument it expects.值得注意的是,你永远不能调用这个函数(除了null ),因为你已经抛弃了它期望什么类型的参数的知识。 ? extends Base ? extends Base is something that extends Base (ie Derived1 or Derived2) but we don't know which. ? extends Base是扩展 Base(即 Derived1 或 Derived2)的东西,但我们不知道是哪个。

//Incompatible types: Object is not convertible to Derived1            
Function<?,String> function2 = serviceClass::method1;

Same issue as the first one, except it's inferring Object instead of Base.与第一个问题相同,只是它推断的是 Object 而不是 Base。

//Incompatible types: Base is not convertible to Derived2
Function<? super Base,String> function3 = serviceClass::method2;

Derived1 or Derived2 are not super classes of Base. Derived1 或 Derived2 不是 Base 的类。 They are subclasses.它们是子类。 Only Object is a superclass of Base.只有 Object 是 Base 的超类。 method2 does not expect Object . method2不期望Object

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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