报错:
java.lang.ClassCastException: java.util.HashMap$Values cannot be cast to java.util.ArrayList
场景:
class DAO<T>{
//一个hashMap对象
private Map<String,T> map = new HashMap<>();
//这个方法返回一个list类对象
public List<T> list(){
return (ArrayList<T>) map.values();
}
}
这里想将HashMap中的值取出来转换成一个List接口类的对象再返回。然后使用HashMap的values()方法返回collection集合,再使用向下转型将collection集合转型为他的子类ArrayList发生类型转换错误。一开始想的比较简单,但是报错了,于是回顾之前的转型知识搞明白了为什么有这种情况。
回顾向下转型:
首先我们为什么要有向下转型? 因为在向上转型之后,我们的父类引用指向子类对象,但是如果我们要使用子类的特有方法,这时候会发现编译器报错,所以我们引出了向下转型。在这个向上转型和向下转型的过程中,向上转型是安全的,而向下转型并不是安全的。
比如
class Animal {}
class Dog extends Animal{}
public class test {
public static void main(String[] args){
Animal animal = new Animal();//创建一个父类对象
Dog dog = (Dog) animal;//通过强制类型转换将animal对象强制向下转型赋给一个子类对象
}
}
这时会报错
Exception in thread "main" java.lang.ClassCastException: Homework.Animal cannot be cast to Homework.Dog at Homework.test.main(test.java:16)
也就是说我们是无法把一个子类对象的引用指向一个父类对象的。所以一开始的问题就明白了,使用HashMap类的values方法返回的是一个collection对象,我们是无法用子类对象引用ArrayList指向父类对象Collection实例的。之所以会犯这样的错误是因为我对向下转型的理解不够深刻,之前我们提到的向下转型是在向上转型的前提之下,也就是说不管向上转型向下转型,我们堆中的对象也就是我们的运行类型是不变的,变化的是引用也就是编译类型。
结论:所以父类对象强转为子类对象的前提是父类对象要先引用这个子类对象
解决方案:
1,通过HashMap的keySet方法返回keySet集合,再用Map的get()方法获得value
public List<T> list(){
List<T> list = new ArrayList<>();
Set<String> keySet = map.keySet();
for (String key : keySet) {
list.add(map.get(key));
}
return list;
}
2,通过HashMap的values()方法获得values集合,再使用迭代器或者foreach
public List<T> list(){
List<T> list = new ArrayList<>();
Collection<T> values = map.values();
for (T t: values) {
list.add(t);
}
return list;
}
3,通过entrySet方法返回entrySet集合再使用迭代器或者foreach,再调用entry类型的getValues和getKey
public List<T> list(){
List<T> list = new ArrayList<>();
Set<Map.Entry<String, T>> entries = map.entrySet();
Iterator<Map.Entry<String, T>> iterator = entries.iterator();
while (iterator.hasNext()) {
Map.Entry<String, T> next = iterator.next();
list.add(next.getValue());
}
return list;
}
4这种也是最简单的一种,直接使用ArrayList的有参构造器public ArrayList(Collection<? extends E> var1)
public List<T> list(){
ArrayList<T> ts = new ArrayList<>(map.values());
return ts;
}