在写java作业的时候遇到了以下问题:
自定义了一个worker泛型的ArrayList集合,添加元素后试图直接使用remove(Object o)方法传入一个worker类型的形参删除元素,结果删除失败。
试图百度该问题,结果搜到的结果大多不是直接告诉我用remove(int index)的那个重载就是告诉我它不行,它只适用于原始类型
翻了数页无果一气之下挖到底层才解决问题,希望该博客能帮到和我一样对此产生疑问但找不到答案的人
我们知道ArrayList集合给出了一个删除第一次出现的指定对象的删除元素方法remove(Object o)
但在大多数情况下,当arrayList包含用户自定义的数据类型的项时,此方法难以给出正确的结果。 网上的解释为:它只适用于原始数据类型。此时用户希望根据对象字段的值删除项,并且无法通过Remove函数进行比较。
针对以上情况,如果用户仍需要使用该remove(Object o)
方法而不是另一个指定下标的remove(int index)
方法重载,上述问题的解决方法为:在指定的用户自定义类中重载equals()
方法。
e.g.
public boolean equals(Object o) {
worker w = (worker)o;//在equals函数中强转类型
if(w.name == this.name && w.no == this.no && w.salary == this.salary)return true;
else return false;
}
为什么不直接使用worker
类型的形参传入而用Object
类型的形参,以及为何要重载equals()
方法,是因为remove(Object o)
的底层实现如下:
底层实现参考文章:ArrayList的底层实现原理 - maoyl - 博客园 (cnblogs.com)
// 移除此列表中首次出现的指定元素(如果存在)。这是应为ArrayList中允许存放重复的元素。
public boolean remove(Object o) {
// 由于ArrayList中允许存放null,因此下面通过两种情况来分别处理。
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
// 类似remove(int index),移除列表中指定位置上的元素。
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) { //注意此时的判断条件
fastRemove(index);
return true;
}
}
return false;
}
}
我们可以发现,在remove(Object o)
方法中对于寻找要删除的元素时使用的判断条件为if (o.equals(elementData[index]))
所以我们可以通过重载equals()
方法来自定义判断对象相等的条件
而在equals()
方法中需要进行强制类型转换的原因是elementData
的底层声明类型为Object
:
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer.
*/
private transient Object[] elementData;
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
由于不能保证elementData[index]
在传入equals
方法时一定为用户声明的自定义类型,所以最保险的方法就是在用户重载的equals()
方法中进行一次强制类型转换。
以下为实例代码:
import java.util.*;
public class WorkerTest {
public static void main(String[] args) {
ArrayList a1 = new ArrayList();
a1.add(new worker("1001","张三",3000));
a1.add(new worker("1003","李四",3500));
a1.add(new worker("1004","王五",2500));
print(a1);
if (a1.remove(new worker("1003","李四",3500)))System.out.println("成功删除员工信息!");
else System.out.println("不存在该员工信息,删除失败!");
print(a1);
}
public static void print(ArrayList a) {//遍历输出
Iterator itr = a.iterator();
while(itr.hasNext())
{
worker e = (worker) itr.next();
System.out.println(e.toString());
}
}
}
class worker{
private String no;//工号
private String name;//姓名
private double salary;//工资
public worker(String no, String name, double salary) {
this.no = no;
this.name = name;
this.salary = salary;
}
public String toString() {
String s = this.no + "号工人" + this.name + ",每月工资为" + this.salary + "元";
return s;
}
public boolean equals(worker w) {//此时没有进行强制类型转换
if(w.name == this.name && w.no == this.no && w.salary == this.salary)return true;
else return false;
}
//私有成员的get和set方法略
}
以下为重写了equals()
方法但没有进行强制类型转换的运行结果:
在以上样例的equals()
方法中添加强制类型转换:
public boolean equals(Object o) {
worker w = (worker)o;//在equals函数中强转类型
if(w.name == this.name && w.no == this.no && w.salary == this.salary)return true;
else return false;
}
以下为重写了equals()
方法且进行强制类型转换的运行结果: