前言 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);
	}
}

牛客网java调试_牛客网java调试

注意要点

这里的移除元素操作,我把它当成了是利用对象的引用来移除,但是它是使用的索引来移除的。
这里主要是因为基本类型和包装类型的自动装箱和拆箱机制,虽然初始化的数据为 {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);
	}
}

牛客网java调试_List_02

那么问题来了,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)));

牛客网java调试_牛客网java调试_03


这样似乎是不可以的,但是上面确实移除了元素 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);
	}

牛客网java调试_System_04

因为我这里没有重写equals方法,所以它调用的其实是Cat的父类的方法,即Object的equals,而Object的equals方法是什么样的呢?

public boolean equals(Object obj) {
    return (this == obj);
}

这是直接比较两个对象是否同一个对象了,所以是肯定不相等。那就没有办法了吗?也不是,我们可以重写 Cat 类的equals方法和hashCode方法,那样就可以了。如果感兴趣的话可以尝试一下。