目录
1.常用方法
2.关于遍历
3.关于删除
4.关于删除
5.关于删除
6.关于扩容
7.关于最大容量
8.1.8版本新特性
9.List的其他实现类
ArrayList实现了List接口,内部通过Object类型的数组有序存储数据(可重复),并且能够根据元素数量进行扩容,实现了动态的增加和减少元素.
1.常用方法
add() addAll() |
增加元素 |
remove() removeAll() clear() |
移除元素 |
contains() containsAll() |
是否包含指定元素 |
size() isEmpty() equals() |
元素个数 是否为空 是否为同一个ArrayList |
iterator() toArray() |
创建迭代器 将元素返回指定数组 |
2关于遍历
public class ArrayListDemo2 { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.add(23); list.add(33); list.add(64); list.add(33); list.add(54); list.add(89); // 重写了toString方法,直接打印输出 System.out.println(list); // 通过for循环遍历 for (int i = 0, j = list.size(); i < j; i++) { System.out.println(list.get(i)); } // 通过for each遍历 for (int value : list) { System.out.println(value); } // 通过迭代器遍历 Iterator<Integer> car = list.iterator(); while (car.hasNext()) { int value = car.next(); System.out.println(value); } } }
3.关于删除
public class ArrayListDemo3 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); String str1 = new String("Hello"); String str2 = new String("Hello"); list.add(str1); System.out.println(list.size()); list.remove(str2); System.out.println(list.size()); } }
运行结果:
1
0
虽然str1和str2是两个String对象,但是list中的元素被移除了.实际上remove方法内部是通过equals方法判断是否是同一个元素,我们用下面的代码验证:
public class ArrayListDemo3 { public static void main(String[] args) { ArrayList<Person> list = new ArrayList<>(); Person p1 = new Person("Hello"); Person p2 = new Person("World"); list.add(p1); System.out.println(list.size()); list.remove(p2); System.out.println(list.size()); } } class Person { String name; public Person(String name) { this.name = name; } @Override public boolean equals(Object o) { System.out.println("我被执行了"); return true; } }
运行结果:
1
我被执行了
0
4.关于删除
我们利用一个ArrayList来存储分数,现在希望将60分以下的删除:
public class ArrayListDemo4 { public static void main(String[] args) throws Exception { ArrayList<Integer> list = new ArrayList<>(); list.add(80); list.add(54); list.add(68); list.add(72); list.add(49); list.add(51); list.add(98); list.add(77); list.add(43); list.add(50); for (int i = 0; i < list.size(); i++) { if (list.get(i) < 60) { list.remove(i); } } for (int value : list) { System.out.println(value); } } }
运行结果:
80
68
72
51
98
77
50
为什么51和50没有删掉呢?实际上,ArrayList在每次删除一个元素后,后面的元素会向前移动补位.在上述程序中,当我们删除49后,后面的元素向前补位,下一次循环时索引加1,便跳过了51.解决方法:for循环从ArrayList尾部向前遍历.
for (int i = list.size() - 1; i >= 0; i--) { if (list.get(i) < 60) { list.remove(i); } }
运行结果:
80
68
72
98
77
5.关于删除
在上一节中,我们能不能通过for each和Iterator进行操作呢?
// for each循环 for (int value : list) { if (value < 60) { list.remove(new Integer(value)); } } // 迭代器 Iterator<Integer> car = list.iterator(); while (car.hasNext()) { int value = car.next(); if (value < 60) { list.remove(new Integer(value)); } }
两段代码的运行结果一样:java.util.ConcurrentModificationException.抛出了并发修改异常,所以当for each和iterator对一个ArrayList进行迭代时,需保证这个ArrayList不能改变,因为ArrayList是非线程安全的.但是Iterato提供了一个remove方法,可以对ArrayList中的元素进行删除.即:
Iterator<Integer> car = list.iterator(); while (car.hasNext()) { int value = car.next(); if (value < 60) { car.remove(); } }
运行结果:
80
68
72
98
77
6.关于扩容
每一个ArrayList都有一个容量,即数组Object[] elementData的长度.利用无参构造函数创建一个ArrayList时,会使用默认容量10.当我们向其中不断地增加元素超过容量时,ArrayList会进行扩容.ArrayList的扩容原理:新建一个Object类型的数组,长度为原数组长度*3/2,然后将就数组的值赋给新数组,使elementData指向新数组.通过反射进行验证:
public class ArrayListDemo6 { public static void main(String[] args) throws Exception { ArrayList<Integer> list = new ArrayList<>(); Class c = Class.forName("java.util.ArrayList"); Field f = c.getDeclaredField("elementData"); f.setAccessible(true); Object[] data = null; // 向list中添加50个元素,输出每次ElementData的长度 for (int i = 1; i <= 50; i++) { list.add(i); data = (Object[]) f.get(list); System.out.print(data.length + "\t"); if (i % 10 == 0) { System.out.println(); } } } }
运行结果:
10 10 10 10 10 10 10 10 10 10
15 15 15 15 15 22 22 22 22 22
22 22 33 33 33 33 33 33 33 33
33 33 33 49 49 49 49 49 49 49
49 49 49 49 49 49 49 49 49 73
如果我们已知要存储数据的容量,尽量在创建ArrayList时为其指定容量,避免其多次扩容而降低性能.另外,ArrayList中还为我们提供了两个针对于控制容量的方法:
trimToSize() | 将elementData的长度修整为当前元素个数 |
ensureCapacity() | 设置当前ArrayList容量 |
7.关于最大容量
在ArrayList中,还有一个静态常量MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8,用来限制当前ArrayList的最大容量(理论上可以达到Integer.MAX_VALUE).在每次进行扩容时,会用一个int型数据来存储新的容量:int newCapacity = oldCapacity + (oldCapacity >> 1);当ArrayList中的元素达到MAX_ARRAY_SIZE后再次扩充时,newCapacity经过扩容算法会溢出,导致符号位由0变1,变成负值.ArrayList中的hugeCapacity方法通过判断newCapacity是否发生溢出,关键代码:
private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
所以,当ArrayList达到极限容量时,再次扩容会抛出异常.
8.1.8版本新特性
JDK在SE1.8中新增了stream包,并且在Collection中增加了stream()方法,利用其特性我们可以用来进行过滤以及排序等.
public class ArrayListDemo8 { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); Collections.addAll(list, 95, 34, 67, 89, 23, 79, 66, 12, 98); list.stream().filter(e -> e > 60).sorted((i1, i2) -> i1 - i2).forEach(System.out::println); } }
上述代码执行功能:过滤掉60及以下的分数→排序→打印输出.
运行结果:
66
67
79
89
95
98
9.List的其他实现类
1)Vector
Vector是早期的collection,与ArrayList的区别主要有两点:线程安全,扩容方式*2.
2)LinkedList
双向循环链表,内部元素不是通过数组存储的.而是把每一个元素封装Node<E>,每一个Node有三个属性:
E item; | 元素本身 |
Node<E> next; | 指向后一个Node |
Node<E> prev; | 指向前一个Node |
而LinkedList本身只包含两个Node类型的属性first和last,通过Node使元素形成链表,并且是双向的,实现逻辑上的地址连续.在进行插入和删除功能时,性能要优于ArrayList.
3)Stack
对象堆栈.遵循LIFO(Last In First Out)原则,常用方法:
empty() | 测试堆栈是否为空 |
peek() | 查看堆栈顶部的对象,但不移除 |
pop() | 移除堆栈顶部的对象,并返回该对象 |
push() | 把对象压入堆栈顶部 |
search() | 返回对象在堆栈中的位置,以1为基数 |
相关推荐
Java ArrayList是Java集合框架中的一种动态数组,继承了AbstractList,并实现了List接口。ArrayList位于java.util包中,使用前需要引入它。ArrayList是一个可以动态修改的数组,与普通数组的区别就是它是没有固定...
Java集合框架是Java编程语言中的一个核心组成部分,它为数据存储和操作提供了丰富的类库。在Java中,集合框架主要包括接口(如List、Set、Queue)和实现这些接口的类(如ArrayList、HashSet、LinkedList等)。这个...
`ArrayList`是Java集合框架中的一个动态数组类,它能够存储任意类型的对象,并且在运行时动态调整其大小。这使得`ArrayList`成为处理数量未知的数据集合时的一个非常实用的选择。 #### 二、基本用法与初始化 `...
`<s:set>` 赋值给变量,`<s:sort>` 对集合进行排序,`<s:submit>` 创建提交按钮,`<s:subset>` 输出集合的子集。 T. `<s:tabbedPanel>, <s:table>, <s:text>, <s:textarea>, <s:textfield>`: 创建选项卡面板、表格...
- 泛型类的实例化必须提供实际类型参数,如`MyList<String> list = new MyList<>();` - 对于无参构造的泛型类,可以使用匿名内部类的方式省略尖括号,如`new MyList<String>() {}`。 9. 泛型和静态方法: - 泛型...
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E")); List<String> subset = list.subList(1, 4); // 子集为 ["B", "C", "D"] ``` 3. 集合的交集:Java集合框架没有直接提供计算交集的...
`ArrayList`是Java集合框架中的一个重要组成部分,属于`List`接口的一种实现。它提供了一种动态调整大小的数组,能够有效地存储和操作一系列元素。`ArrayList`的底层实现是基于数组结构,因此它在查询元素时具有较快...
例如,`ArrayList<E>`就是Java集合框架中的一个泛型类,其中`E`是元素类型的占位符。我们创建ArrayList实例时,可以指定`E`的具体类型,如`ArrayList<String>`,这样就确保了列表只能存储字符串,避免了类型转换的...
在使用泛型类时,需要在类名后面添加“<>”并指定具体的类型,例如:`ShowObject<Dog> showDog = new ShowObject<Dog>();` 泛型接口的声明使用“interface 名称 < 泛型列表 >”的格式,例如:`interface Listen<E> ...
Java集合框架提供了多种用于存储和操作数据的接口和实现类。其中最主要的三种类型是`List`、`Set`和`Map`。本文主要针对`List`进行详细的解析,包括其子类`ArrayList`和`LinkedList`的特点与应用场景。 #### List ...
四、泛型与集合框架 1. 泛型集合:使用泛型可以限制集合中存储的元素类型,如`List<String> names = new ArrayList<String>();` 2. 泛型集合的优势:防止了ClassCastException,提高了代码的可读性和安全性。 3. ...
Java集合框架中,ArrayList是一种常见的集合实现类,用于存储和操作对象集合。ArrayList基于动态数组的数据结构,因此它能够提供自动扩容的功能,同时也能够快速地进行随机访问。本篇文档将深入探讨ArrayList的内部...
本课程“【IT十八掌徐培成】Java基础第10天-03.List-集合框架-ArrayList”深入讲解了Java中的ArrayList类,这是集合框架中的一个重要组成部分,特别适用于对元素有序且可变大小的需求。 ArrayList是Java.util包下的...
在Java编程中,List接口是集合框架的重要组成部分,提供了有序存储元素的功能。ArrayList和LinkedList是List接口的两种主要实现,它们各有优缺点,适用于不同的场景。此外,匿名类的概念在Java中用于简化代码结构,...
在Java集合框架中,泛型的应用尤其广泛。集合框架是Java中用于存储和操作对象的核心组件,包括List、Set和Map等接口以及它们的实现类。在未引入泛型之前,集合中的元素都是Object类型,这导致了频繁的强制类型转换,...
- **概念**:Java集合框架是一个用于存储和操作对象集合的API,它提供了多种数据结构以适应不同的场景需求。 - **目的**:简化程序员的工作,提供高效的数据管理方式。 #### 二.`Collection`接口 - **定义**:`...
在探讨 JDK 7.0 中 ArrayList 的底层实现原理之前,首先需要了解 ArrayList 作为 Java 集合框架中 List 接口的动态数组实现类的基本概念。ArrayList 提供了一种存储有序、可重复、允许为 null 的数据结构,并且该...