英文:
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<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)
);
}
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<T>
是一个函数式接口,因为它带有 @FunctionalInterface
注解。这意味着 applyAsInt
的签名与任何 class<sup>1</sup>
、方法引用或者能够从 <T>
映射到 int
的 lambda 表达式相匹配。
在这种情况下,Dish::getCalories
通过调用 Dish
实例的 getCalories()
方法,将一个 Dish
映射到一个 int
:
- 映射的源是
Dish
实例 - 映射的结果是在该实例上调用
getCalories()
后的结果<sup>2</sup>。
(注:这是一个直观的解释。更详细的技术解释,请参阅JLS的相关部分。)
<sup>1 - 如果提供的是类的实例,则该类 API 中只能有一个方法满足函数式接口的要求。因此,假设 Dish
声明了 @ToIntFunction<Dish>
注解,它不能暴露两个无参数且返回 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<T>
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 <T>
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<Dish>
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
的签名与ToIntFunction
的applyAsInt
相同。如果我错了,请纠正我。
英文:
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, 嗯,这里可以运行!我不确定这里是否还有什么隐藏的东西。
<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<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)
);
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>
英文:
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<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)
);
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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论