1.首先思考一个问题:为什么要有集合?
我们也知道,数组可以保存多个对象,但是在某些情况下无法确定到底需要保存多少个对象,此时数组不再适用没因为数组的长度不可变,例如,要保存一个学校的学生信息,由于不停有新生来报道,同时也有学生毕业离开学校,这时学生的数目无法固定,并且随时可能变动,为了保存这些数目不确定的对象,JAVA提供了一系列特殊的类,统称为集合,集合可以储存任意类型的对象,并且长度可变。
下面是集合体系核心架构图:
接下来我将根据这条图的架构来学习集合:
2.单列集合Collection
Collection是单列集合的根接口,用于存储一系列符合某种规则的元素。Collections集合有两个重要的子接口,分别是List和Set。
1.size():返回集合中元素的个数
2.add(Object obj):向集合中添加一个元素
3.addAll(Colletion coll):将形参coll包含的所有元素添加到当前集合中
4.isEmpty():判断这个集合是否为空
5.clear():清空集合元素
6.contains(Object obj):判断集合中是否包含指定的obj元素
① 判断的依据:根据元素所在类的equals()方法进行判断
②明确:如果存入集合中的元素是自定义的类对象,要去:自定义类要重写equals()方法
7.constainsAll(Collection coll):判断当前集合中是否包含coll的所有元素
8.rentainAll(Collection coll):求当前集合与coll的共有集合,返回给当前集合
9.remove(Object obj):删除集合中obj元素,若删除成功,返回ture否则
10.removeAll(Collection coll):从当前集合中删除包含coll的元素
11.equals(Object obj):判断集合中的所有元素 是否相同
12.hashCode():返回集合的哈希值
13toArray(T[] a):将集合转化为数组
①如有参数,返回数组的运行时类型与指定数组的运行时类型相同。
14.iterator():返回一个Iterator接口实现类的对象,进而实现集合的遍历。
15.数组转换为集合:Arrays.asList(数组)
这些Collection方法都来自Java API文档。Collection没有get方法,可以用tocharArray方法将集合转换成一个object类型的数组。
主要功能示例:
package com.Collection;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionMethod {
public static void main(String[] args) {
ArrayList list = new ArrayList();
//add:添加单个元素
list.add("5");
list.add(10); //list.add(new Integer(10));
list.add(true);
System.out.println("list=" + list);//list=[5, 10, true]
//remove:删除指定元素
list.remove(0); //删除第一个元素
list.remove(true); //删除指定元素
System.out.println("list=" + list);//list=[10]
//contains:查找元素是否存在
System.out.println(list.contains("2"));//false
//size:获取元素个数
System.out.println(list.size());//1
//isEmpty:判断是否为空
System.out.println(list.isEmpty());//false
//clear:清空
list.clear();
System.out.println("list=" + list);//list=[]
//addAll添加多个元素
ArrayList list2 = new ArrayList();
list2.add("tom");
list2.add("jack");
list.addAll(list2);
System.out.println("list=" + list);//list=[tom, jack]
//containsAll:查找多个元素是否都存在
System.out.println(list.containsAll(list));//true
//removeAll:删除多个元素
list.removeAll(list);
System.out.println("list=" + list);//list=[]
}
}
2.1 List集合
List集合的特点是元素有序(存储和读取的顺序是一致的)、可重复、有整数序列.
习惯性的会将实现了List接口的对象成为List集合。在List集合中允许出现重复的元素,所有的元素是以一种线性的方式进行存储的,在程序中可以通过索引(类似于数组中的元素角标)来访问集合中的指定元素。
List作为Coecction集合的子接口,不但继承了Collection接口中的全部方法,而且还增加了一些操作集合的特有方法。如下图所示
1.void add(int index,Collection ele):在index位置插入ele元素
2.boolean addAll(int index,Collection eles):从index位置开始将eles中的所有元素添加进来
3.Object get(int index):获取指定index位置的元素
4.int indexOf(Object obj):返回obj在集合中首次出现的位置
5.int lastIndexOf(Object obj):返回obj当前集合中末尾出现的位置
6.Object remove(int index):移除指定index位置的元素,并返回此元素
7.Object set(int index,Object ele):设置指定index位置的元素为ele,相当于替换
8.List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
主要功能示例
import java.util.ArrayList;
import java.util.List;
public class ListMethod {
public static void main(String[] args) {
List list = new ArrayList();
// void add(int index,Collection ele):在index位置插入ele元素
list.add("helo");
list.add("你好");
System.out.println(list); //[hello, 你好]
// boolean addAll(int index,Collection eles):从index位置开始将eles中的所有元素添加进来
List list1 = new ArrayList();
list1.add("Jack");
list1.add("Tom");
list1.add("Jack");
list.addAll(1,list1);
System.out.println(list); //hello, Jack, Tom, Jack, 你好]
// Object get(int index):获取指定index位置的元素
System.out.println(list.get(1)); //Jack
// int indexOf(Object obj):返回obj在集合中首次出现的位置
System.out.println(list.indexOf("Jack")); //1
// int lastIndexOf(Object obj):返回obj当前集合中末尾出现的位置
System.out.println(list.lastIndexOf("Jack")); //3
// Object remove(int index):移除指定index位置的元素,并返回此元素
System.out.println(list.remove(3)); //Jack
System.out.println(list); //[hello, Jack, Tom, 你好]
// Object set(int index,Object ele):设置指定index位置的元素为ele,相当于替换
System.out.println(list.set(1,"Hello")); //Jack
System.out.println(list); //[hello, Hello, Tom, 你好]
// List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
System.out.println(list.subList(1,2)); //[Hello]
}
}
2.1.1ArrayList集合
ArrayList是List接口的一个实现类,它是程序中最常见的一种集合,ArrayList 继承了 AbstractList ,并实现了 List 接口。在ArrayList内存内部封装了一个长度可变的数组对象,当存入的元素超过数组长度时,Array List会在内存中分配一个更大的数组来存储这些元素,因此可以将Array List集合看作一个长度可变的数组。
由于ArrayList内部的数据存储结构是数组形式,在增加或删除指定位置元素的时候,会创建新的数组,效率比较低,所以不适合做大量的删除操作。但是这种数组又是通过索引方式来访问元素,因此在遍历和查找元素时就是非常高效的。
01如何创建对象?
ArrayList<泛型> list=new ArrayList<>();
02 常用的方法
ArrayList一样可以使用List的所有方法
对于元素的操作,基本体现在——增、删、查。常用的方法有:
1.public boolean add(E e) :将指定的元素添加到此集合的尾部。
2.public E remove(int index) :移除此集合中指定位置上的元素。返回被删除的元素。
3.public E get(int index) :返回此集合中指定位置上的元素。返回获取的元素。
4.public int size() :返回此集合中的元素数。遍历集合时,可以控制索引范围,防止越界。
这些都是最基本的方法,操作非常简单,代码如下:
import java.util.ArrayList;
import java.util.List;
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
System.out.println(list); // []
// 向集合中添加元素:add
boolean success = list.add("小朱");
System.out.println(list); // [小朱]
System.out.println("添加的动作是否成功:" + success); // true
list.add("小陈");
list.add("小刘");
list.add("小王");
list.add("小李");
System.out.println(list); // [小朱, 小陈, 小刘, 小王, 小李]
// 从集合中获取元素:get。索引值从0开始
String name = list.get(2);
System.out.println("第2号索引位置:" + name); // 小刘
// 从集合中删除元素:remove。索引值从0开始。
String whoRemoved = list.remove(3);
System.out.println("被删除的人是:" + whoRemoved); // 小王
System.out.println(list); // [小朱, 小陈, 小刘, 小李]
// 获取集合的长度尺寸,也就是其中元素的个数
int size = list.size();
System.out.println("集合的长度是:" + size);//3
2.1.2 LinkedList集合
为什么要使用LinkedList?
ArrayList集合在查询元素时速度很快,但是在新增元素的时候效率又很低,为了克服这种局限性,就有了另一个List的实现类LinkedList。
LinkedList内部包含有两个Node类型的first和last属性维护一个双向循环链表,从而可以将所有元素彼此连接起来。要插入一个新元素的时候,只需要修改元素之间的这种引用关系即可,删除一个节点也是类似。所以LinkedList集合对于元素的增删操作效率很高
LinkedList除了从接口Collection和List中继承并实现集合操作方法之外,还专门对元素的增删操作定义了一些特有的方法,从增删改查四个方法来说明
一.增加
1、boolean add(E e) 将指定元素添加到此列表的结尾。
2、void add(int index, E element) 在此列表中指定的位置插入指定的元素。
3、 void addFirst(E e)将指定元素插入此列表的开头。
4、void addLast(E e)将指定元素添加到此列表的结尾。
5、boolean addAll(Collection<? extends E> c)添加指定 collection 中的所有元素到此列表的结尾,顺序是指定 collection 的迭代器返回这些元素的顺序。
public static void main(String[] args) {
LinkedList<String> list=new LinkedList<String>();
list.add("111");
list.add("222");
list.add(0,"333");
list.addFirst("000");
list.addLast("444");
LinkedList<String> list2=new LinkedList<String>(list);
LinkedList<String> list3=new LinkedList<String>();
list3.addAll(list2);
System.out.println(list);
System.out.println(list2);
System.out.println(list3);
}
输出结果
[000, 333, 111, 222, 444]
[000, 333, 111, 222, 444]
[000, 333, 111, 222, 444]
二.删除
1、 E remove() 获取并移除此列表的头(第一个元素)。
2、 boolean remove(Object o) 从此列表中移除首次出现的指定元素(如果存在)。
3、 E removeFirst()移除并返回此列表的第一个元素。
4、 boolean removeFirstOccurrence(Object o)从此列表中移除第一次出现的指定元素(从头部到尾部遍历列表时)。
5、 E removeLast()移除并返回此列表的最后一个元素
6、boolean removeLastOccurrence(Object o)从此列表中移除最后一次出现的指定元素(从头部到尾部遍历列表时)。
7、 void clear()
public static void main(String[] args) {
LinkedList<String> list=new LinkedList<String>();
list.add("111");
list.add("222");
list.add("333");
list.add("444");
list.add("555");
list.add("666");
list.add("777");
list.add("888");
System.out.println(list);
list.remove();
System.out.println(list);
list.remove(0);
System.out.println(list);
list.remove("333");
System.out.println(list);
list.removeFirst();
System.out.println(list);
list.removeLast();
System.out.println(list);
list.clear();
System.out.println(list);
}
输出结果
[111, 222, 333, 444, 555, 666, 777, 888]
[222, 333, 444, 555, 666, 777, 888]
[333, 444, 555, 666, 777, 888]
[444, 555, 666, 777, 888]
[555, 666, 777, 888]
[555, 666, 777]
[]
三.修改元素
E set(int index, E element) 将此列表中指定位置的元素替换为指定的元素。
四.获取元素
1、E get(int index) 返回此列表中指定位置处的元素。
2、E getFirst()返回此列表的第一个元素。
3、E getLast()返回此列表的最后一个元素。
4、int indexOf(Object o)返回此列表中首次出现的指定元素的索引,如果此列表中不包含该元素,则返回 -1。
5、int lastIndexOf(Object o)返回此列表中最后出现的指定元素的索引,如果此列表中不包含该元素,则返回 -1
6、 int size()返回此列表的元素数。
public static void main(String[] args) {
LinkedList<String> list=new LinkedList<String>();
list.add("111");
list.add("222");
list.add("333");
list.add("444");
list.add("555");
list.add("666");
list.add("777");
list.add("888");
System.out.println(list.get(0));
System.out.println(list.getFirst());
System.out.println(list.getLast());
System.out.println(list.indexOf("111"));
System.out.println(list.size());
}
111
111
888
0
8
在这里插入代码片
2.1.3 对于什么情况下使用ArrayList和LinkedList做以总结:
如果查询多,增删少,则使用ArrayList
如果查询少,增删多,则使用LinkedList
如果不知道使用什么,则使用ArrayList
3.1Set集合
Set接口和List接口一样,他同样继承自Collection接口,与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection接口更加严格,与List接口不同的是,Set集合的特点是元素无序并且不可重复,都以某种规则保证存入的元素不出现重复。
Set接口主要有两个实现类,分别是HashSet和TreeSet,其中HashSet是根据对象的哈希值来确定元素在集合中的存储的位置,因此具有良好的存取和查找性能,TreeSet则是以二叉树的方式来存储元素,它可以实现对集合中的元素进行排序。
3.1.1HashSet集合
HashSet是Set接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的,当向HashSet集合中添加一个元素时,首先会调用该元素的hashCode()方法来确定元素的存储位置,然后再调用元素对象的equals()方法来确保该位置没有重复元素。
那么HashSet集合为什么不能出现重复的元素呢?
这是因为它在存入元素时做了很多工作,当调用HashSet集合的add()方法存入元素时,首先调用存入元素的hashCode()方法,获得对象的哈希值,然后根据对象的哈希值计算出一个存储位置;如果该位置上没有元素,则直接将元素存入,如果该位置上有元素存在,则会调用equals()方法让当前存入的元素依次和该位置上的元素进行比较,如果返回的结果为false就将该元素存入集合,返回的结果为true,则说明有重复元素,就将该元素舍弃。
由于HashSet接口中没有顺序,所以不存在根据索引的get方法
HashSet的主要方法基本跟Collection的方法一致,如下
1.add(E e):如果此 set 中尚未包含指定元素,则添加指定元素。
2.clear():从此 set 中移除所有元素。
3.clone():返回此 HashSet 实例的浅表副本:并没有复制这些元素本身。
4.contains(Object o):如果此 set 包含指定元素,则返回 true。
5.isEmpty():如果此 set 不包含任何元素,则返回 true。
6.Iterator iterator():返回对此 set 中元素进行迭代的迭代器。
7.remove(Object o):如果指定元素存在于此 set 中,则将其移除。
8.size():返回此 set 中的元素的数量(set 的容量)。
import java.util.HashSet;
import java.util.Iterator;
public class myHSetClass {
public static void main(String[]args){
HashSet hset=new HashSet();
//add()向hist集合添加自定义对象元素
hset.add(new Person(1,"A1"));
hset.add(new Person(2,"A2"));
hset.add(new Person(3,"A3"));
hset.add(new Person(4,"A4"));
hset.add(new Person(4,"A4"));
// 返回对此 set 中元素进行迭代的迭代器
Iterator it=hset.iterator();
while(it.hasNext()){
Person p=(Person)it.next();
//打印集合集合里的元素
System.out.println(p.getAger()+","+p.getName());
}
//size 获取元素个数
System.out.println("HashSet的元素格个数:"+hset.size());
//contains判断 HashSet中是否包含某个元素
System.out.println("HashSet中是否包含某个元素:"+hset.contains(new Person(4,"A4")));
//remove 删除对象
System.out.println("是否删除成功:"+ hset.remove(new Person(1,"A1")));
System.out.println("删除后的集合");
//删除后的集合
while(it.hasNext()){
Person p=(Person)it.next();
//打印集合集合里的元素
System.out.println(p.getAger()+","+p.getName());
}
}
}
class Person{
private String name;
private int age;
//创建添加元素构造器
Person(int age,String name){
this.name=name;
this.age=age;
}
public String getName(){
return name;
}
public int getAger(){
return age;
}
public int hashCode(){
System.out.println(this.name+"....hasCode");
//乘4是为了尽量保证哈希值的唯一
return name.hashCode()+age*4;
}
public boolean equals(Object obj){
//判断哈希值是否相同
if(!(obj instanceof Person)){
return false;
}
Person p=(Person)obj;
//打印比较次数
System.out.println(this.name+"...equals.."+p.name);
return this.name.equals(p.name) && this.age==p.age;
}
}
3.1.2TreeSet集合
TreeSet是Set接口的另一个实现类,它内部采用平衡二叉树来存储元素,这样的结构可以保证TreeSet集合中没有重复的元素,并且可以对元素进行排序。
二叉树就是每个节点最多有两个子节点的有序树,每个系欸但及子节点组成的数称为子树,通常左侧的子节点称为左子树,右侧的节点称为右子树,其中左子树上的元素小于它的根节点,而右子树上的元素大于它的根节点
针对TreeSet集合存储元素的特殊性,TreeSet在继承Set接口的基础上实现了一些特有的方法,如下所示:
1.Object first():返回TreeSet集合的首个元素
2.Object last():返回TreeSet集合的最后一个元素
3.Object lower(Object o):返回TreeS儿童集合中给定元素的最大元素,如果没有返回null
4.Object floor(Object o):返回TreeSet集合中小于或等于给定元素的最大元素,如果没有返回null
5.Object higher(Object o):返回TreeSet集合中大于给定元素的最小元素,如果没有返回null
6.Object ceiling(Object o):返回TreeSet集合中大于或等于给定元素的最小元素,如果没有返回null
7.Object pollFirst() 移除并返回集合的第一个元素
8.Object pollLast() 移除并返回集合的最后一个元素
import java.util.TreeSet;
public class Tree{
public static void main(String[args]){
//创建TreeSet集合
TreeSet ts=new TreeSet();
/1.想TreeSet集合中添加元素
ts.add(3);
ts.add(9);
ts.add(1);
ts.add(21);
System.out.println("创建的TreeSet集合为:"+ts);//[1,3,9,21]]
//获取收尾元素
System.out.println("TreeSet集合首元素为:"+ts.first());//1
System.out.println("TreeSet集合尾部元素为:"+ts.last()); //21
//3.比较并获取元素
System.out.println("集合中小于或等于9的最大一个元素为:"+ts.floor(9));//9
System.out.println("集合中大于10的最小的一个元素为:"+ts.higher(10));//21
System.out.println("集合中大于100的最小的一个元素为:"+ts.higher(100));//null
//4.删除元素
Object first=ts.pollFirst();
System.out.println("删除的第一个元素是:"+first);//1
System.out.println("删除的第一个元素后TreeSet集合变为是:"+ts);//[3,9,21]
}
}
从上面的例子可以看出,向TreeSet集合添加元素时,不论元素的添加顺序如何,这些元素都能按照一定的顺序进行排序,其原因是每次向TreeSet集合存入一个元素时,就会将该元素与其它元素进行笔记哎,最后将他插入到有序的对象序列中,集合中的元素在进行比较时,都会调用compareTo()方法,该方法时Comparable接口中定义的,因此要想对集合中的元素进行排序,就必须实现Comparable接口。