Java泛型类型实例检查及LinkedListCollection的frequency方法实现问题
问题背景与代码
我需要实现一个名为frequency的方法,用于统计LinkedListCollection集合中泛型E类型对象的出现次数(不确定集合是否应实现为LinkedList,还是直接调用super()构造器,仅考虑类名LinkedListCollection的意义才选择LinkedList)。该方法参数类型为Object,不可修改(属约定要求)。
我的类代码
public class LinkedListCollection<E> extends AbstractCollection<E> { private int size; private Collection<? extends E > list; /** * @ensures isEmpty(); */ public LinkedListCollection() { list = new LinkedList<>(); size = 0; } /** * @param is the Collection of elements that should be placed in the list * * @requires c != null; * @requires !c.contains(null); * @ensures containsAll(c) && c.containsAll(this); * @ensures size() == c.size(); * * @throws NullPointerException is the param collection is null or contains null */ public LinkedListCollection(Collection<? extends E> c) { if ((c == null) || (c.contains(null))) { throw new NullPointerException(); } list=new LinkedListCollection<>(); size=c.size(); list.addAll(c); }
我实现的frequency方法
public int frequency(Object o) { E newob= (E) o; Iterator it = list.iterator(); int frequency= 0; while(it.hasNext()) { if (it.next().equals(newob)) frequency++; } return frequency; }
我原本想先检查对象是否为E类型实例,但instanceof无法用于泛型类型,因此直接进行了强制转换,但不确定是否正确。现咨询:
frequency方法的正确实现方式是什么?- 上述构造器是否正确?
- Java中如何检查对象是否为泛型类型的实例?(我认为还需重写equals方法)
解答
1. frequency方法的正确实现
你的实现存在两处关键问题:
- 直接强制转换
Object o为E会触发未经检查的转换警告,且完全没必要——equals方法本身支持Object类型参数,直接用原对象比较即可。 - 未处理
o为null的情况,虽然构造器禁止集合存null,但方法参数可能传入null,会导致NullPointerException。
正确实现如下:
public int frequency(Object o) { int count = 0; Iterator<E> iterator = list.iterator(); while (iterator.hasNext()) { E element = iterator.next(); if (o == null ? element == null : o.equals(element)) { count++; } } return count; }
如果使用增强for循环会更简洁:
public int frequency(Object o) { int count = 0; for (E element : list) { if (o == null ? element == null : o.equals(element)) { count++; } } return count; }
2. 构造器的问题修正
你的带参构造器存在严重逻辑错误:
list=new LinkedListCollection<>();会创建嵌套的LinkedListCollection实例,导致后续addAll操作逻辑混乱,应该直接实例化LinkedList。- 手动维护
size字段容易出现不一致,建议直接重写size()方法返回list.size(),不用自己维护。
修正后的构造器代码:
public class LinkedListCollection<E> extends AbstractCollection<E> { private Collection<E> list; /** * @ensures isEmpty(); */ public LinkedListCollection() { list = new LinkedList<>(); } /** * @param c the Collection of elements that should be placed in the list * * @requires c != null; * @requires !c.contains(null); * @ensures containsAll(c) && c.containsAll(this); * @ensures size() == c.size(); * * @throws NullPointerException if the param collection is null or contains null */ public LinkedListCollection(Collection<? extends E> c) { if (c == null || c.contains(null)) { throw new NullPointerException(); } list = new LinkedList<>(c); } @Override public int size() { return list.size(); } // 还需重写AbstractCollection要求的iterator()方法 @Override public Iterator<E> iterator() { return list.iterator(); } }
3. 泛型类型的实例检查与equals重写
Java由于类型擦除,泛型类型在运行时会被擦除为原始类型,因此无法直接用instanceof检查对象是否为E类型实例。有两种可行方案:
- 传入类型令牌:在类的构造器中传入
Class<E>类型参数并保存,后续用clazz.isInstance(o)做检查:
public class LinkedListCollection<E> extends AbstractCollection<E> { private final Class<E> typeToken; private Collection<E> list; public LinkedListCollection(Class<E> typeToken) { this.typeToken = typeToken; list = new LinkedList<>(); } public boolean isInstanceOfE(Object o) { return typeToken.isInstance(o); } }
- 利用集合已有元素推断:如果集合非空,可以通过第一个元素的类型判断,但集合为空时失效,且可靠性较低,不推荐。
关于equals重写:
- 若只是统计集合元素的出现次数,只需保证元素类型
E正确实现了equals方法即可; - 若需要自定义
LinkedListCollection实例之间的相等判断逻辑,才需要重写集合类的equals和hashCode方法。
内容的提问来源于stack exchange,提问作者10969_ shirazu_
相关产品推荐
相关产品推荐

