Java中如何将仅含B类元素的List<A>安全向下转型为List<B>
解决方案
可修改父类Zoo代码的最优方案
核心思路是将父类Zoo改造为泛型类,从编译层面限定存储的元素类型,完全避免遍历强转开销,同时保留继承复用的逻辑。
改造后代码如下:
public static class Animal { public void feed() {} } public static class Cat extends Animal { } // 泛型参数T的上界限定为Animal,保证父类原有方法逻辑可用 public static class Zoo<T extends Animal> { public List<T> m_animals; public Zoo() { m_animals = new ArrayList<>(); } public void feedAnimals() { for(T animal : m_animals) animal.feed(); } } // 子类继承时直接指定泛型参数为Cat public static class CatZoo extends Zoo<Cat> { public void addCat(Cat cat) { m_animals.add(cat); } List<Cat> getCats() { // 直接返回列表即可,无任何转换开销 return m_animals; // 若需避免外部修改内部列表,可返回不可变视图: // return Collections.unmodifiableList(m_animals); } }
该方案优势:
- 100%复用父类原有逻辑,无需修改feedAnimals等方法
- 编译期就保证CatZoo的存储列表只能存入Cat类型,无类型安全风险
- getCats方法时间复杂度为O(1),没有遍历、拷贝、强转的额外开销
- 完全符合需求:CatZoo的使用者只能操作Cat类型,不会接触到Animal类型的操作入口
无法修改父类Zoo代码的兼容方案
如果受历史代码限制不能修改父类定义,由于你已经100%确认列表中仅存在Cat元素,可以通过泛型擦除的特性直接做类型转换,不需要遍历:
public static class CatZoo extends Zoo { public void addCat(Cat cat) { m_animals.add(cat); } @SuppressWarnings("unchecked") // 抑制编译警告,前提是严格保证类型安全 List<Cat> getCats() { // 两次通配符转换跳过编译类型检查 return (List<Cat>)(List<?>) m_animals; // 同样可返回不可变视图避免内部列表被修改: // return Collections.unmodifiableList((List<Cat>)(List<?>) m_animals); } }
注意事项:
- 必须严格控制所有往m_animals中添加元素的入口,保证只能存入Cat类型,否则后续访问列表元素时会抛出
ClassCastException - 该方案时间复杂度同样为O(1),效率和泛型方案一致
内容的提问来源于stack exchange,提问作者A.Hristov
相关产品推荐
相关产品推荐

