java集合之ArrayList
ArrayList<E>类:位于java.util包下,是List集合中的一种。
特点:有序,可重复,实现不同步,底层数据结构是数组,查询快增删慢,允许存储null。每个 ArrayList 实例都有一个容量。该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向 ArrayList 中不断添加元素,其容量也自动增长。在添加大量元素前,应用程序可以使用 ensureCapacity 操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量(增长量为原来长度的50%)
常用构造:
ArrayList() : 空参构造,默认容量是10
ArrayList(int capacity) : 带参构造,指定初始容量。
方法:
1)添加功能
boolean add(E e) : 将指定的元素添加到此列表的尾部。
void add(int index,E e): 将指定的元素插入此列表中的指定位置。
boolean addAll(Collection<? extends E> c):按照指定 collection 的迭代器所返回的元素顺序,将该 collection 中的所有元素添加到此列表的尾部。
boolean addAll(int index, Collection<? extends E> c):从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。
2)判断功能
boolean isEmpty(): 如果此列表中没有元素,则返回 true,注意其内部代码是调用size()方法来判断的
boolean contains(Object o): 如果此列表中包含指定的元素,则返回 true
3)获取功能
int size() : 返回此列表中的元素个数。
E get(int index):返回此列表中指定位置上的元素。
4)删除功能
void clear() :移除此列表中的所有元素。注意:此方法比较暴力,一般不使用。
E remove(int index):移除此列表中指定位置上的元素。返回:从列表中移除的元素
boolean remove(Object o):移除此列表中首次出现的指定元素(如果存在)。如果此列表包含此元素则返回true
5)转换数组功能
Object[] toArray():按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。
6)修改功能
E set(int index,E e) : 用指定的元素替代此列表中指定位置上的元素。返回以前位于该指定位置上的元素
7)迭代器功能
public Iterator<E> iterator() 返回按适当顺序在列表的元素上进行迭代的迭代器
public ListIterator<E> listIterator() 返回此列表元素的列表迭代器(按适当顺序)。
public ListIterator<E> listIterator(int index) 返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
集合的遍历方式:
1)增强for
存储自定义类,使用增强for进行集合的遍历。
package com.list;
public class Student {
private String name;
private int age;
public Student(String name,int age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
package com.list;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class CollectionTest {
public static void main(String[] args) {
//1 创建集合对象
List<Student> stus = new ArrayList<Student>();
//2 创建学生对象
Student stu1 = new Student("zong",23);
Student stu2 = new Student("wen",23);
Student stu3 = new Student("wen",23);
Student stu4 = new Student("wu",23);
Student stu5 = new Student("wen",23);
Student stu6 = new Student("ya",24);
//3 添加学生对象
stus.add(stu1);
stus.add(stu2);
stus.add(stu3);
stus.add(stu4);
stus.add(stu5);
stus.add(stu6);
//遍历方式一: 将学生集合对象转成数组对象
Object[] studes = stus.toArray();
for(int i=0;i<studes.length;i++){
Student stu = (Student)studes[i];
System.out.println(stu);
}
//遍历方式二:利用迭代器遍历集合
ListIterator<Student> itor = stus.listIterator();
while(itor.hasNext()){ //刚开始迭代器指向集合的首部,需要执行next才能获取第一个元素,itor.remove();此方法不能用在next方法之前
Student stu = itor.next();
System.out.println(stu);
}
//逆序遍历,但是前提必须先前序遍历
while(itor.hasPrevious()){
Student stu = itor.previous();
System.out.println(stu);
}
//遍历方式三:普通for循环
for(int i =0;i<stus.size();i++){
Student s = stus.get(i);
System.out.println(stu);
}
//遍历方式四:增强for
for(Student s : stus){
System.out.println(s);
}
}
}
遍历集合时出现的ConcurrentModificationException
:
遍历集合时如果要实现对集合本身的修改(添加新元素、移除指定元素或修改元素),为防止出现并发修改异常:
如果使用迭代器遍历:
产生异常原因:迭代器依赖于集合而存在,在迭代过程中,集合进行了修改,迭代器并不知道集合进行了修改,故而报错。也就是说在迭代器遍历集合元素过程中,集合是不能修改元素的。
解决方案:使用迭代器遍历集合,使用迭代器修改集合(使用迭代器本身提供的功能方法如remove 或者 set、add当然这是list特有的迭代器功能)。
集合修改之添加元素的效果:元素添加在刚才迭代元素的后面。
例如:集合修改之移除
在遍历时如果遇到Student的name="wen"且age=23,则移除此元素。
Iterator<Student> iter = stus.iterator();
while(iter.hasNext()){
Student s = iter.next();
if(s.getName().equals("wen") && s.getAge()==23){
iter.remove();
}
}
System.out.println(stus);
输出结果为:
[Student [name=zong, age=23], Student [name=wu, age=23], Student [name=ya, age=24]]
例:集合修改之添加
同样的在遍历时如果遇到Student的name="wu"且age=23,则添加一个元素。
Student stu7 = new Student("boke",25);
ListIterator<Student> iter = stus.listIterator();
while(iter.hasNext()){
Student s = iter.next();
if(s.getName().equals("wu") && s.getAge()==23){
iter.add(stu7);
}
}
System.out.println(stus);
输出结果:
[Student [name=zong, age=23], Student [name=wen, age=23], Student [name=wen, age=23], Student [name=wu, age=23], Student [name=boke, age=25], Student [name=wen, age=23], Student [name=ya, age=24]]
如果不是采用迭代器方式遍历(普通for):
解决方案:使用集合遍历,使用集合修改。
集合在遍历时添加元素的效果:在集合的末尾添加元素。
例:集合修改之移除
for(int i=0;i<stus.size();i++){
Student s = stus.get(i);
if(s.getName().equals("wen") && s.getAge()==23){
stus.remove(i--); //防止元素漏掉遍历。
}
}
System.out.println(stus);
输出结果为:
[Student [name=zong, age=23], Student [name=wu, age=23], Student [name=ya, age=24]]
例:集合修改之添加
Student stu7 = new Student("boke",25);
for(int i=0;i<stus.size();i++){
Student s = stus.get(i);
if(s.getName().equals("wu") && s.getAge()==23){
stus.add(stu7); //追加在集合尾部
}
}
System.out.println(stus);
输出结果为:
[Student [name=zong, age=23], Student [name=wen, age=23], Student [name=wen, age=23], Student [name=wu, age=23], Student [name=wen, age=23], Student [name=ya, age=24], Student [name=boke, age=25]]
ArrayList实现元素不可重复的存取:
思路一:创建一个新的集合
创建两个集合:一个添加好元素list1和一个空列表list2
循环遍历list1集合,判断list2集合是否包含list1的元素,如果不包含就添加该元素到list2
最后就可以得到不含重复元素的集合list2
List<Student> stus2 = new ArrayList<Student>();
for(Student s : stus){
if(!stus2.contains(s))
stus2.add(s);
}
System.out.println(stus);
输出结果:
[Student [name=zong, age=23], Student [name=wen, age=23], Student [name=wu, age=23], Student [name=ya, age=24]]
思路二:不创建新的集合
借鉴选择排序的思想,去除集合中重复的元素。
for(int i=0;i<stus.size()-1;i++){
for(int j=i+1;j<stus.size();j++){
if(stus.get(i).equals(stus.get(j))){
stus.remove(j--);
}
}
}
System.out.println(stus);
输出结果:
[Student [name=zong, age=23], Student [name=wen, age=23], Student [name=wu, age=23], Student [name=ya, age=24]]
ArrayList源码解析:
1 ArrayList集合为什么可以添加重复的元素??
添加元素的源码:
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
查看源码可知,其底层直接添加,没有做任何判断,返回结果始终为true,表示始终添加成功。
2 ArrayList集合移除一个和指定元素的相等的元素,是移除一个还是把所有相同的全部移除????
通过查看源码可知:其移除第一次查找相等的元素,依赖equals()方法,对于自定义对象,需要重写该方法
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) { //同时也可以看出ArrayList允许存储Null
fastRemove(index);
return true; //移除成功
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true; //一旦查找到就return ,表明移除第一次查找到的元素,而不是全部相等的元素
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1; //需要移动元素的个数
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,numMoved); //调用的是native类型方法
elementData[--size] = null; // 等待垃圾回收器回收
}