好的,所以SortedMap
/SortedSet
是一个接口,而TreeMap
/TreeSet
是它的实现。他们都保持元素排序,对吧?那么为什么我们需要TreeMap
/ TreeSet
?
5 回答
接口不提供任何功能,它们只是根据它提供的方法定义一个类的大致轮廓。SortedMap
但是/内部没有代码SortedSet
实现如何实际实现此功能。
事实上,您通常可以有多种方法来实现相同的功能。想一想接口java.util.Set
:您可以将其实现为 aTreeSet
也可以实现为HashSet
. 通常,不同实现之间存在一些权衡:哈希集可能平均提供更快的访问时间,而树集可能更好地保持其项目的顺序。
然而,通常情况下,开发人员并不真正关心实现细节,只要他们知道他们可以将项目存储在集合中并检索它们。这个基本思想,但不是如何实现它,是由接口定义的。
这也是您无法实例化接口的原因。如果您尝试以下操作:
SortedSet<Integer> set = new SortedSet<Integer>();
你的编译器会抱怨。那是因为“SortedSet”本身并没有真正实现一个集合,它只是定义了一个有序集合的实现必须在方法方面提供什么。
这是一个人为的例子。想象一下,您想提供一个计算集合中正整数百分比的功能。你可以定义一个方法:
public double getPercentageOfPositives(Set<Integer> set) {
if (set.size() == 0) {
return 0.0;
}
int count = 0;
for (Iterator<Integer> iter = set.iterator(); iter.hasNext();) {
if (iter.next() > 0) count++;
}
return 100.0 * count / set.size();
}
在这里,您并不真正关心您的方法的用户是给您 aTreeSet
还是 a HashSet
。给定类使用哪种原则并不重要,因为无论如何您只是在调用size()
方法和方法。iterator()
您所需要的只是相信任何集合都将具有这两种方法这一事实。一个界面给了你这种信任。
因此,您的方法签名只要求 a Set
,这是一个接口,定义了所有实现它的类必须提供(以及其他)asize()
和一个iterator()
方法。如果你这样写:
public double getPercentageOfPositives(SortedSet<Integer> set) {
...
}
我有一个实例,HashSet
即使HashSet
提供了size()
,我也无法使用您的方法iterator()
。:-(
从这个意义上说,接口就像一个超类,它定义了所有实现它的类必须具有的共性。但它本身不提供任何功能。
因此回到你原来的例子SortedSet
:这个接口不提供任何功能。它只定义了排序集实现必须提供的方法。TreeSet
就是这样一个实现。
同样的思路也适用于SortedMap
.
对,因为当我们有类时我们需要接口。
SortedMap
并SortedSet
定义通过使用带有 aTreeMap
和 a 的树来实现的功能TreeSet
。
SortedMap
/SortedSet
是接口,所以你不能实例化它们。 TreeMap
/TreeSet
是类,可以实例化和使用。我们需要SortedMap
/的原因SortedSet
是除了 Sun 的基于树的实现之外,可能还有其他实现。
这是一张用于获取大图的备忘单(来源在图片中)
答案就在你的问题中;SortedMap
并且SortedSet
是接口。它们定义了方法和属性,但实际上并没有实现它们,因此它们不提供任何功能。
TreeMap
并且TreeSet
是这些接口的实现。
良好的 OOP 设计实践建议您对接口而不是实现进行编码。这意味着您的所有方法签名都应该引用接口而不是类。
所以你会这样做:
Object squishObjects(SortedMap map);
代替
Object squishObjects(TreeMap map);
这样,如果出现更好的实现SortedMap
,您可以将其切换,而无需修改所有依赖于TreeMap
.