前言 Preface
马上大四了,就快准备校招了。我身边的同学都开始投简历了,但是我不是很了解这方便。主要我的室友都是考研的,没有想过就业。所以平时对于这方面的了解也是比较少的。所以,现在就有点慌张了。今天下载了牛客网,先做了几个Java的小练习。发现,自己对于知识点的理解还是比较欠缺的。很多东西理解的不是很透彻,或者就没有深入理解过。所以,特地来记录一下自己的理解。如果遗漏、错误之处,欢迎指出。
题目描述
如果一个list初始化为{5, 3, 1},执行一下代码后,其结果为()?
nums.add(6);
nums.add(0, 4);
nums.remove(1);
选项:
A.[5, 3, 1, 6]
B.[4, 3, 1, 6]
C.[4, 3, 6]
D.[5, 3, 6]
错误的思路:
对于这道题,我一开始的理解是在list的末尾添加一个6,然后在头部0位置插入一个4,再移除元素1.
结果为[4, 5, 3, 6]。但是并没有这个答案,然后我就随便选择了选项C。
但是正确答案是选项B。
正确的思路是:
在list的末尾添加一个6,然后再头部0位置插入一个4(此时为[4, 6, 3, 1, 6]),再移除索引为1的元素(即5)。最后的结果为 [4, 3, 1, 6]。
测试代码
package dragon;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TestCode {
public static void main(String[] args) {
test01();
}
static void test01() {
List<Integer> nums = new ArrayList<>(Arrays.asList(5, 3, 1));
System.out.println("输出原始数据:");
nums.forEach(System.out::println);
nums.add(6);
nums.add(0, 4);
nums.remove(1);
System.out.println("输出修改后的数据:");
nums.forEach(System.out::println);
}
}
注意要点
这里的移除元素操作,我把它当成了是利用对象的引用来移除,但是它是使用的索引来移除的。
这里主要是因为基本类型和包装类型的自动装箱和拆箱机制,虽然初始化的数据为 {5,3, 6}。但是Java的List中只能存放数据的引用,不能存放基本类型数据。所以,list中存放的应该是 new Integer(5), new Ineger(3), new Integer(6)。
所以如果要按照引用来移除数据,必须使用 nums.remove(new Integer(1))。
测试代码
package dragon;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TestCode {
public static void main(String[] args) {
test02();
}
static void test02() {
List<Integer> nums = new ArrayList<>(Arrays.asList(5, 3, 1));
System.out.println("输出原始数据:");
nums.forEach(System.out::println);
nums.add(6);
nums.add(0, 4);
boolean flag = nums.remove(new Integer(1));
System.out.println("移除元素是否成功:" + flag);
System.out.println("输出修改后的数据:");
nums.forEach(System.out::println);
}
}
那么问题来了,list中的 1 和 new Integer(1) 的引用相同吗?
我们使用代码来测试一下:
List<Integer> list = new ArrayList<>(Arrays.asList(1, 100, 1000));
System.out.println("list.get(0) == new Integer(1): " + (list.get(0) == new Integer(1)));
这样似乎是不可以的,但是上面确实移除了元素 1。这些东西还是不能考猜测,得去看看到底是怎么回事?
找到 ArrayList 中的这个根据对象来移除元素的方法:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
然后它判断元素相等的方法是根据元素的 equals 方法,所以也可以知道为什么先做null判断了,否则会发生 NullPointException。那我们再转去看 Integer 的 equals 方法,该方法如下:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
它就是根据 Integer 所代表的值来做判断的,所以这个移除是没有问题。虽然 list.get(0) 和 new Integer(0) 是不同的对象,但是它们的值是相等的,所以可以使用 remove 方法来移除 list 中的元素。
所以,它不是在所有的情况下都能成立的,例如如下代码:
package dragon;
public class Cat {
private String name;
private int age;
private String sex;
public Cat(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
//省略 getter 和 setter
}
static void test03() {
List<Cat> catList = new ArrayList<>();
catList.add(new Cat("tomcat", 1, "famale"));
catList.add(new Cat("kittycat", 2, "male"));
catList.add(new Cat("buckcat", 1, "famale"));
boolean flag = catList.remove(new Cat("kittycat", 2, "male"));
System.out.println("移除是否成功:" + flag);
}
因为我这里没有重写equals方法,所以它调用的其实是Cat的父类的方法,即Object的equals,而Object的equals方法是什么样的呢?
public boolean equals(Object obj) {
return (this == obj);
}
这是直接比较两个对象是否同一个对象了,所以是肯定不相等。那就没有办法了吗?也不是,我们可以重写 Cat 类的equals方法和hashCode方法,那样就可以了。如果感兴趣的话可以尝试一下。