- 概述
相当于一个容器。
Java的集合框架是由很多接口、抽象类、具体类组成的,都位于java.util包中。
数组就是一个容器,但它删除元素麻烦;长度不能改变;容量不够时,需进行扩容。
而程序运行时,数据是时刻变化的,为满足各种变化的数据存储需求,在Java中封装了许多类类存储不同数据,这些类称为集合类。
2.单列集合 Collection
其子接口Set和List分别定义了存储方式。
● List 中的数据对象有顺序且可以重复。
● Set 中的数据对象没有顺序且不可以重复。
2.1 List
接口实现类的集合,可存储重复元素;有序;可通过索引操作元素
List继承了Collection接口,有三个实现的类
● ArrayList :数组列表
数组每个空间是连续的,所以查询方便,直接通过下标获取指定位置元素;但从中间增添删除元素较
麻烦,因增添删除后,其他元素要位移。
import java.util.ArrayList;
public class ArrayListDemo1 {
/*
ArrayList 数组列表 动态增添数组
ArrayList<E> 使用泛型的语法,为集合存储数据设定数据类型
底层数组 transient Object[] elementData;
add(); 默认向集合末尾添加元素,首次底层会初始化一个长度为10的数组,
当集合满了,会自动扩容为原来的1.5倍。
*/
public static void main(String[] args) {
//ArrayList<String> a=new ArrayList<String>();
ArrayList<String> a=new ArrayList();
a.add("a");//末尾添加
a.add("b");
a.add("c");
a.add("d");
a.add("e");
a.add("f");
a.add("g");
a.add("h");
a.add("i");
a.add("j");
a.add("k");
a.add(0,"A");//向指定位置添加
//a.clear();//清空
a.remove(1);//删除指定位置元素
a.remove("a");//删除指定内容元素 第一个出现的
System.out.println(a.size());//获取集合中元素个数
System.out.println(a.get(2));
System.out.println(a);
System.out.println(a.contains("f"));
System.out.println(a.isEmpty());
a.ensureCapacity(20);//扩容为指定容量
System.out.println(a.indexOf("b"));//从前向后 获取指定元素首次位置
System.out.println(a.lastIndexOf("b"));//从后向前 获取元素首次位置
a.set(1,"A");
System.out.println(a);
Object[] o=a.toArray();//将集合转为Object类
System.out.println(o.length);
String[] as=a.toArray(new String[a.size()]);//将集合转为指定类型
System.out.println(Arrays.toString(as));
}
}
● LikedList: 链表列表
每一个数据存储在一个Node类中 Node节点
链表结构,对外提供头尾节点,查询元素慢,必须从头或尾部开始;
从中间删除元素块,只需改变next节点的内存地址即可,元素不位移。
import java.util.LinkedList;
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<String> l=new LinkedList<>();
l.add("a");
l.add("b");
l.add("c");
l.add("d");
l.add(1,"A");
System.out.println(l.get(2));
l.remove(1);
l.remove("3");
System.out.println(l.size());
//LinkedList 可实现队列和栈结构容器
l.addFirst("A");
l.addLast("D");
System.out.println(l.getFirst());
System.out.println(l.getLast());
System.out.println(l.removeFirst());
System.out.println(l.removeLast());
System.out.println(l);
}
}
●Vector : 数组列表(线程安全的)
import java.util.Vector;
public class VectorDemo {
/*
List
Vector 数组列表
synchronized 线程安全的
*/
public static void main(String[] args) {
Vector<Integer> v=new Vector();
v.add(1);
v.add(2);
v.add(3);
v.add(4);
v.add(5);
v.add(6);
v.add(7);
v.add(8);
v.add(9);
v.add(10);
v.add(11);
v.add(12);
System.out.println(v);//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
}
}
List接口集合迭代
● for循环遍历
●增强for循环的遍历
import java.util.ArrayList;
public class LinkedFor {
public static void main(String[] args) {
ArrayList<String> a=new ArrayList<>();
a.add("a");
a.add("b");
a.add("c");
a.add("d");
//for 允许删除元素,注意元素的位移及索引变化
for(int i=0;i<a.size();i++){
String s=a.get(i);
System.out.println(s);
}
//增强循环 不允许删除元素 高度封装
for(String s:a){
System.out.println(s);
}
}
}
● 迭代器遍历(Iterator)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
public class LinkedFor2 {
public static void main(String[] args) {
ArrayList<String> a=new ArrayList<>();
a.add("a");
a.add("b");
a.add("c");
a.add("d");
/*
对集合进行遍历的迭代器
*/
Iterator<String> it=a.iterator();
while(it.hasNext()){//判断有无下一个元素
String item=it.next();//取出元素
if(item.equals("b")){
it.remove();
}
}
System.out.println(a);//[a, c, d]
/*
//获取集合的迭代器
ListIterator<String> it=a.listIterator();
while(it.hasNext()){
String item=it.next();
System.out.println(item);
}*/
//从后向前进行遍历 给定开始的位置
ListIterator<String> it=a.listIterator(a.size());//4 0-3
while(it.hasPrevious()){
String item=it.previous();
System.out.println(item);
/*输出
d
c
b
a
*/
}
}
}
2.2 Set
Set接口继承了Collection接口。 Set中所存储的元素是不重复的,但是是无序的, Set中的元素是没有索引的 。 Set接口有两个实现 类。
● HashSet
元素不能重复,即彼此调用equals方法比较,都返回false。 底层数据结构是哈希表+链表 哈希表依赖于哈希值存储 。
import java.util.HashSet;
public class HashSetDemo2 {
/*
HashSet:不能存储重复元素,存储元素无序
判断元素是否重复:不直接用equals()进行判断,因效率低;
而是先调用hashCode(),计算hash值,判断两整数是否相等;
但不同内容计算的hash值可能相同,当hash值相同时,再调用equals()判断
*/
public static void main(String[] args) {
HashSet<String> hs = new HashSet<>();
hs.add("as");//110 设哈希值为110
hs.add("as");//110
hs.add("通话");//1179410 与下面的元素哈希值相同
hs.add("种地");//1179410
System.out.println(hs);//[as, 通话, 种地]
}
}
存储自定义对象
import java.util.Objects;
package com.albb.javaCollection.Set;
import java.util.HashSet;
public class HashSetDemo3 {
public static void main(String[] args) {
/*
存储自定义对象时,类中默认没有重写hashCode()和equals(),
都是调用Object类中,其中的hashCode()默认获取对象的内存地址
*/
Car car1=new Car(101,"宝马1");
Car car2=new Car(102,"宝马2");
Car car3=new Car(103,"宝马3");
Car car4=new Car(101,"宝马1");
Car car5=new Car(104,"宝马4");
HashSet<Car> hs=new HashSet<>();
hs.add(car1);
hs.add(car2);
hs.add(car3);
hs.add(car4);
hs.add(car5);
System.out.println(hs);//[Car{num=101, name='宝马1'}, Car{num=102, name='宝马2'}, Car{num=103, name='宝马3'}, Car{num=104, name='宝马4'}]
}
}
public class Car implements Comparable<Car>{
private int num;
private String name;
public Car(int num,String name){
super();
this.num=num;
this.name=name;
}
@Override
public String toString() {
return "Car{" +
"num=" + num +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Car car = (Car) o;
return num == car.num &&
Objects.equals(name, car.name);
}
@Override
public int hashCode() {
return Objects.hash(num, name);
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
● TreeSet
不能储存重复元素,按值的自然顺序排列 以给Set集合中的元素进行指定方式的排序。存储的对象必须实现Comparable接口。 TreeSet底层数据结构是二叉树(红黑树是一种自平衡的二叉树)。
import java.util.TreeSet;
public class TreeSetDemo2 {
public static void main(String[] args) {
/*
向TreeSet添加类,必须实现Comparable接口,支持比较大小进行排序
*/
Car car1 = new Car(101, "宝马1");
Car car2 = new Car(102, "宝马2");
Car car3 = new Car(103, "宝马3");
Car car4 = new Car(101, "宝马1");
Car car5 = new Car(104, "宝马5");
TreeSet<Car> ts=new TreeSet<>();
ts.add(car1);
ts.add(car2);
ts.add(car3);
ts.add(car4);
ts.add(car5);
System.out.println(ts);//[Car{num=101, name='宝马1'}, Car{num=102, name='宝马2'}, Car{num=103, name='宝马3'}, Car{num=104, name='宝马4'}]
}
}
import java.util.Objects;
public class Car implements Comparable<Car>{
private int num;
private String name;
public Car(int num,String name){
super();
this.num=num;
this.name=name;
}
@Override
public String toString() {
return "Car{" +
"num=" + num +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Car car = (Car) o;
return num == car.num &&
Objects.equals(name, car.name);
}
@Override
public int hashCode() {
return Objects.hash(num, name);
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(Car o) {
return this.num-o.num;
}
}
遍历方式:
增强for循环 迭代器遍历
因为set集合,元素没有索引,索引就不能使用普通的for。
3. Map
将键映射到值的对象 一个映射不能包含重复的键 每个键最多只能映射到一个值。
有三个实现类
● HashMap
元素的key值不能重复, 排列顺序是不固定的,可以存储一个 为null的键。
import java.util.Collection;
import java.util.HashMap;
import java.util.Set;
public class HashMapDemo {
public static void main(String[] args) {
/*
Map 键值对形式存储数据
键不能重复,值可以
HashMap
键无序,只能存储一个null键
*/
HashMap<String,String> hm=new HashMap<>();
hm.put("a","aa");
hm.put("x","yy");
hm.put("b","bb");
hm.put("s","yy");
hm.put("b","bbb");
//hm.clear(); //清空hm中所有键值
//hm.remove(); //删除指定key
System.out.println(hm.get("a"));//aa
System.out.println(hm.containsKey("bb"));//false //判断是否包含指定的key
System.out.println(hm.isEmpty());//false
System.out.println(hm.size());//4 //键值对数
/*Collection<String> list=hm.values();
System.out.println(list);*/
Set<String> keyset=hm.keySet();//获取hm中所有的key
for(String key:keyset){
String values=hm.get(key);
System.out.println(key+" : "+values);/*
a : aa
b : bbb
s : yy
x : yy
*/
}
System.out.println(hm);//{a=aa, b=bbb, s=yy, x=yy}
}
}
● TreeMap
所有的元素都保持着某种固定的顺序,如果需要得到一个有序 的Map就应该使用TreeMap,key值所在类必须实现Comparable接口,重写compareTo方法。
键是红黑树结构,可以保证键的排序和唯一性。
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
/*
键值对存储
根据建进行排序,建的类型必须实现Comparable接口
*/
TreeMap<String,Integer> tm=new TreeMap<>();
tm.put("c",2);
tm.put("b",3);
tm.put("a",1);
tm.put("d",4);
tm.put("a",11);
System.out.println(tm);//{a=11, b=3, c=2, d=4}
}
}
● HashTable
键值对存储
底层结构和HashMap类似,但Hashtable线程安全
不能存储为null的key
import java.util.Hashtable;
public class HashtableDemo {
public static void main(String[] args) {
Hashtable<String,String> ht=new Hashtable<>();
ht.put("a","a");
ht.put("s","s");
ht.put("g","g");
ht.put("a","a");
ht.put("b","b");
System.out.println(ht);//{b=b, a=a, s=s, g=g}
}
}
import java.util.Hashtable;
public class HashtableDemo {
public static void main(String[] args) {
Hashtable<String,String> ht=new Hashtable<>();
ht.put(null,"a");
System.out.println(ht);
/*
Exception in thread "main" java.lang.NullPointerException
at java.util.Hashtable.put(Hashtable.java:465)
at com.albb.javaCollection.Map.HashtableDemo.main(HashtableDemo.java:18)
*/
}
}
for 遍历
方式1:根据键找值 • 获取所有键的集合 • 遍历键的集合,获取到每一个键 • 根据键找值 方式2:根据键值对对象找键和值 • 获取所有键值对对象的集合 • 遍历键值对对象的集合,获取到每一个键值对对象 • 根据键值对对象找键和
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapFor {
public static void main(String[] args) {
HashMap<String,String> hm=new HashMap<>();
hm.put("a","1");
hm.put("s","4");
hm.put("b","2");
hm.put("e","3");
Set<String> keyset=hm.keySet();
for(String key:keyset){
System.out.println(hm.get(key));
/*
1
2
4
3
*/
}
/*
方法2:遍历时,将key-value封装到一个个Entry对象中,包含了key和value
*/
Set<Map.Entry<String,String>> entryset=hm.entrySet();
for(Map.Entry<String,String> entry:entryset){
System.out.println(entry.getKey()+":"+entry.getValue());
/*
a:1
b:2
s:4
e:3
*/
}
}
}
4.Collections 类
● Collections是集合类的工具类,与数组的工具类Arrays类似.
它里面的方法有很多,如:
addAll(Collection<? super T> c, T... elements);
该方法的第二位参数以下代码中详解
binarySearch(List<? extends Comparable<? super T>> l ist, T key)
sort(List<T> l ist)
sort(List<T> l ist, Comparator<? super T> c) 后面讲
swap(List<?> l ist, int i, int j)
copy(List<? super T> dest, List<? extends T> src) ; 注意 dest size需大于等于src.size
emptyList() 返回为空的集合,不能添加数据
fill(List<? super T> l ist, T obj)
max(Col lection<? extends T> col l)
min(Col lection<? extends T> col l)
replaceAl l(List<T> l ist, T oldVal, T newVal)
reverse(List<?> l ist)
shuffle(List<?> l ist) 随机排序
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class CollectionsDemo {
public static void main(String[] args) {
/*
Collection 接口 是单列集合的顶级接口
Collections类 提供关于集合操作的方法类似于Arrays类
*/
ArrayList<String> a=new ArrayList<>();
a.add("a");
a.add("d");
a.add("c");
a.add("b");
/*//Collections.addAll(a,"1","2","3");将指定元素添加到原数组中
System.out.println(Collections.binarySearch(a,"d"));
Collections.sort(a);
Collections.swap(a,0,3);
Collections.reverse(a);
*/
ArrayList<String> b=new ArrayList<>();
b.add("1");
b.add("2");
b.add("3");
b.add("4");
b.add("5");
Collections.copy(b,a);//将a复制到b中,b的size()必须>=a的size()
System.out.println(b);
/*
List emptyList=Collections.emptyList();
返回一个空集合(内部类),不能使用,避免出现空指针
*/
//Collections.fill(a,"0");
Collections.shuffle(a);//随机调整元素位置
System.out.println(a);
System.out.println(Collections.max(a));
System.out.println(Collections.min(a));
test(1,2,3);
}
/*
int...a 可变长度参数,本质是一个数组
在一个参数列表中,只能有一个可变长度的参数,且只能放在参数列表的最后一位
*/
public static void test(int b,int...a){
System.out.println(Arrays.toString(a));// [2,3]
}
}