Java集合框架01:Collection集合之List
什么是集合
用来存放对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能
任何放入集合的对象,都会转换为Object类型,因此集合可以放置任何对象
集合和数组的区别:
- 数组长度固定,集合长度不固定
- 数组可以存储基本类型和引用类型,集合只能存储引用类型
Collection体系结构
Collection父接口
代表一组任意类型的对象集合
在开发过程中,很少会直接使用Collection接口,因为Collection接口只是一个存储数据的标准,并不能区分存储类型
add()、remove()、size()、toArray()、contains()、iterator()、clone()方法
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
public class Hello{
public static void main(String[] args) {
//Collection是接口无法实例化,但可以声明引用变量,不常用
Collection collection = new ArrayList();
//add()方法添加元素,如果元素是对象,那只是添加了其引用地址
collection.add("java");
collection.add("python");
collection.add("c++");
//因为集合只能存储引用类型,所以此处默认执行了自动装箱的操作
collection.add(1);
//remove()方法删除元素
collection.remove("c++");
//size()方法查看元素个数
System.out.println(collection.size());
//直接打印集合对象默认调用toString()方法
System.out.println(collection);
//toArray()方法将集合转换成数组
System.out.println(Arrays.toString(collection.toArray()));
//contains()方法判断元素是否存在
System.out.println(collection.contains("c++"));
//两种遍历集合的方法
//1.增强for循环(Collection接口类型没有下标,不能用普通for循环)
for (Object i : collection){ //集合元素都是Object类型
System.out.println(i);
}
//2.iterator()迭代器方法,声明一个Iterator接口类型的引用变量
Iterator it = collection.iterator();
//迭代器对象的hasNext()方法先判断集合还有没有元素
while (it.hasNext()){
//next()方法取出元素
System.out.println(it.next());
//此时如果需要删除元素,只能使用迭代器对象的remove()方法,并且必须要调用过next()方法
// //it.remove();
}
}
}
拓展:正确遍历集合的同时删除元素
import java.util.ArrayList;
import java.util.Iterator;
public class Hello{
public static void main(String[] args) {
ArrayList list = new ArrayList();
//创建一个集合
for (int i = 0; i < 10; i++) { //[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list.add(i);
}
//clone()方法可以复制集合,复制后的结果是Object类型,需要强制转换(浅拷贝,和Object类相比不用实现Cloneable接口)
ArrayList list1 = (ArrayList) list.clone();
ArrayList list2 = (ArrayList) list.clone();
//1.直接for循环遍历删除元素会出错,因为删除一个元素后,集合长度发生了改变(数组长度是不变的)
for (int i = 8; i < list.size(); i++) { //目的是删除8和9,但实际在删除8以后,集合长度缩短了,因此9会被漏掉
list.remove(i);
}
System.out.println(list); //[0, 1, 2, 3, 4, 5, 6, 7, 9]
//2.在删除元素以后,手动将i减1,和数组的长度保持一致,就可以正确删除
for (int i = 8; i < list1.size(); i++) {
list1.remove(i);
i--;
}
System.out.println(list1); //[0, 1, 2, 3, 4, 5, 6, 7]
//3.推荐使用Iterator()迭代器删除,不会受集合长度变化的影响
Iterator it = list2.iterator();
int index = 0;
while (it.hasNext()){
Object next = it.next(); //remove()方法只有在调用了next()方法后才可以使用
if (index >= 8){ //迭代器没有下标,但是按顺序迭代的,所以可以将循环次数作为下标
it.remove();
}
index++;
}
System.out.println(list2); //[0, 1, 2, 3, 4, 5, 6, 7]
}
}
List子接口
有序、有下标、元素可以重复
拥有Collection接口的所有方法,还有自己的方法
ArrayList实现类
存储结构:数组,存储空间连续,查询快,增删慢
运行效率快,线程不安全
add()、subList()、remove()、get()、indexOf()、set()、listIterator()方法
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class Hello{
public static void main(String[] args) {
//List list = new ArrayList();也可以,但不常用
ArrayList list = new ArrayList();
//add()方法可指定位置添加元素,是有序的
list.add("java");
list.add(0, "python");
list.add("c++");
list.add(1);
//subList()方法截取集合的子集
System.out.println(list.subList(1, 3)); //[java, c++],该方法需要变量接收,不会对原集合产生影响
System.out.println(list); //[python, java, c++, 1]
//remove()方法可根据数字下标(int类型)或内容删除元素,直接对原集合操作,若元素本身是数字(Object类型),需要表明类型才能删除
list.remove(0);
list.remove("c++");
list.remove((Object) 1);
System.out.println(list); //[java]
//get()方法根据下标获取元素
System.out.println(list.get(0));
//indexOf()方法根据元素获取下标
System.out.println(list.indexOf("java"));
//set()方法替换指定位置的元素
list.set(0, "Java");
//三种遍历集合的方法
//1.for循环或增强for循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//2.iterator()迭代器方法
Iterator it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//3.listIterator()列表迭代器方法,创建一个ListIterator接口类型引用,可以向前后遍历
ListIterator li = list.listIterator();
while (li.hasNext()){
//nextIndex()方法获取下标,next()方法获取元素
System.out.println(li.nextIndex() + ":" + li.next());
}
while (li.hasPrevious()){
System.out.println(li.previousIndex() + ":" + li.previous());
}
}
}
拓展:ArrayList源码分析
//ArrayList()
//集合默认是容量为10
private static final int DEFAULT_CAPACITY = 10;
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//如果没有添加任何元素,容量为0;添加一个元素之后,容量变成10
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//add()
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
//每次扩容,容量增大1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
LinkedList实现类
存储结构:双向链表,存储空间不连续,增删快,查询慢
方法和ArrayList基本一样,也有自己的方法
removeFirst()、removeLast()方法
import java.util.LinkedList;
public class Hello{
public static void main(String[] args) {
LinkedList list = new LinkedList();
//add()方法可指定位置添加元素,是有序的
list.add("java");
list.add("c++");
list.add("python");
Object first = list.removeFirst(); //removeFirst()方法删除并返回第一个元素
Object last = list.removeLast(); //removeLast()方法删除并返回最后一个元素
System.out.println(first); //java
System.out.println(last); //python
System.out.println(list); //[c++]
}
}
拓展:LinkedList源码分析
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
private static class Node<E> {
//item是实际数据
E item;
//next是下一个节点
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}