Collection集合
Collection层次结构中的根接口。Collection表示一组对象,这些对象也称为collection的元素。
import java.util.ArrayList;
import java.util.Collection;
public class Demo1 {
public static void main(String[] args) {
//我有3个学生,请把这个3个学生的信息存储到数组中,并遍历数组,获取得到每一个学生信息。
//学生类中有name(姓名)和age(年龄)两个属性,并重写了toString方法
Student s1=new Student("张三",15);
Student s2=new Student("李四",16);
Student s3=new Student("王五",15);
Student[] students=new Student[3];
//数组作为容器,有一些不便之处
//数组长度一旦确定,不便在数组中增删元素
//Java为我们提供了一种容器,集合。它对容器中的元素进行增删改查操作很方便
//我们通过多态的形式来创建Collection接口的对象
Collection collection=new ArrayList();
/*
boolean add(E e)
确保此collection包含指定的元素(可选操作)。如果此collection由于调用而发生更改,则返回true。
*/
collection.add(s1);
collection.add(s2);
collection.add(s3);
System.out.println(collection);
}
}
class Student {
private String name;
private int age;
public Student() {
}
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
/*
运行结果:
[Student{name='张三', age=15}, Student{name='李四', age=16}, Student{name='王五', age=15}]
*/
数组与集合的区别:
- 数组的长度一旦确定,不可变。而集合的长度可以改变。
- 集合的长度可变 数组既可以基本类型数据,也可以存储引用类型数据。集合只能存储引用类型数据。
- 数组只能存储同一种数据类型的数据,集合可以存储多种数据类型的数据
方法
boolean add(E e)
确保此collection包含指定的元素(可选操作)。如果此collection由于调用而发生更改,则返回true。
boolean addAll(Collection<? extends E> c)
将指定collection中的所有元素都添加到此collection中(可选操作)。
import java.util.ArrayList;
import java.util.Collection;
public class Demo {
public static void main(String[] args) {
Collection collection1=new ArrayList();
//如果add方法存储基本数据类型,会将这些基本数据类型进行自动装箱,然后再存储
//也就是说,集合中存储的依旧是引用数据类型
collection1.add(100);
collection1.add(200);
collection1.add(300);
System.out.println(collection1);
Collection collection2=new ArrayList();
collection2.add(1000);
collection2.add(2000);
collection2.add(3000);
collection1.addAll(collection2);
//addAll方法只会改变collection1,即调用者的集合。而collection2不会发生改变。
System.out.println(collection1);
System.out.println(collection2);
}
}
/*
运行结果:
[100, 200, 300]
[100, 200, 300, 1000, 2000, 3000]
[1000, 2000, 3000]
*/
void clear()
移除此collection中的所有元素(可选操作)。
boolean remove(Object o)
从此collection中移除指定元素的单个实例,如果存在的话(可选操作)。
boolean removeAll(Collection<?> c)
移除此collection中那些也包含在指定collection中的所有元素(可选操作)。
import java.util.ArrayList;
import java.util.Collection;
public class Demo {
public static void main(String[] args) {
Collection collection=new ArrayList();
collection.add(100);
collection.add(200);
collection.add(300);
collection.remove(100);
System.out.println(collection);
collection.clear();
System.out.println(collection);
Collection collection1=new ArrayList();
collection1.add(100);
collection1.add(200);
collection1.add(300);
Collection collection2=new ArrayList();
collection2.add(100);
collection2.add(2000);
collection2.add(3000);
//移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。即移除交集元素
//移除一个及一个以上返回则true
boolean b = collection1.removeAll(collection2);
System.out.println(b);
//同样的,只有collection1中的元素发生改变,collection2中的元素不变
System.out.println(collection1);
System.out.println(collection2);
}
}
/*
运行结果:
[200, 300]
[]
true
[200, 300]
[100, 2000, 3000]
*/
boolean contains(Object o)
如果此collection包含指定的元素,则返回true。
boolean containsAll(Collection<?> c)
如果此collection包含指定collection中的所有元素,则返回true。
boolean isEmpty()
如果此collection不包含元素,则返回true。
import java.util.ArrayList;
import java.util.Collection;
public class Demo {
public static void main(String[] args) {
Collection collection=new ArrayList();
collection.add(100);
collection.add(200);
collection.add(300);
collection.add(400);
boolean b1= collection.contains(100);
Collection collection1=new ArrayList();
collection1.add(100);
collection1.add(200);
boolean b2 = collection.containsAll(collection1);
boolean b3 = collection.isEmpty();
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
}
}
/*
运行结果:
true
true
false
*/
遍历的方法:
通过迭代器遍历集合中的元素
Iterator接口:对collection进行迭代的迭代器。
返回Iterator的子类对象
我们可使用以下方法对集合进行遍历
boolean hasNext()
如果仍有元素可以迭代,则返回 true。
E next()
返回迭代的下一个元素。
int size()
返回此 collection 中的元素数。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Demo {
public static void main(String[] args) {
Collection arrayList=new ArrayList();
arrayList.add(100);
arrayList.add(200);
arrayList.add(300);
arrayList.add(400);
arrayList.add(500);
arrayList.add(600);
//输出iterator可得:java.util.ArrayList$Itr@1b6d3586。$代表该类是一个内部类,可以访问外部类成员
//private class Itr implements Iterator<E>
Iterator iterator=arrayList.iterator();
while (iterator.hasNext())
{
Object next = iterator.next();//将指针下移
System.out.println(next);
}
int size = arrayList.size();
System.out.println(size);
}
}
/*
运行结果:
100
200
300
400
500
600
6
*/
boolean retainAll(Collection c)
仅保留此collection中那些也包含在指定collection的元素。换句话说,移除此collection中未包含在指定collection中的所有元素。
import java.util.ArrayList;
import java.util.Collection;
public class Demo {
public static void main(String[] args) {
Collection collection1=new ArrayList();
collection1.add(100);
collection1.add(200);
collection1.add(300);
collection1.add(400);
Collection collection2=new ArrayList();
collection2.add(300);
collection2.add(400);
collection2.add(500);
collection2.add(600);
//保留collection1和collection2中的交集元素
boolean b = collection1.retainAll(collection2);
System.out.println(b);
System.out.println(collection1);
System.out.println(collection2);
}
}
/*
运行结果:
true
[300, 400]
[300, 400, 500, 600]
*/
Object[] toArray()
返回包含此collection中所有元素的数组。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class Demo {
public static void main(String[] args) {
Collection collection=new ArrayList();
collection.add(100);
collection.add(200);
collection.add(300);
Object[] objects = collection.toArray();
System.out.println(Arrays.toString(objects));
}
}
/*
输出结果:
[100, 200, 300]
*/
List集合
有序的 collection(也称为序列)。列表通常允许重复的元素。
方法
void add(int index, E element)
在列表的指定位置插入指定元素(可选操作)。
int indexOf(Object o)
返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回-1。
int lastIndexOf(Object o)
返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回-1。
List subList(int fromIndex,int toIndex)
返回列表中指定的fromIndex(包括 )和toIndex(不包括)之间的部分视图。
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List list=new ArrayList();
list.add(100);
list.add(0,200);
list.add(1,300);
list.add(100);
System.out.println(list);
int index1= list.indexOf(100);
int index2 = list.lastIndexOf(100);
System.out.println(index1);
System.out.println(index2);
List list1 = list.subList(0, 3);
System.out.println(list);
System.out.println(list1);
}
}
/*
运行结果:
[200, 300, 100, 100]
2
3
[200, 300, 100, 100]
[200, 300, 100]
*/
E get(int index)
返回列表中指定位置的元素。
E set(int index,E element)
用指定元素替换列表中指定位置的元素(可选操作)。
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List list=new ArrayList();
list.add(100);
list.add(200);
list.add(300);
list.add(400);
Object o1 = list.get(1);
System.out.println(o1);
//返回被替换的旧元素
Object o2 = list.set(0, 10);
System.out.println(o2);
System.out.println(list);
}
}
/*
运行结果:
200
100
[10, 200, 300, 400]
*/
List集合遍历的三种方式
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class Demo {
public static void main(String[] args) {
List list=new ArrayList();
list.add(100);
list.add(200);
list.add(300);
list.add(400);
//遍历List集合
//方式1:通过迭代器
Iterator iterator = list.iterator();
while (iterator.hasNext())
{
Object next = iterator.next();
System.out.println(next);
}
System.out.println("-------------");
//方法2:在for循环中使用get方法
//因为Collection接口中没有get方法,所以无法用for循环遍历集合
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("-------------");
//方式3:List集合本身具有的迭代器ListIterator
ListIterator listIterator = list.listIterator();
while (listIterator.hasNext())
{
Object next = listIterator.next();
System.out.println(next);
}
}
}
/*
运行结果:
100
200
300
400
-------------
100
200
300
400
-------------
100
200
300
400
*/
正向迭代和反向迭代
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Demo {
public static void main(String[] args) {
List list=new ArrayList();
list.add(1001);
list.add(1002);
list.add(1003);
list.add(1004);
list.add(1005);
//正向迭代
ListIterator listIterator = list.listIterator();
while (listIterator.hasNext())
{
Object next = listIterator.next();
System.out.println(next);
}
//反向迭代
//注意反向迭代前要先进行正向迭代。即先将指针移至集合的最后一位,才能进行反向迭代
System.out.println("---------");
while (listIterator.hasPrevious()) //判断有没有上一个元素
{
Object previous = listIterator.previous(); //获取上一个元素并使指针上移
System.out.println(previous);
}
}
}
并发修改异常
public class Demo {
public static void main(String[] args) {
//有一个集合,判断里面有没有 "world" 这个元素,如果有,就添加一个 "javaee" 元素,请写代码实现。
List list=new ArrayList();
list.add("aa");
list.add("bb");
list.add("world");
list.add("cc");
ListIterator listIterator = list.listIterator();
while (listIterator.hasNext())
{
Object next = listIterator.next();
String str=(String)next;
if(str.equals("world"))
list.add("javaee");
}
}
}
/*
运行后会产生异常:Exception in thread "main" java.util.ConcurrentModificationException(并发修改异常)
*/
我们来简单探讨一下异常产生的原因
在ListItr这个内部类中,有两个成员变量:
expectedModCount:表示对ArrayList修改次数的期望值,它的初始值为modCount。
modCount:是AbstractList类中的一个成员变量
每次进行调用add或remove方法时,modCount的值会发生变化。
我们再来看next方法,next方法中调用了checkForComodification方法,我们可以看一下这个方法的代码:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
也就是说在调用next方法时,如果modCount != expectedModCount就会抛出ConcurrentModificationException这个异常,即并发修改异常。
总结一下就是在add或remove方法会使modCount的值发生改变,致使在调用next方法时modCount与expectedModCount不相等所以产生了并发修改异常 。
解决方法:
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Demo {
public static void main(String[] args) {
//方式1:使用迭代器自带的添加和删除方法
List list=new ArrayList();
list.add("aa");
list.add("bb");
list.add("world");
list.add("cc");
ListIterator listIterator = list.listIterator();
while (listIterator.hasNext()) {
Object next = listIterator.next();
String str = (String) next;
if (str.equals("world"))
listIterator.add("javaee");
}
}
}
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args) {
//方式2:使用for循环
List list=new ArrayList();
list.add("aa");
list.add("bb");
list.add("world");
list.add("cc");
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
String str=(String)o;
if (str.equals("world"))
list.add("javaee");
}
}
}
ArrayList类、Vector类、LinkedList类
ArrayList类:List接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括null在内的所有元素。除了实现List接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。
Vector类:Vector类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。
LinkedList类:List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。
三个子类的比较:
ArrayList:底层数据结构是数组,查询快,增删慢。线程不安全,效率高。
Vector:底层数据结构是数组,查询快,增删慢。线程安全,效率低。
LinkedList:底层数据结构是链表,查询慢,增删快。线程不安全,效率高。
三个子类的特殊方法
除了可以用迭代器和for循环遍历ArrayList集合,还可以使用forEach方法
public void forEach(Consumer<? super E> action)
对Iterable的每个元素执行给定的操作,直到所有元素都被处理或动作引发异常。
对于这个方法需要传入一个Consumer类的对象,经查询该类为一个接口。所以传入该接口子类的对象
//方法1:创建该接口的子类,然后传入该类对象
import java.util.ArrayList;
import java.util.function.Consumer;
public class Demo {
public static void main(String[] args) {
ArrayList arrayList=new ArrayList();
arrayList.add("aaa");
arrayList.add("bbb");
arrayList.add("ccc");
arrayList.add("aaa");
arrayList.add("ddd");
arrayList.add("eee");
arrayList.forEach(new MyConsumer());
}
}
class MyConsumer implements Consumer<String>
{
//在该方法中对传入的对象,即集合中的元素进行操作
@Override
public void accept(String s) {
System.out.println(s);
}
}
//方法2:创建匿名内部类,在匿名内部类中重写accept方法
import java.util.ArrayList;
import java.util.function.Consumer;
public class Demo1 {
public static void main(String[] args) {
ArrayList arrayList=new ArrayList();
arrayList.add("aaa");
arrayList.add("bbb");
arrayList.add("ccc");
arrayList.add("aaa");
arrayList.add("ddd");
arrayList.add("eee");
arrayList.forEach(new Consumer() {
@Override
public void accept(Object o) {
System.out.println(o);
}
});
}
}
Vector类特有的迭代器
使用方法和iterator方法和listIterator方法类似
import java.util.Enumeration;
import java.util.Vector;
public class Demo {
public static void main(String[] args) {
//Vector自带的迭代器
Vector vector = new Vector();
vector.add(100);
vector.add(200);
vector.add(300);
Enumeration elements = vector.elements();
while (elements.hasMoreElements())
{
Object o = elements.nextElement();
System.out.println(o);
}
}
}
LinkedList类中一些特有方法
public E peek()
获取但不移除此列表的头(第一个元素)。
public E poll()
获取并移除此列表的头(第一个元素)
public E pop()
从此列表所表示的堆栈处弹出一个元素。换句话说,移除并返回此列表的第一个元素。
import java.util.LinkedList;
public class Demo2 {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add(100);
linkedList.add(200);
linkedList.add(300);
Object peek = linkedList.peek();
System.out.println(peek);
Object poll = linkedList.poll();
System.out.println(poll);
System.out.println(linkedList);
Object pop = linkedList.pop();
System.out.println(pop);
System.out.println(linkedList);
}
}
/*
运行结果:
100
100
[200, 300]
200
[300]
*/
poll方法和pop方法的区别
poll是队列数据结构实现类的方法,从队首获取元素,同时获取的这个元素将从原队列删除;当队列中没有元素时,调用方法输出返回的元素会输出null
pop是栈结构的实现类的方法,表示返回栈顶的元素,同时该元素从栈中删除,当栈中没有元素时,调用该方法会发生异常
import java.util.LinkedList;
public class Demo {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add(100);
linkedList.add(200);
linkedList.add(300);
linkedList.clear();
Object poll1 = linkedList.poll();
//调用pop方法会出现异常
//Exception in thread "main" java.util.NoSuchElementException
Object pop1 = linkedList.pop();
System.out.println(poll1); //此处会输出null
}
}