你好!在前面的课程中,我们深入研究了数组,回顾了使用数组的常见示例。
一般而言,数组超级方便。你已经知道,数组可以做很多事情。:)不过,数组的缺点也不少。
输出:
大小受限。在创建数组时,你便需要知道数组需要包含多少元素。如果你低估了数量,则空间就不够了。如果高估了数量,数组一半是空的,这也不太好。毕竟,你分配的内存仍然比需要的多。
数组没有添加元素的方法。你必须始终明确指出要添加元素的位置的下标。如果你不小心为某个位置指定了下标,而该位置被你需要的某个值所占据,那么该值将被覆盖。
没有删除项目的方法。值只能被“归零”。
public class Cat {
private String name;
public Cat(String name) {
this.name = name;
}
public static void main(String[] args) {
Cat[] cats = new Cat[3];
cats[0] = new Cat("托马斯");
cats[1] = new Cat("比蒙斯");
cats[2] = new Cat("莱昂内尔·梅西");
cats[1] = null;
System.out.println(Arrays.toString(cats));
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
Output:
[Cat{name='托马斯'}, null, Cat{name='莱昂内尔·梅西'}]
非常幸运,Java 的创建者对数组的优缺点了如指掌,因此创建了一个非常有趣的数据结构 ArrayList。
简而言之,ArrayList 是一个提高了效率且包含很多新功能的数组。
创建起来非常轻松:
ArrayList<Cat> cats = new ArrayList<Cat>();
现在我们创建了一个存储 Cat 对象的列表。注意,我们并未指定 ArrayList 的大小,但它会自动扩展。
这怎么可能?实际上非常简单。这可能让你非常惊讶,但 ArrayList 就是在普通数组之上构建的 :)是的,它包含一个数组,即存储元素的地方。
但是 ArrayList 采用特殊的方式来处理此数组: - 当填充内部数组时,ArrayList 会在内部创建一个新数组。新数组的大小是旧数组的大小乘以 1.5 再加 1。
- 旧数组中的所有数据都将复制到新数组中
- 旧数组被垃圾回收器清理。
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<Cat>();
cats.add(new Cat("比蒙斯"));
}
将新项目添加到列表末尾。现在没有溢出数组的风险,因而这个方法是完全安全的。
顺便说一下,ArrayList 不仅可以通过其下标来查找对象,而且可以通过对象查找下标:它可以使用一个引用来查找 ArrayList 中对象的下标!这正是 indexOf() 方法的用途:
我们传递所需对象的引用,而 indexOf() 返回其下标:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("托马斯");
Cat behemoth = new Cat("比蒙斯");
Cat lionel = new Cat("莱昂内尔·梅西");
Cat fluffy = new Cat ("福乐斐");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
int thomasIndex = cats.indexOf(thomas);
System.out.println(thomasIndex);
}
输出:
0
这就对了。托马斯对象确实存储在元素 0 中。
数组并非只有缺点。毫无疑问,数组还有很多优点。其中一个优点就是按下标搜索元素的功能。这是因为指向一个下标也就是指向一个特定的内存地址,因此以这种方式搜索数组就非常快。ArrayList 也知道如何实现这一点:get() 方法实现下面的代码:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<<>();
Cat thomas = new Cat("托马斯");
Cat behemoth = new Cat("比蒙斯");
Cat lionel = new Cat("莱昂内尔·梅西");
Cat fluffy = new Cat ("福乐斐");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
Cat secondCat = cats.get(1);
System.out.println(secondCat);
}
输出:
Cat{name='比蒙斯'}
此外,你可以轻松查找 ArrayList 是否包含特定的对象。这是通过使用 contains() 方法实现的:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("托马斯");
Cat behemoth = new Cat("比蒙斯");
Cat lionel = new Cat("莱昂内尔·梅西");
Cat fluffy = new Cat ("福乐斐");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
cats.remove(fluffy);
System.out.println(cats.contains(fluffy));
}
该方法会检查 ArrayList 的内部数组是否包含元素,并返回布尔值(true 或 false)。

false
另一个有关插入的重要信息。
ArrayList 支持你使用下标不仅在数组末端而且在任何地方插入元素。
可以使用两个方法实现此功能:- add(int index, Cat element)
- set(int index, Cat element)
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("托马斯");
Cat behemoth = new Cat("比蒙斯");
Cat lionel = new Cat("莱昂内尔·梅西");
Cat fluffy = new Cat ("福乐斐");
cats.add(thomas);
cats.add(比蒙斯);
System.out.println(cats.toString());
cats.set(0, lionel);// 我们现在获得包含 2 个猫的列表。使用 set 添加第 3 个猫
System.out.println(cats.toString());
}
输出:
[[Cat{name='托马斯'}, Cat{name='比蒙斯'}]
[Cat{name='莱昂内尔·梅西'}, Cat{name='比蒙斯'}]
我们有一个包含 2 个猫的列表。然后,我们使用 set() 方法插入了另一个猫作为元素 0。因此,旧元素已被新元素替代。
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("托马斯");
Cat behemoth = new Cat("比蒙斯");
Cat lionel = new Cat("莱昂内尔·梅西");
Cat fluffy = new Cat ("福乐斐");
cats.add(thomas);
cats.add(比蒙斯);
System.out.println(cats.toString());
cats.add(0, lionel);// 我们现在获得包含 2 个猫的列表。使用 add 添加第三个猫
System.out.println(cats.toString());
}
在这里,add() 的工作方式有些不同。它会将所有元素移到右侧,然后将新元素作为元素 0 写入。
输出:
[Cat{name='托马斯'}, Cat{name='比蒙斯'}]
[Cat{name='莱昂内尔·梅西'}, Cat{name='托马斯'}, Cat{name='比蒙斯'}]
要完全清除列表,请使用 clear() 方法:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("托马斯");
Cat behemoth = new Cat("比蒙斯");
Cat lionel = new Cat("莱昂内尔·梅西");
Cat fluffy = new Cat ("福乐斐");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
cats.clear();
System.out.println(cats.toString());
}
输出:
[]
一切内容都从列表中移除。
顺便指出,与数组不同,ArrayList 会重写 toString() 方法并且已经将列表适当地显示为字符串。对于普通数组,我们必须使用 Arrays 类实现这一点。
前面我提到了 Arrays:Java 支持你轻松在数组和 ArrayList 之间切换,即从一个转换为另一个。Arrays 类体用了 Arrays.asList() 方法实现此功能。我们使用该方法来获取数组形式的内容,并将这些内容传递给 ArrayList 构造方法:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("托马斯");
Cat behemoth = new Cat("比蒙斯");
Cat lionel = new Cat("莱昂内尔·梅西");
Cat fluffy = new Cat ("福乐斐");
Cat[] catsArray = {thomas, behemoth, lionel, fluffy};
ArrayList<Cat> catsList = new ArrayList<>(Arrays.asList(catsArray));
System.out.println(catsList);
}
输出:
[Cat{name='托马斯'}, Cat{name='比蒙斯'}, Cat{name='莱昂内尔·梅西'},
Cat{name='福乐斐'}]
你还可以按相反方向执行:从 ArrayList 对象获取数组。我们使用 toArray() 方法执行此操作:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("托马斯");
Cat behemoth = new Cat("比蒙斯");
Cat lionel = new Cat("莱昂内尔·梅西");
Cat fluffy = new Cat ("福乐斐");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
Cat[] catsArray = cats.toArray(new Cat[0]);
System.out.println(Arrays.toString(catsArray));
}
注意:我们已将空数组传递给 toArray() 方法。这不是错误。在 ArrayList 类内部,该方法的实现方式是传递一个空数组来提高其性能。只需记住这一点,将来会用到(当然,你可以传递某个特定大小的数组;这也是可以的)。
那现在看看大小。列表的当前大小可以使用 size() 方法找到:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>();
Cat thomas = new Cat("托马斯");
Cat behemoth = new Cat("比蒙斯");
Cat lionel = new Cat("莱昂内尔·梅西");
Cat fluffy = new Cat ("福乐斐");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
System.out.println(cats.size());
}
请务必了解的一点是,与数组的 length 属性不同,ArrayList.size() 方法返回元素的实际数量,而不是原始容量。毕竟,我们在创建 ArrayList 时并未指定大小。不过,你可以指定大小 - ArrayList 提供了合适的构造方法。
但就添加新元素而言,这并没有改变其行为:
public static void main(String[] args) {
ArrayList<Cat> cats = new ArrayList<>(2);// 创建基于初始容量 2 的 ArrayList
Cat thomas = new Cat("托马斯");
Cat behemoth = new Cat("比蒙斯");
Cat lionel = new Cat("莱昂内尔·梅西");
Cat fluffy = new Cat ("福乐斐");
cats.add(thomas);
cats.add(behemoth);
cats.add(lionel);
cats.add(fluffy);
System.out.println(cats.size());
}
控制台输出:
4
我们创建了一个含 2 个元素的列表,但可以在需要时静默扩展。
另一个考虑是,如果我们最初创建一个非常小的列表,就不得不更频繁地扩展,而这会使用部分资源。
在本节课中,我们几乎没有讲述从 ArrayList 中移除元素的过程,但并不意味着我们将其忘在脑后。我们将这个主题放在单独的课程中进行介绍,稍后会看到 :)更多阅读内容: |
---|
GO TO FULL VERSION