有人可以解释一下为什么这段代码编译并运行正常,尽管SortedSet是一个接口而不是一个具体的类:
public static void main(String[] args) {
Integer[] nums = {4, 7, 8, 14, 45, 33};
List<Integer> numList = Arrays.asList(nums);
TreeSet<Integer> numSet = new TreeSet<Integer>();
numSet.addAll(numList);
SortedSet<Integer> sSet = numSet.subSet(5, 20);
sSet.add(17);
System.out.println(sSet);
}
它通常打印结果:[7, 8, 14, 17]
此外,由于SortedSet无法实现(预期),因此我更加惊讶。这行不编译:
SortedSet<Integer> sSet = new SortedSet<Integer>();
但是,如果我尝试代码:
public static void main(String[] args) {
Integer[] nums = {4, 7, 8, 14, 45, 33};
List<Integer> numList = Arrays.asList(nums);
numList.add(56);
System.out.println(numList);
}
它会抛出一个UnsupportedOperationException
。我估计,这来自List是一个接口而不能作为具体类处理的事实。 SortedSet
的真实情况如何?
答案 0 :(得分:3)
SortedSet是一个界面。这意味着您可以引用实现此接口的类,但不能创建没有implmenetation的类实例。
在Arrays.asList()的情况下,它返回一个包装原始数组的类。您无法添加到原始阵列,因此不支持添加。例如,如果使用set,则将更改原始数组。
答案 1 :(得分:1)
List<Integer> numList = Arrays.asList(nums);
Array.asList()
在List界面中返回数组但换行。所以列表仍然由数组支持,并且数组是固定大小,您不能添加/删除数组中的元素。这就是为什么下一行会抛出异常UnsupportedOperationException
。
有关更多详细信息,java ArrayList
仍然是一个数组,但它有一些帮助方法,您可以删除/添加元素(您可以使用wiki作为短语resizeable array
以获取更多详细信息。
其次,SortedSet
是一个接口。像抽象类这样的接口可以引用一个实现/扩展它的类,但它不是具体类,所以你不能在那些(接口或抽象类)上创建对象。
我知道,你提出的两个问题,可能都与OOP中的polymorphism
有关,我也建议你使用wiki这句话。
希望这有帮助:)
答案 2 :(得分:0)
SortedSet是一个接口而不是一个类。
你只能从非抽象类中实例化。
列表也是一个界面。 但是根据List的文档,“add”方法是可选的,这意味着没有保证可以得到支持。
我认为可选方法与接口的概念和契约相矛盾。 最好的方法是使用NonModifyableList(不添加)和ModifyableList(使用add)。 目前糟糕的选择可能是历史和不打破旧代码的结果。
答案 3 :(得分:0)
如果我理解正确,您就会问为什么可以成功将对象引用为SortedSet(或任何接口类型)。当变量的类型是接口或抽象类时,这意味着变量必须包含一个继承该变量类型(或null对象)的对象。
虽然每个对象的实际类型必须是具体类,但sSet
变量只需要保存某个继承(实现)SortedSet的类的实例。
对于TreeSet.subSet
方法,它返回一个对象,其类型是一个内部定义的具体类,它实现了SortedSet。