- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我读过 Joshua Bloch 写的很棒的“Effective Java”。但是我不清楚书中的一个例子。它摘自关于泛型的章节,确切的条目是“第 28 条:使用有界通配符来增加 API 灵 active ”。
在本项目中,它展示了如何使用有界类型参数和有界通配符类型编写最通用和防弹(从类型系统的角度来看)版本的从集合中选择最大元素的算法。
写的静态方法的最终签名是这样的:
public static <T extends Comparable<? super T>> T max(List<? extends T> list)
它与 Collections#max
中的一个基本相同来自标准库的函数。
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
我理解为什么我们需要在 T extends Comparable<? super T>
中使用有界通配符类型约束,但在参数类型中真的有必要吗?在我看来,如果我们只留下 List<T>
也是一样的或 Collection<T>
,不是吗?我的意思是这样的:
public static <T extends Comparable<? super T>> T wrongMin(Collection<T> xs)
我编写了以下使用这两种签名的愚蠢示例,但没有发现任何区别:
public class Algorithms {
public static class ColoredPoint extends Point {
public final Color color;
public ColoredPoint(int x, int y, Color color) {
super(x, y);
this.color = color;
}
@Override
public String toString() {
return String.format("ColoredPoint(x=%d, y=%d, color=%s)", x, y, color);
}
}
public static class Point implements Comparable<Point> {
public final int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return String.format("Point(x=%d, y=%d)", x, y);
}
@Override
public int compareTo(Point p) {
return x != p.x ? x - p.x : y - p.y;
}
}
public static <T extends Comparable<? super T>> T min(Collection<? extends T> xs) {
Iterator<? extends T> iter = xs.iterator();
if (!iter.hasNext()) {
throw new IllegalArgumentException("Collection is empty");
}
T minElem = iter.next();
while (iter.hasNext()) {
T elem = iter.next();
if (elem.compareTo(minElem) < 0) {
minElem = elem;
}
}
return minElem;
}
public static <T extends Comparable<? super T>> T wrongMin(Collection<T> xs) {
return min(xs);
}
public static void main(String[] args) {
List<ColoredPoint> points = Arrays.asList(
new ColoredPoint(1, 2, Color.BLACK),
new ColoredPoint(0, 2, Color.BLUE),
new ColoredPoint(0, -1, Color.RED)
);
Point p1 = wrongMin(points);
Point p2 = min(points);
System.out.println("Minimum element is " + p1);
}
那么您能举个例子说明这种简化的签名是 Not Acceptable 吗?
附言为什么会有T extends Object
在正式实现中?
好吧,多亏了@Bohemian,我才弄清楚它们之间的区别。
考虑以下两种辅助方法
private static void expectsPointOrColoredPoint(Point p) {
System.out.println("Overloaded for Point");
}
private static void expectsPointOrColoredPoint(ColoredPoint p) {
System.out.println("Overloaded for ColoredPoint");
}
当然,为父类(super class)及其子类重载方法不是很聪明,但它让我们看到实际推断出的返回值类型(points
和以前一样是 List<ColoredPoint>
)。
expectsPointOrColoredPoint(min(points)); // print "Overloaded for ColoredPoint"
expectsPointOrColoredPoint(wrongMin(points)); // print "Overloaded for ColoredPoint"
对于这两种方法,推断类型都是 ColoredPoint
.
有时您希望明确传递给重载函数的类型。您可以通过几种方式进行:
你可以投:
expectsPointOrColoredPoint((Point) min(points)); // print "Overloaded for Point"
expectsPointOrColoredPoint((Point) wrongMin(points)); // print "Overloaded for Point"
仍然没有区别...
或者您可以使用语法 class.<type>method
告诉编译器应该推断出什么类型:
expectsPointOrColoredPoint(Algorithms.<Point>min(points)); // print "Overloaded for Point"
expectsPointOrColoredPoint(Algorithms.<Point>wrongMin(points)); // will not compile
啊哈!这是答案。 List<ColoredPoint>
无法传递给需要 Collection<Point>
的函数因为泛型不是协变的(不像数组),但可以传递给期望 Collection<? extends Point>
的函数.
在这种情况下,我不确定在哪里或谁可能更喜欢使用显式类型参数,但至少它显示了 wrongMin
在哪里可能不合适。
感谢@erickson 和@tom-hawtin-tackline 对 T extends Object
目的的回答约束条件。
最佳答案
不同之处在于返回的类型,尤其是受推理的影响,其中类型可能是 Comparable 类型和List 类型之间的分层类型。让我举个例子:
class Top {
}
class Middle extends Top implements Comparable<Top> {
@Override
public int compareTo(Top o) {
//
}
}
class Bottom extends Middle {
}
使用您提供的签名:
public static <T extends Comparable<? super T>> T max(List<? extends T> list)
我们可以在没有错误、警告或(重要的)转换的情况下编写代码:
List<Bottom> list;
Middle max = max(list); // T inferred to be Middle
如果您需要 Middle
结果,无需推断,您可以显式键入对 Middle
的调用:
Comparable<Top> max = MyClass.<Middle>max(list); // No cast
或传递给接受Middle
的方法(其中推理不起作用)
someGenericMethodThatExpectsGenericBoundedToMiddle(MyClass.<Middle>max(list));
我不知道这是否有帮助,但为了说明编译器允许/推断的类型,签名看起来像这样(当然不是编译):
public static <Middle extends Comparable<Top>> Middle max(List<Bottom> list)
关于java - 为什么我们需要有界通配符 <?在 Collections.max() 方法中扩展 T>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47055975/
快速且可能简单的 Lambda 问题: 我有一家有评论的餐厅。我想查询具有以下内容的那个: 最大(平均评分) 和 Max(ReviewCount) 和 Max(NewestReviewDate) 和
在尝试使用 C++17 折叠表达式时,我尝试实现 max sizeof ,其中结果是类型 sizeof 的最大值。我有一个使用变量和 lambda 的丑陋折叠版本,但我想不出一种使用折叠表达式和 st
我目前正在使用 C 并遇到了一些我觉得有趣的东西,但似乎在这里找不到任何类似的东西。 我正在为数组(大小 1000000)静态分配内存。我知道这相当大并且有可能引起问题。但是,使用 10^6 不会出现
我有一个具有 max-height 的 div 和其中的图像,应该使用 max-width:100% 和 max-height:100%。在 Chromium 中,这是可行的,但 Firefox 仅使
我有一个最大高度的 div 和里面的一个图像,它应该使用最大宽度:100% 和最大高度:100%。在 Chromium 中,这是可行的,但 Firefox 仅使用最大宽度而忽略最大高度。 div#ov
在一本在线 awk 手册中我找到了例子awk '{ if (NF > max) max = NF } END { print max }' 该程序打印任何输入行上的最大字段数。但我不明白 awk 如何
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在制作一个非循环图数据库。 表 Material (id_item,id_collection,...)主键(id_item,id_collection) (item可以是collection本身
我有以下两个表。 1.电影详情(电影ID、电影名称、评分、票数、年份) 2.电影类型(Movie-ID,Genre) 我正在使用以下查询来执行连接并获得每个评分最高的电影流派。 select Movi
我有一个查询,我想返回 idevent 中给定传感器 ID (sensorID) 范围内的最高 ID 值,但是查询没有返回最高值。 我运行查询时减去 max() 语句的结果: mysql> SELEC
SUM(MAX() + MAX()) 有正确的方法吗? 这是我一直在努力做的事情 SELECT SUM(MAX(account.BALANCE1) + MAX(account.BALANCE2))
这个问题类似于CSS media queries: max-width OR max-height , 但由于我的代表不够高,我无法在回复中添加评论(问题),我想在原始问题中添加。 与其他主题中的发帖
Jon Skeet今天报告(source): Math.Max(1f, float.NaN) == NaN new[] { 1f, float.NaN }.Max() == 1f 为什么? 编辑:双倍
这个问题已经有答案了: Java 8 stream's .min() and .max(): why does this compile? (5 个回答) 已关闭 7 年前。 我正在学习1z0-809
我在处理一些数据库记录时遇到了一些挑战。 我需要为特定列获取具有 MAX 值的行,并且这些记录必须介于两个时间戳值之间。 这是SQL查询 SELECT id, MAX(amount), created
我想在媒体查询中使用 AND 条件。我使用了下面的代码,但是没有用 @media screen and (max-width: 995px AND max-height: 700px) { } 最佳答
在编写 CSS 媒体查询时,有什么方法可以用“或”逻辑指定多个条件吗? 我正在尝试做这样的事情: /* This doesn't work */ @media screen and (max-widt
我对仅使用 max(list array) 和 np.max(list array) 之间的区别有疑问。 这里唯一的区别是 Python 返回代码所需的时间吗? 最佳答案 它们在边缘情况下可能不同,例
例如: a = [[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.
这个问题在这里已经有了答案: Java 8 stream's .min() and .max(): why does this compile? (5 个答案) 关闭 6 年前。 我正在学习 1z0
我是一名优秀的程序员,十分优秀!