keySet()返回java.util.Set。 为什么不向NavigableSet强制转换抛出ClassCastException? 如果真实对象是带有java.util.Set引用的TreeSet,则可以这样做。我无法理解。
import java.util.*;
class A1{}
public class Main{
public static void main(String args[]){
SortedMap nvs=new TreeMap();
nvs.put(1,"one");
nvs.put(2,"two");
nvs.put(3,"three");
nvs.put(4,"four");
NavigableSet nss=(NavigableSet)nvs.keySet();
for(Object ob: nss){
System.out.print(nvs.get(ob)+", ");
}
}
}
答案 0 :(得分:2)
最好的办法是查看TreeMap
的实际代码(这是来自java 1.7):
public Set<K> keySet() {
return navigableKeySet();
}
public NavigableSet<K> navigableKeySet() {
KeySet<K> nks = navigableKeySet;
return (nks != null) ? nks : (navigableKeySet = new KeySet(this));
}
这是KeySet
类声明:
static final class KeySet<E> extends AbstractSet<E> implements NavigableSet<E> {...}
如您所见,TreeMap#keySet
方法返回类型Set
,它是NavigableSet
的超级接口。从Set
实例返回的KeySet
引用指向navigableKeySet()
实例,与KeySet
方法一样。
由于NavigableSet
类实现了NavigableSet
,因此您始终可以将指向其实例的引用转换为keySet()
引用。
为了确保您独立于navigableKeySet()
方法实施,您只需调用NavigableSet
方法即可获得{{1}}并避免投射
答案 1 :(得分:2)
您的问题表明您不了解多态性。让我们用一个类比。你去酒吧,要一杯啤酒。你得到了斯特拉。你没有专门询问斯特拉,并且酒吧没有公开他们的啤酒实际上是斯特拉啤酒,但事实是你得到的实际的混凝土啤酒类型是斯特拉。因为酒吧并不能保证你在要求啤酒时会得到Stella,所以你不应该依赖它,因为未来版本的酒吧可能会给你一个Jupiler,因为Jupiler和Stella都是啤酒。
你的问题也一样。返回类型是Set,因此它可以返回任何类型的Set。除非javadoc保证该方法实际上返回了一个NavigableSet,否则你不应该依赖它。
答案 2 :(得分:0)
它不是通过ClassCastException
,因为返回的对象是NavigableSet
。例如,您可以对返回的对象使用getClass()方法并将其打印出来。该类是NavigableSet
或其子类。
您还可以使用调试器(例如Eclipse)来获取对象的类。
由于SortedMap.keySet()规范告诉它返回Set
个对象,因此将其强制转换为NavigableSet
可能不安全。实现中的其他或更改可能会导致您的代码通过ClassCastException
。
编译器无法检查这一点,因此检查是在运行时执行的。