【问题标题】:Assigning object to interface variable without implementing interface将对象分配给接口变量而不实现接口
【发布时间】:2018-10-26 07:45:18
【问题描述】:

我刚刚学习java 8的方法引用概念。我觉得奇怪的是一个方法引用被分配给接口变量而不实现接口的例子,而调用接口的抽象方法是调用被引用的方法。

interface Sayable {
    void say();
}

public class InstanceMethodReference {
    public void saySomething() {
        System.out.println("Hello, this is non-static method.");
    }

    public static void main(String[] args) {
        InstanceMethodReference methodReference = new InstanceMethodReference();
        Sayable sayable = methodReference::saySomething;
        sayable.say();
    }
}

上面的代码打印了 saySomething 方法的消息,我试图了解这里的方法和对象的内存分配是如何完成的,以及总体上它是如何工作的。

任何帮助表示赞赏。

【问题讨论】:

  • 请从方法名称“saySomething”中删除“say”,看看它是否仍然有效。我猜它只是考虑将“say”作为您要初始化的引用的方法名称的前缀。
  • 但是这是否可以将任何方法分配给任何接口变量然后再次调用接口的抽象方法,这对我来说似乎很混乱。
  • @MuhmmadAbubakarIkram 没关系,仍然有效!
  • 那么返回类型的匹配就是条件。您是否尝试过更改返回类型?我想那它不会工作

标签: java object interface functional-programming


【解决方案1】:

这只是匿名实现或带有闭包的 lambda 的语法糖(指的是定义之外的状态,在您的情况下是 methodReference 的实例)。在这方面,方法引用和 lambda 被同等对待。所以真的是一样的内存分配。

当接口只有一个非静态方法并且该方法的签名与 lambda 或方法引用的签名匹配时,可以使用方法引用(或 lambdas)。在这种情况下,编译器将知道如何包装它,因此它是可分配的。无论是FunctionConsumerSupplier 等“标准”接口之一,还是自定义接口,都应该是功能接口。

以下内容引用来自official Oracle Java documentation

Arrays.sort(rosterAsArray, Person::compareByAge);

方法引用 Person::compareByAge 在语义上与 lambda 表达式 (a, b) -> Person.compareByAge(a, b) 相同。每个都有以下特点:

  • 它的形参列表是从 Comparator.compare 复制过来的,即 (Person, Person)。
  • 它的主体调用方法 Person.compareByAge。

【讨论】:

  • 为什么可以将该 lambda 赋值给 Sayable 类型的变量?不应该是 Function 之类的东西(或等效的返回类型/参数)吗?
  • 感谢您的解释。不过,我认为这可能会产生误导,因为您可能认为您正在调用 say,而实际上您正在调用 saySomething
  • 添加了对答案的回复
  • 您正在调用隐式实现的方法say,而该方法又调用saySomething。确实需要一些时间来适应,IMO lambdas 就足够了,我发现方法引用是多余的。
【解决方案2】:

虽然您的Sayable 没有明确声明它是@FunctionalInterface,但它确实是一个,因为它只有一个非静态方法。

可以为任何函数式接口分配类似 lambda 的表达式(例如 () -> printf("bla bla"))或方法引用(例如 methodReference::saySomething)。就是这样。

【讨论】:

    【解决方案3】:
       interface Rideable {
    CarRide getCarRide(String name);
    }
    class CarRide {
    private String name;
    public CarRide(String name) {
    this.name = name;
    }
    }
    
    public class Test_QN_26 {
    
        public static final int MIN = 1;
    
        public static void main(String[] args) {
    
        
            //C. (Only one correct):
            Rideable rider = CarRide::new;
            CarRide vehicle = rider.getCarRide("MyCarRide");
            System.out.println("vehicle.toString() "+ vehicle.toString());
        
            
    
        enter code here
        }
    
        
    }
    

    【讨论】:

    • 这是一个使用构造函数创建接口的示例,请参考 ::new,它可以正常工作。回答问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-20
    • 2015-11-13
    • 1970-01-01
    • 2017-12-24
    • 1970-01-01
    相关资源
    最近更新 更多