Java中如何将Set复制到List?为何此代码无编译错误?
new ArrayList<>(HashMap.keySet())能正常编译运行? 嘿,你的疑惑其实挺常见的——乍一看Set和List是两个不同的集合类型,好像没法直接转换,但这段代码能跑通的关键在于ArrayList的构造器设计和集合接口的继承关系,咱们一步步拆解:
1. HashMap.keySet()的返回类型本质是Collection的子类型
没错,HashMap.keySet()返回的是Set<K>,但你别忘了:Set接口是继承自Collection接口的!也就是说,Set<String>本身就是Collection<String>的一种实现,完全符合Collection类型的定义。
2. ArrayList有一个接受Collection的构造器
ArrayList提供了一个重载构造器:
public ArrayList(Collection<? extends E> c)
这个构造器的作用是把传入的Collection中的所有元素,复制到新创建的ArrayList实例中。这里的泛型参数<? extends E>表示:只要传入的集合元素是E的子类(或者E本身),就可以被接受。
当你写new ArrayList<String>(map.keySet())时,map.keySet()返回的Set<String>正好满足Collection<? extends String>的要求——因为String的子类就是它自己,所以完全匹配构造器的参数类型。
举个实际运行的例子
比如你写这段代码:
HashMap<String, Integer> myMap = new HashMap<>(); myMap.put("apple", 1); myMap.put("banana", 2); List<String> keyList = new ArrayList<>(myMap.keySet());
运行后,keyList会包含"apple"和"banana"(不过注意:HashMap的keySet是无序的,所以list里的元素顺序不固定)。
澄清你的误解
你担心的“Set和List不兼容”是指不能直接把Set实例赋值给List类型的变量(比如List<String> list = myMap.keySet();这行代码肯定会编译错误),但咱们的代码是通过ArrayList的构造器,把Set里的元素“转移”到了新的ArrayList中,这是完全合法的操作——本质是集合间的元素复制,而非类型强制转换。
内容的提问来源于stack exchange,提问作者Roger Kim

