List子接口
- 特点:有序,有下标,元素可重复。
- 方法:
- add(int index, E element) //将指定的元素插入此列表中的指定位置(可选操作)。
- indexOf(Object o) //返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
- lastIndexOf([Object o) //返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
- listIterator() //返回列表中的列表迭代器(按适当的顺序)。
- addAll(int index, Collection<? extends E> c) //将指定集合中的所有元素插入到此列表中的指定位置(可选操作)。
- get(int index) //返回此列表中指定位置的元素。
- subList(int fromIndex, int toIndex) //返回此列表中指定的
fromIndex
(含)和toIndex
之间的视图。
四种不同的遍历方法
package com.list.demo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class Demo1 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("小米");
list.add("苹果");
list.add("华为");
System.out.println(list.indexOf("苹果")); // 获取元素的索引
System.out.println("-------------1.for循环遍历-----------------");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("-------------2.for增强循环-----------------");
for (Object item : list
) {
System.out.println(item);
}
System.out.println("-------------3.iterator迭代器-----------------");
Iterator iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("-------------4.listIterator迭代器-----------------");
/*
*void add(E e)将指定的元素插入列表(可选操作)。
boolean hasNext() 返回 true如果遍历正向列表,列表迭代器有多个元素。
boolean hasPrevious() 返回 true如果遍历反向列表,列表迭代器有多个元素。
E next() 返回列表中的下一个元素,并且前进光标位置。
int nextIndex() 返回随后调用 next()返回的元素的索引。
E previous() 返回列表中的上一个元素,并向后移动光标位置。
int previousIndex() 返回由后续调用 previous()返回的元素的索引。
void remove() 从列表中删除由 next()或 previous()返回的最后一个元素(可选操作)。
void set(E e) 用 指定的元素替换由 next()或 previous()返回的最后一个元素(可选操作)。
*
* */
ListIterator listIterator = list.listIterator();
/*
* 1.从前往后遍历
* */
System.out.println("----------从前往后遍历-----------");
while (listIterator.hasNext()) {
System.out.println(listIterator.next());
}
/*
* 2.从后往前遍历
* */
System.out.println("----------从后往前遍历-----------");
while (listIterator.hasPrevious()){
System.out.println(listIterator.previous());
}
}
}
方法解析
-
subList(int fromIndex, int toIndex) //返回此列表中指定的
fromIndex
(含)和toIndex
之间的视图。- 该方法会切割了list,其中切割的元素会包含起始位,但不会结束位
-
add(int index, E element) //将指定的元素插入此列表中的指定位置(可选操作)。
- 当使用索引时可以在索引位置处插入该元素,其他元素依次后移
-
remove(int index),如果在加入的数据为int类型时,会自动装箱,当我们用remove方法时不可以直接写数字,直接写数字就会调用索引的重载方法。
package com.list.demo;
import java.util.ArrayList;
import java.util.List;
public class Demo2 {
public static void main(String[] args) {
List list = new ArrayList();
// 此时我们加入的数据为数字,会自动装箱-->Integer
list.add(10);
list.add(20);
list.add(30);
list.add(40);
list.add(50);
// list.remove(10); //IndexOutOfBoundsException
list.remove(0); //通过下标索引来删除 10
list.remove(new Integer(50)); // 通过元素来删除 50
System.out.println(list);
list.add(10);
list.add(20);
List list1 = list.subList(2, 4);// 40 10
System.out.println(list1); //[40, 10]
}
}
List的实现类
-
ArrayList【重点】
- 数组结构实现,查询快,增删慢
- JDK1.2加入,运行效率高(快),线程不安全
-
Vector【了解】:
- 数组结构实现,查询快,增删慢
- JDK1.0,运行效率低(慢),线程安全
-
LinkedList:
-
链表结构实现,增删快,查询慢
-
链表与数组
-
链表:
-
数组:
-
ArrayList类【重点】
ArrayList【重点】
- 数组结构实现,查询快,增删慢
- JDK1.2加入,运行效率高(快),线程不安全
package com.list.demo;
import com.collection.demo.Student;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<Object> arrayList = new ArrayList<>();
Student s1 = new Student("张三", 18, 55);
Student s2 = new Student("王五", 58, 75);
Student s3 = new Student("赵六", 19, 45);
Student s4 = new Student("李四", 28, 65);
// 增加
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
arrayList.add(s4);
// 查找
// 1.for
System.out.println("-------------1.for--------------");
for (int i = 0; i < arrayList.size(); i++) {
System.out.println(arrayList.get(i));
}
// 2.for增强
System.out.println("-------------2.for增强--------------");
for (Object item : arrayList
) {
Student item1 = (Student) item;
System.out.println(item1);
}
// 3.迭代器
System.out.println("-------------3.迭代器--------------");
Iterator<Object> iterator = arrayList.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// 4.列表迭代器
System.out.println("-------------4.列表迭代器--------------");
ListIterator<Object> listIterator = arrayList.listIterator();
while (listIterator.hasNext()) {
System.out.println(listIterator.next());
}
System.out.println("-------------4.列表迭代器逆序--------------");
while (listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
// 删除
arrayList.remove(0); // 通过索引删除
System.out.println("删除后个数:"+arrayList.size());
System.out.println(arrayList);
System.out.println("==============================");
arrayList.remove(new Student("李四", 28, 65));
// 并没有删除成功,实际上这里调用了对象的equals()方法,如果想要通过对象的形式删除,要重写equals()方法
System.out.println("删除后个数:"+arrayList.size());
System.out.println(arrayList);
System.out.println("==============================");
// 判断
System.out.println(arrayList.contains(new Student("赵六", 19, 45)));
System.out.println(arrayList.isEmpty());
// 查找
System.out.println(arrayList.indexOf(new Student("赵六", 19, 45)));
}
}
package com.collection.demo;
import java.util.Objects;
public class Student {
private String name;
private int age;
private int weight;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", weight=" + weight +
'}';
}
// 重写equals
@Override
public boolean equals(Object o) {
// 1.如果对象为空
if (o == null) {
return false;
} else {
// 如果是其实例对象,且所有信息都相同,我们就认为其是相同对象
if (o instanceof Student && this.name.equals(((Student) o).name)
&& this.age == ((Student) o).age && this.weight == ((Student) o).weight) {
return true;
} else {
return false;
}
}
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setWeight(int weight) {
this.weight = weight;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public int getWeight() {
return weight;
}
public Student(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
}
源码分析
private static final int DEFAULT_CAPACITY = 10; // ArrayList类中定义的容器默认容量
- 注意:当ArraysList被创建,但还没有添加元素时,此时容量为0
transient Object[] elementData; // non-private to simplify nested class access
// 真实存放对象的数组
private int size; // 元素个数 默认为0
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
- 当我们往一个新建的ArrayList中添加元素时,容器的容量会变成默认值,10。
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {// 此时minCapacity为1
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//elementData和DEFAULTCAPACITY_EMPTY_ELEMENTDATA此时都是空数组所以成立
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
// DEFAULT_CAPACITY是10 所以现在minCapacity变成了10
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
// minCapacity=10 ,elementData.length=0 成立
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 好几个亿
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {// minCapacity=10
// overflow-conscious code
int oldCapacity = elementData.length; //0
int newCapacity = oldCapacity + (oldCapacity >> 1);0
if (newCapacity - minCapacity < 0)//0-10x小于10
newCapacity = minCapacity; // newCapacity = 10 新数组的容量变为10
if (newCapacity - MAX_ARRAY_SIZE > 0)
// 不成立,MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 好几个亿
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
//newCapacity=10,elementData为空,执行后,elementData变成长度为10的数组
}
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass()); //返回一个长度为10的数组
}
- 当初始数组装满时,添加第11个元素,数组会自动扩容
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!! //此时size + 1=11
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {//minCapacity=11
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//添加第一个元素后就不再执行
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);//minCapacity=11
}
private void ensureExplicitCapacity(int minCapacity) {//minCapacity=11
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0) // 11-10>0
grow(minCapacity);//minCapacity=11
}
private void grow(int minCapacity) {//minCapacity=11
// overflow-conscious code
int oldCapacity = elementData.length; //10
int newCapacity = oldCapacity + (oldCapacity >> 1);
//10 + 10/2 = 15 相当于变成原来的1.5倍
if (newCapacity - minCapacity < 0)//15-11>0
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)//MAX_ARRAY_SIZE=好几个亿,不成立
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);//newCapacity=15
}
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass()); // 返回扩容后的数组
}
- 结论:
- ArrayList第一次添加元素时,容器的容量会从 0 ------> 10
- 当容器装满时,再往里边添加元素时,每次会扩容1.5倍
Vector类【了解】
Vector【了解】:
- 数组结构实现,查询快,增删慢
- JDK1.0,运行效率低(慢),线程安全
package com.list.demo;
import java.util.Enumeration;
import java.util.Vector;
public class Demo3 {
public static void main(String[] args) {
Vector<Object> vector = new Vector<>();
vector.add("香蕉");
vector.add("菠萝");
vector.add("哈密瓜");
// 删除
// vector.remove("香蕉");
// vector.clear();
// vector 枚举器
Enumeration<Object> elements = vector.elements();
while (elements.hasMoreElements()) {
String o = (String) elements.nextElement();
System.out.println(o);
}
// 判断
System.out.println(vector.contains("香蕉"));
System.out.println(vector.isEmpty());
// 其他方法
System.out.println(vector.elementAt(0));
System.out.println(vector.firstElement());
System.out.println(vector.listIterator());
}
}
- 其他方法请查看API文档
LinkedList类【增删常用】
LinkedList:
- 链表结构实现,增删快,查询慢
- 双向链表
package com.list.demo;
import com.collection.demo.Student;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<Object> list = new LinkedList<>();
Student s1 = new Student("张三", 18, 55);
Student s2 = new Student("王五", 58, 75);
Student s3 = new Student("赵六", 19, 45);
Student s4 = new Student("李四", 28, 65);
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
// 删除
list.remove(s1);
// list.clear();
// 遍历
// 1.for
System.out.println("------------1.for----------------");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// 2.增强for
System.out.println("------------2.增强for----------------");
for (Object item : list
) {
System.out.println(item);
}
// 3.迭代器
System.out.println("------------3.迭代器----------------");
Iterator<Object> iterator = list.iterator();
while (iterator.hasNext()) {
Student s = (Student) iterator.next();
System.out.println(s);
}
// 4.列表迭代器
System.out.println("------------4.列表迭代器----------------");
ListIterator<Object> listIterator = list.listIterator();
while (listIterator.hasNext()) {
Student s = (Student)listIterator.next();
System.out.println(s);
}
System.out.println("========================");
// 判断
System.out.println(list.isEmpty());
list.contains(new Student("张三", 18, 55));
// 其他方法
System.out.println(list.indexOf(s2));
}
}
源码分析
- 链表初始大小
transient int size = 0;
- 头结点
transient Node<E> first;
- 尾结点
transient Node<E> last;
- 构造方法
public LinkedList() {
}
- add方法
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last; // null
final Node<E> newNode = new Node<>(l, e, null);
last = newNode; // last --->newNode
if (l == null)
first = newNode; // first --> newNode,添加第一个元素时
else
l.next = newNode;
size++; // 链表大小+1
modCount++;
}
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
//prev=null,element=添加对象,next=null
this.item = element;
this.next = next;
this.prev = prev;
}
}
- 添加第二个元素时
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) { // e --> 新增对象
final Node<E> l = last; // 上一个节点 l ---> last
final Node<E> newNode = new Node<>(l, e, null);
last = newNode; // 新增节点赋值为尾结点last ---> newNode
if (l == null)
first = newNode;
else
l.next = newNode;// 上一个节点的,下一个节点赋值为新增节点
size++; // 链表大小加1
modCount++;
}
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element; // 新增对象
this.next = next; // 下一个节点 null
this.prev = prev; // 上一个节点
}
}