当前位置: 首页 > 知识库问答 >
问题:

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

令狐烨烨
2023-03-14

想得到一些建议

我的班级结构是这样的

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";
    }
}

在我的主代码(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;
    }
}

有没有办法声明我的函数对象,以便可以使用相同的函数对象来引用采用不同类型参数的方法?

共有3个答案

上官兴昌
2023-03-14

您可以将模式匹配用于开关表达式,它仍处于预览阶段,但将很快在即将于2022年9月发布的Java19中完成。

public static class ServiceClass {
    public static String method(Base base) {
        return switch (base) {
            case Derived1 d1 -> "Derived1";
            case Derived2 d2 -> "Derived2";
            default          -> "Unknown subtype";
        };
    }
}

main()

public static void main(String[] args) {
    Function<? super Base,String> func = ServiceClass::method;

    System.out.println(func.apply(new Derived1()));
    System.out.println(func.apply(new Derived2()));        
}

输出:

Derived1
Derived2
酆勇
2023-03-14
//Incompatible types: Base is not convertible to Derived1
Function<? extends Base,String> function1 = serviceClass::method1; 

这是一种我不完全理解的奇怪的类型推断。这是推断函数

你可以这样修理它。演员阵容安全:

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

或者这个:

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

值得注意的是,您永远不能调用此函数(除非使用null),因为您已经放弃了它所期望的参数类型的知识<代码>?extends Base是扩展Base的东西(即Derived1或Derived2),但我们不知道是哪个。

//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;

Derived1或Derived2不是Base的超类。它们是子类。只有Object是Base的超类。方法2不期望对象

慕容宇
2023-03-14

是的,通过使用中间变量

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

也就是说,您将无法调用函数,因为您不知道是传递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)

但是,您可以使用泛型对参数类型进行抽象:

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

这样你就可以写

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

但不是

invokeSafely(function, new Derived1()); // same error as before
 类似资料:
  • 问题内容: 我在理解Hibernate如何处理泛型时遇到一些麻烦,并且想知道实现我的目标的最佳方法。 给定一个简单的通用实体: 在进行hibernate初始化时,出现异常: 我几乎可以肯定,这是因为我没有给hibernate一些可能的限制条件。我知道你可以指定的东西,如上面的注释,但你失去使用泛型的灵活性。我可以使用注解限制可接受的泛型的范围吗?例如:如果我想要class ,该类从抽象类继承而来,

  • null 为什么我不能在MyList中添加对象。因为如果我们使用super,这意味着这个列表可以包含在Java类的继承制度中等于或高于number的对象。因此应该按照该语句在列表中添加新的Object()。 多谢了。

  • 问题内容: 我有一个简单的示例,它似乎应该工作: 因此,我们有一个名为的类,它符合协议,并定义了一个可选的类方法。 但是,这一行: 导致错误: 类型名称后的预期成员名称或构造函数调用 知道我在做什么错吗? 编辑 从声明中删除单词并稍微更改函数可以使代码得以编译,但是现在我遇到了运行时错误,指出 “快速动态投放失败” 问题答案: 我无法解释为什么您的代码会导致运行时异常。但是,如果您更改函数原型,它

  • 问题内容: 更新: 感谢所有提供帮助的人-这个答案的答案在于我在更复杂的代码中没有注意到的内容以及对Java5协变量返回类型不了解的内容。 原始帖子: 今天早上我一直在玩一些东西。虽然我知道我 可以用 不同的方式解决整个问题,但我发现自己一直迷恋于弄清楚为什么它没有按我预期的那样工作。在花了一些时间阅读这些内容之后,我发现我离理解还很近,因此我将其作为一个问题来看看我是否只是愚蠢,或者是否真的有我

  • 问题内容: 我有一个接口将对象转换为字符串: 以及用于存储所有可用转换器的地图: 现在,我有了要转换的异构数据列表,如下所示: 但是此代码无法编译: 我应该如何更改代码? 问题答案: 您面临的问题称为通配符捕获。Java无法识别将从数据中接收的类型。尝试以两种方式中的任何一种重构代码 方法1:如下 更改您的界面 方法2: 通过类型推断来捕获通配符的Helper方法 创建如下的帮助方法, 如下调用此

  • 问题内容: 我使用SpringBoot进行REST Web服务开发,并使用SonarQube进行静态分析。 我的应用程序中有一些端点,它们的外观如下: SonarQube抱怨将ResponseEntity与通配符一起使用,并向我报告了一个 严重问题:“返回参数中不应使用通用通配符类型” 。 我想知道是否应该在SonarQube中禁用此验证,或者针对这些情况提出不同的返回类型。 你怎么看待这件事?