Java如何判断List<Animals>中是否包含指定子类实例
实现集合中指定子类实例的判断方案
初始代码与问题复现
首先定义的父类Animals初始代码如下:
public class Animals { private String type; public String getType(){ return this.type; } }
后续创建了Horse、Bear、Dog等多个继承自Animals的子类,定义List<Animals>类型集合存储不同子类实例,需要实现方法判断集合中是否存在指定子类的对象(例如是否存在Bear类实例),尝试多种方案均未得到正确结果:
- 调用
horse.getClass()无法返回有效结果 - 编写如下测试代码:
Horse h = new Horse();
执行System.out.print(h instanceof Bear);语句后返回true,结果不符合预期
- 使用
equals方法判断得到错误结果 - 尝试在每个子类中定义字符串类型属性,通过比对字符串值判断类型,但Java无法正确读取该字符串属性,无法推进。
问题根因说明
h instanceof Bear返回true属于类继承关系编写错误,正常情况下Horse类实例不可能对Bear类的instanceof判断返回true,优先检查子类的继承声明:所有子类必须直接继承Animals,即写法为public class Horse extends Animals,不能出现子类之间互相继承、写错继承目标类的问题。- 自定义字符串属性判断类型失效的原因是父类中
type是私有属性,子类无法直接访问,也没有在构造方法中给type赋值,调用getType()永远返回null,自然无法匹配。 equals方法默认是判断两个对象的引用地址是否相同,和类型判断逻辑无关,没有重写的情况下不可能用来判断对象类型。- 直接调用
getClass()是可行的类型判断方式,之前无法返回有效结果大概率是继承关系错误或者写法不对。
最优实现方案
不需要在类中额外自定义类型标记字段,直接使用JDK原生的Class类做类型判断,无额外维护成本,不会出现人为赋值错误。
第一步:修正类定义
如果不需要自定义type属性做其他业务逻辑,父类可以直接写成空类即可;如果要保留type属性,就添加带参构造供子类传入类型值:
public class Animals { private String type; // 供子类调用传入类型标识 public Animals(String type) { this.type = type; } public String getType() { return type; } } // 子类示例,继承时调用父类构造 public class Horse extends Animals { public Horse() { super("horse"); } } public class Bear extends Animals { public Bear() { super("bear"); } } public class Dog extends Animals { public Dog() { super("dog"); } }
第二步:编写通用判断方法
/** * 检查动物集合中是否存在指定类型的实例 * @param animalList 存储Animals子类实例的集合 * @param targetClz 要查找的目标子类类型,例如Bear.class * @return 存在目标类型实例返回true,否则返回false */ public static boolean hasTargetTypeInstance(List<Animals> animalList, Class<? extends Animals> targetClz) { // 空值快速返回 if (animalList == null || animalList.isEmpty() || targetClz == null) { return false; } for (Animals animal : animalList) { // 精确匹配类型,不包含目标类的子类 if (animal.getClass() == targetClz) { return true; } // 如果需要匹配目标类及其所有子类,把上面的判断替换成下面这行 // if (targetClz.isInstance(animal)) { // return true; // } } return false; }
调用示例
// 判断集合中是否存在Bear类实例 boolean containBear = hasTargetTypeInstance(animalList, Bear.class);
注意事项
- 不要用
instanceof做精确类型判断:instanceof会沿着继承链向上匹配,只要对象是目标类的子类/实现类都会返回true,不适合做精确的类型匹配。 - 不推荐用自定义字符串标记类型:容易出现拼写错误、漏赋值的问题,维护成本高,远不如原生
Class比对可靠。 - 排查类继承关系是第一优先级:出现不符合预期的
instanceof结果,一定是类的继承声明写反或者写错了,先修正这个问题再做后续逻辑。
内容的提问来源于stack exchange,提问作者Todoroki Attack
相关产品推荐
相关产品推荐

