为什么不向NavigableSet强制转换抛出ClassCastException?

时间:2012-12-07 19:57:17

标签: java casting classcastexception treeset sortedset

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)+", ");
         }
     }
}

3 个答案:

答案 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

编译器无法检查这一点,因此检查是在运行时执行的。