这个方法引用是如何有效的?

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

How is this method reference valid?

问题

class Dish {
  public int getCalories() {
    return calories;
  }

public static final List<Dish> menu = Arrays.asList(
      new Dish("pork", false, 800, Dish.Type.MEAT),
      new Dish("beef", false, 700, Dish.Type.MEAT),
      new Dish("chicken", false, 400, Dish.Type.MEAT),
      new Dish("french fries", true, 530, Dish.Type.OTHER),
      new Dish("rice", true, 350, Dish.Type.OTHER),
      new Dish("season fruit", true, 120, Dish.Type.OTHER),
      new Dish("pizza", true, 550, Dish.Type.OTHER),
      new Dish("prawns", false, 400, Dish.Type.FISH),
      new Dish("salmon", false, 450, Dish.Type.FISH)
  );
}
int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));
英文:
class Dish {
  public int getCalories() {
    return calories;
  }

public static final List&lt;Dish&gt; menu = Arrays.asList(
      new Dish(&quot;pork&quot;, false, 800, Dish.Type.MEAT),
      new Dish(&quot;beef&quot;, false, 700, Dish.Type.MEAT),
      new Dish(&quot;chicken&quot;, false, 400, Dish.Type.MEAT),
      new Dish(&quot;french fries&quot;, true, 530, Dish.Type.OTHER),
      new Dish(&quot;rice&quot;, true, 350, Dish.Type.OTHER),
      new Dish(&quot;season fruit&quot;, true, 120, Dish.Type.OTHER),
      new Dish(&quot;pizza&quot;, true, 550, Dish.Type.OTHER),
      new Dish(&quot;prawns&quot;, false, 400, Dish.Type.FISH),
      new Dish(&quot;salmon&quot;, false, 450, Dish.Type.FISH)
  );
}

How is the following Dish::getCalories method reference valid when summingInt requires a ToIntFunction? I am asking because the signature of getcalories does not match the signature of applyAsInt abstract method of ToIntFunction

int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));

答案1

得分: 3

> 我之所以在问这个问题,是因为 getCalories 的签名与 ToIntFunction 接口的 applyAsInt 抽象方法的签名不一致。

实际上,它是匹配的。

ToIntFunction&lt;T&gt; 是一个函数式接口,因为它带有 @FunctionalInterface 注解。这意味着 applyAsInt 的签名与任何 class&lt;sup&gt;1&lt;/sup&gt;、方法引用或者能够从 &lt;T&gt; 映射到 int 的 lambda 表达式相匹配。

在这种情况下,Dish::getCalories 通过调用 Dish 实例的 getCalories() 方法,将一个 Dish 映射到一个 int

  • 映射的源是 Dish 实例
  • 映射的结果是在该实例上调用 getCalories() 后的结果<sup>2</sup>。

(注:这是一个直观的解释。更详细的技术解释,请参阅JLS的相关部分。)


<sup>1 - 如果提供的是类的实例,则该类 API 中只能有一个方法满足函数式接口的要求。因此,假设 Dish 声明了 @ToIntFunction&lt;Dish&gt; 注解,它不能暴露两个无参数且返回 int 的方法。</sup>

<sup>2 - 正常的方法覆盖规则适用。如果实际对象是 Dish 的子类型的实例,并且它重写了 getCalories(),那么映射会调用那个方法,而不是被重写的方法。</sup>

英文:

> I am asking because the signature of getCalories does not match the signature of applyAsInt abstract method of ToIntFunction.

Actually, it does match.

ToIntFunction&lt;T&gt; is a functional interface since it has the annotation @FunctionalInterface. That means that the signature of applyAsInt matches any class<sup>1</sup>, method reference or lambda that provides a method that maps from &lt;T&gt; to int.

In this case Dish::getCalories is mapping a Dish to an int by calling the Dish instance's getCalories() method on it:

  • The source for the mapping is the instance of Dish
  • The result of the mapping is the result of calling getCalories() on the instance<sup>2</sup>.

(Note: this is an intuitive explanation. For a technical explanation, refer to the relevant parts of the JLS.)


<sup>1 - In the case where an instance of a class is supplied, there can only be one method in the class API that satisfies the functional interface requirement. So, hypothetically, if Dish was declared with the @ToIntFunction&lt;Dish&gt; annotation, it could not expose two methods that take no arguments and return an int.</sup>

<sup>2 - Normal method overriding rules apply. If the actual object is an instance of a subtype of Dish, and it overrode getCalories(), then the mapping would call that method, not the overridden method.</sup>

答案2

得分: 0

因此,对于任何想知道为什么它有效的人来说,它有效是因为this在对象的每个方法中都是一个隐含的第一个参数。因此,Dish::getCalories的签名与ToIntFunctionapplyAsInt相同。如果我错了,请纠正我。

英文:

For anyone wondering why it works. It works because this is an implicit first argument to every method of an object. Hence, the signature of Dish::getCalories is the same as applyAsInt of ToIntFunction. Please correct me if I am wrong.

答案3

得分: 0

Emmm,这里可以运行我不确定这里是否还有什么隐藏的东西

&lt;pre&gt;
import java.util.List;

import static java.util.stream.Collectors.summingInt;

import java.util.Arrays;

class Dish {

	public int getCalories() {
		return calories;
	}

	public static final List&lt;Dish&gt; menu = Arrays.asList(
			new Dish(&quot;pork&quot;, false, 800, Dish.Type.MEAT),
			new Dish(&quot;beef&quot;, false, 700, Dish.Type.MEAT),
			new Dish(&quot;chicken&quot;, false, 400, Dish.Type.MEAT),
			new Dish(&quot;french fries&quot;, true, 530, Dish.Type.OTHER),
			new Dish(&quot;rice&quot;, true, 350, Dish.Type.OTHER),
			new Dish(&quot;season fruit&quot;, true, 120, Dish.Type.OTHER),
			new Dish(&quot;pizza&quot;, true, 550, Dish.Type.OTHER),
			new Dish(&quot;prawns&quot;, false, 400, Dish.Type.FISH),
			new Dish(&quot;salmon&quot;, false, 450, Dish.Type.FISH)
	);

	public static void main(String[] args) {
		int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));
		System.out.println(totalCalories);
	}

	String name;

	int calories;

	Dish.Type type;

	public Dish(String name, boolean b, int calories, Dish.Type type) {
		super();
		this.name = name;
		this.calories = calories;
		this.type = type;
	}

	enum Type {
		MEAT, FISH, OTHER
	}

}
&lt;/pre&gt;
英文:

Emmm, well, it works here! I'm not sure if there is still something concealed here.

<pre>
import java.util.List;

import static java.util.stream.Collectors.summingInt;

import java.util.Arrays;

class Dish {

public int getCalories() {
return calories;
}
public static final List&lt;Dish&gt; menu = Arrays.asList(
new Dish(&quot;pork&quot;, false, 800, Dish.Type.MEAT),
new Dish(&quot;beef&quot;, false, 700, Dish.Type.MEAT),
new Dish(&quot;chicken&quot;, false, 400, Dish.Type.MEAT),
new Dish(&quot;french fries&quot;, true, 530, Dish.Type.OTHER),
new Dish(&quot;rice&quot;, true, 350, Dish.Type.OTHER),
new Dish(&quot;season fruit&quot;, true, 120, Dish.Type.OTHER),
new Dish(&quot;pizza&quot;, true, 550, Dish.Type.OTHER),
new Dish(&quot;prawns&quot;, false, 400, Dish.Type.FISH),
new Dish(&quot;salmon&quot;, false, 450, Dish.Type.FISH)
);
public static void main(String[] args) {
int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));
System.out.println(totalCalories);
}
String name;
int calories;
Dish.Type type;
public Dish(String name, boolean b, int calories, Dish.Type type) {
super();
this.name = name;
this.calories = calories;
this.type = type;
}
enum Type {
MEAT, FISH, OTHER
}

}
</pre>

huangapple
  • 本文由 发表于 2020年8月22日 12:45:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/63532654.html
匿名

发表评论

匿名网友

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

确定