“Lambdas” 和 “reference method” 在这个例子中是如何工作的?

huangapple go评论38阅读模式
英文:

How does lambdas and reference method work in this example?

问题

I have a doubt about the functioning of the following code since the Car class does not implement the Rideable interface, and I don't know how it is possible ?

我对以下代码的运行方式有疑问,因为Car类没有实现Rideable接口,我不知道这是如何可能的?

I'm using two ways to do it, one is lambda and the other with reference method.

我有两种方法来实现它,一种是使用Lambda表达式,另一种是使用引用方法。

interface Rideable {
    Car getCar(String name);
}

class Car {
    private String name;

    public Car(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public static void main(String[] args) {
        //both lines are valid for compilation
        Rideable rider = Car::new; 
        //Rideable rider = c -> new Car(c); 

        Car vehicle = rider.getCar("My Car");
        System.out.println(vehicle.getName());
    }
}
界面Rideable {
    Car getCar(String name);
}

类Car {
    private String name;

    public Car(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public static void main(String[] args) {
        // 这两行都可以编译通过
        Rideable rider = Car::new; 
        //Rideable rider = c -> new Car(c); 

        Car vehicle = rider.getCar("My Car");
        System.out.println(vehicle.getName());
    }
}
英文:

I have a doubt about the functioning of the following code since the Car class does not implement the Rideable interface, and I don't know how it is possible ?

I'm using two ways to do it, one is lambda and the other with reference method.

interface Rideable {
	Car getCar(String name);
}

class Car {
	private String name;

	public Car(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}

	public static void main(String[] args) {
		//both lines are valid for compilation
		Rideable rider = Car::new; 
		//Rideable rider = c -> new Car(c); 

		Car vehicle = rider.getCar("My Car");
		System.out.println(vehicle.getName());
	}
}

答案1

得分: 4

Car::new不是“一个新车”。

new Cake()就像:“做一个蛋糕;一旦你做好了,把这个值变成表达式new Cake()的值。”

Cake::new一点都不像蛋糕。它根本不是蛋糕,它的值也没有实现蛋糕的任何接口。毕竟,Cake::new是一个蛋糕的食谱。它是一种能够制作蛋糕的东西,与蛋糕毫无关系。你可以吃蛋糕,但不能吃食谱,或者烤箱,或者面包师(嗯,我猜你可以,但让我们不要对这个感到奇怪。当然,吃掉一个面包师的味道一点都不像蛋糕)。

在Java中,像Cake::new这样的“食谱”是“未类型化的” - 相反,编译器会查看上下文;围绕这个表达式的东西。这就是为什么这个:

Object o = Cake::new;

不会编译:从上下文来看,根本没有任何提示,说明你想要做什么。

上下文需要告诉编译器需要什么类型的食谱,然后编译器会检查你编写的食谱是否符合这些要求。如果符合,那就很好,你得到了你想要的。如果不符合,你会得到一个编译器错误。

所以,回到你的代码:

Rideable描述了一个食谱:任何将名称作为输入并将其转换为Car的食谱都可以被视为“Rideable”。鉴于这是一个定义了精确一个方法的接口,它被称为FunctionalInterface,这些接口很特殊:你可以使用lambda语法或方法引用语法即时创建一个新的rideable。编译器将使lambda/reference表达式适应作为Rideable的新实例。

事实证明,Car::new符合要求!有一个接受字符串的构造函数,构造函数实际上“返回”一个Car,这与Rideable定义的那个方法相匹配。因此,编译器从上下文中确定了你想要什么,它适合,并继续执行。因此,这个:

Rideable r = Car::new;

只是这个语法糖:

Rideable r = name -> new Car(name);

基本上是这个语法糖*:

Rideable r = new Rideable() {
    public Car getCar(String name) {
        return new Car(name);
    }
}

这是这个语法糖:

public class YourCustomRideable implements Rideable {
    @Override public Car getCar(String name) {
        return new Car(name);
    }
}

Rideable r = new YourCustomRideable();

*) 这两者之间有微小的、基本上无关紧要的差异;编译器生成的字节码略有不同。有办法观察这个差异,比如要求获取骑手的标识哈希码,但是不要这样做。你不应该把这些东西当做有相关性的东西,你的Rideable“实例”的整个目的是你打算在其上调用getCar而已,什么都不要做。只要你这样做,这4行代码都是完全等价的。

英文:

Car::new is not 'a new car'.

new Cake() is like: "make a cake; once you've made it, make that the value of the expression new Cake().

Cake::new is nothing like a cake. It's not a cake whatsoever, and its value implements none of the interfaces cake do. After all, Cake::new is a cake recipe. It is a thing capable of making cakes, and that has nothing to do with cakes. You can eat a cake. You can't eat a recipe, or an oven. Or a baker (well, I guess you can, but let's not get weird with this. Certainly eating a baker is going to taste nothing like a cake).

In java, 'recipes' like Cake::new are 'untyped' - instead, the compiler looks at the context; the stuff around this expression. That's why this:

    Object o = Cake::new;

is not going to compile: From context, there's no hints whatsoever as to what you're trying to do here.

The context needs to tell the compiler exactly what sort of recipe is required, and then the compiler will check if the recipe you've written will fit these needs. If yeah, great, then that's what you get. If not, you get a compiler error.

So, back to your code:

a Rideable describes a recipe: Any recipe that takes as input a name, and turns that into a Car, can be deemed a 'Rideable'. Given that this is an interface that defines precisely one method, it is a so-called FunctionalInterface, and those are special: You can use lambda syntax or method reference syntax to create a new rideable on the fly. The compiler will 'fit' the lambda/reference expression to act as a new instance of Rideable.

Turns out, Car::new fits the bill! There is a constructor that takes a string, and constructors effectively 'return' a Car, which matches that one defined method that Rideable has. Thus, the compiler has determined from the context what you want, that it fits, and goes ahead and does it. Therefore, this:

Rideable r = Car::new;

is just syntax sugar for this:

Rideable r = name -> new Car(name);

which is basically syntax sugar* for this:

Rideable r = new Rideable() {
    public Car getCar(String name) {
        return new Car(name);
    }
}

which is syntax sugar for this:

    public class YourCustomRideable implements Rideable {
        @Override public Car getCar(String name) {
            return new Car(name);
        }
    }

    Rideable r = new YourCustomRideable();

*) There are slight, basically irrelevant differences between the two; the compiler produces slightly different byte code. There are ways to observe this difference, such as asking for the identity hashcode of the rider, but, don't. You're not supposed to treat these things as having a relevant identity, the whole point of your 'instance' of Rideable is that you intend to invoke getCar on it and nothing else. As long as you do that, these 4 lines of code are all entirely equivalent.

答案2

得分: 2

Car::new 在使用的上下文中有不同的含义。

在这种情况下,它与以下代码相同:

Rideable rider = name -> new Car(name);

Rideable 只是接受一个 String 并返回一个 Car 的东西。这不要求 Car 实现 Rideable:您使用的是它的构造函数,它接受一个 String 并返回一个 Car

英文:
Car::new

has a meaning which depends on the context in which it is used.

In this case, it is the same as:

Rideable rider = name -> new Car(name);

A Rideable is just something which takes a String and gives you back a Car. This doesn't require Car to implement Rideable: you're using its constructor, which takes a String, and gives you back a Car.

答案3

得分: 1

这个lambda表达式等价于new CarRideable(),如果在某处定义了一个类,类似于以下方式:

class CarRideable implements Rideable {
  public Car getCar(String name) {
    return new Car(name);
  }
}

Car::new 表示只需使用 Car 构造函数来实现 Rideable 中的唯一方法,它可以这样实现。

英文:

That lambda is equivalent to new CarRideable() if there were a class defined somewhere like this:

class CarRideable implements Rideable {
  public Car getCar(String name) {
    return new Car(name);
  }
}

Car::new just says to use the Car constructor to implement the one and only method in Rideable, which it can.

答案4

得分: 0

Java 8 使用接口的概念来引入另一个称为 lambda 表达式 的概念。

首先,您应该了解 FunctionalInterface,函数式接口是一个只包含一个抽象方法的接口,在这里您定义了一个名为 Ridable 的接口,其中只有一个 getCar 方法。

其次,您应该知道 lambda 可以分配给函数式接口,并且 lambda 的类型将由函数式接口的抽象方法指定。所以在这里,不需要您的代码,我们可以有以下代码:

Rideable rider = (String name) -> new Car(name);

这里的 (String name) -> new Car(name) 是一个 lambda 表达式,您可以看到 lambda 的签名与 Ridable Functional interface 中的抽象方法相同。但是在这里 lambda 的右侧什么也不做,只是调用一个方法(这里是构造函数),所以是否更好地引用该方法而不是创建这样的 lambda:

Rideable rider = Car::new;

英文:

Java 8 used the concept of interface for introducing another concept which is called lambda expression.

First of all you should know about FunctionalInterface, Functional interface is an interface with only one abstract method in it here you have defined Ridable interface which has only getCar method in it.

Second you should know lambda can be assigned to functional interface and the type of the lambda will be specified by the abstract method of the functional interface. So here instead of your code we could have:

Rideable rider = (String name) -> new Car(name);

here (String name) -> new Car(name) is a lamba expression, you can see the signature of lambda is the same as abstract method in Ridable Functional interface. But here the right hand side of lambda do nothing but calling a method (which here is a cunstroctor) so isn't it better to just refer to that method instead of creating a lambda like this:

Rideable rider = Car::new;

huangapple
  • 本文由 发表于 2020年7月28日 03:57:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/63122639.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定