-
当我们需要保存一组一样(类型相同)的元素的时候,我们应该使用一个容器来存储,数组就是这样一个容器。但是 ,数组一旦定义,长度将不能再变化。
-
然而在我们的开发实践中,经常需要保存一些变长的数据集合,于是,我们需要一些能够动态增长长度的容器来保存我们的数据。
-
而我们需要对数据的保存的逻辑可能各种各样,于是就有了各种各样的数据结
构。Java中对于各种数据结构的实现,就是我们用到的集合。
- Java的集合框架是由很多接口、抽象类、具体类组成的,都位于java.util包中。
- Collection 接口-定义了存取一组对象的方法,其子接口Set和List分别定义了存储方式。
- Set 中的数据对象没有顺序且不可以重复。
- List 中的数据对象有顺序且可以重复。
- 在Collection 中定义了一些集合中的共有方法:
boolean addAll(Collection c);//将集合c添加到指定集合中 boolean remove(Object element);//删除集合中的指定元素 boolean removeAll(Collection c);//删除指定集合 不包含时,删除相交 的元素 void clear();//清空集合中所有的元素。 int size();//集合中元素的个数 boolean isEmpty();//判断集合是否为空 boolean contains(Object element);//判断集合是否包含指定元素 boolean containsAll(Collection c);//用于检测 arraylist 是否包含指定集合中的所有元素。 boolean retainAll(Collection c);//求交集,集合数据发生变化返回true, 不变返回false
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class CollectionDemo {
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add("abcd");
collection.add("efg");
collection.add("hijk");
collection.add("lmn");
System.out.println(collection);
//collection.clear();清理所有数据
collection.remove("abcd");
System.out.println("是否包含"+"abcd? "+collection.contains("abcd"));
System.out.println(collection);
System.out.println(collection+"的长度为:"+ collection.size());
System.out.println(collection+"是否为空?"+collection.isEmpty());
Object [] strings1 = collection.toArray();
System.out.println(Arrays.toString(strings1));
String [] strings2 = collection.toArray(new String[collection.size()]);//底层是数组复制
System.out.println(Arrays.toString(strings2));
System.out.println("n");
Collection c = new ArrayList<>();
c.add("a");
c.add("b");
c.add("c");
c.add("d");
Collection c1 = new ArrayList<>();
c1.add("a");
c1.add("b");
c1.add("c");
System.out.println("将c1集合中的所有元素添加到c中:");
c.addAll(c1);//将c1集合中的所有元素添加到c中
System.out.println(c+"n"+c1);
c.removeAll(c1);//删除c1在c中的所有元素
System.out.println("删除c1在c中的所有元素 c:"+c);
System.out.println("判断c中是否包含c1中所有的元素:"+c.containsAll(c1));
System.out.println("保留c与c1中相交的元素,若this集合中元素发生变化就返回true否则返回false "+c.retainAll(c1));
System.out.println("c:"+c+"n"+"c1:"+c1);
}
}
结果:
List接口及实现类- List继承了Collection接口,有三个实现的类
- ArrayList
- 数据列表,数据采用数组方式存储。
- LinkedList
- 链表
- Vector
- 数组列表,添加同步锁,线程安全的
- ArrayList
- ArrayList实现了长度可变的数组,在内存分配连续的空间。
- 遍历元素和随机访问元素的效率比较高
- LinkedList采用链表存储方式。插入、删除元素时效率较高。
//无参构造方法: ArrayList
代码测试
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList arrayList1 = new ArrayList<>(20);//创建一个容量为20的集合
ArrayList arrayList = new ArrayList<>();
arrayList.add("a");
arrayList.add("a");
arrayList.add("a");
arrayList.add("a");
arrayList.add("bn");
arrayList.add("a");
arrayList.add("a");
arrayList.add("c");
arrayList.add("a");
arrayList.add("a");
arrayList.add("a");
System.out.println(arrayList.get(2));//获取指定索引的元素
System.out.println(arrayList.indexOf("a")+"n"+arrayList.indexOf("b"));//返回元素第一次出现的索引,若没有就返回-1
System.out.println();
System.out.println("删除前"+arrayList);
arrayList.remove(0);//删除指定索引的元素
System.out.println("删除后"+arrayList);
arrayList.set(2,"d");//替换指定索引的元素
System.out.println("替换索引2处的元素为 d "+arrayList);
}
}
结果:
LinkedList的常用方法: add(int index,Object element)//向集合中指定位置添加元素 addFirist(Object element) //向集合头部添加元素 addLast(Object element) //向集合尾部添加元素 get(int index) //获取指定索引的集合元素 removeFirst() //删除集合头部元素 removeLast() //删除集合尾部元素 remove(int index) //删除指定索引的元素 getFirst() //获取集合头部元素 getLast()//获取集合尾部元素List接口集合迭代
- 迭代器遍历(iterator)
public class IteratorDemo {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList<>();
arrayList.add("a");
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
arrayList.add("d");
System.out.println(arrayList);
for(int i=0;i
if(arrayList.get(i).equals("a")){
arrayList.remove(i);
i--;
}
}
System.out.println(arrayList);
System.out.println();
System.out.println("从前往后遍历");
Iterator iterator = arrayList.iterator();//迭代器,遍历只支持从前往后
while(iterator.hasNext()){
String s = iterator.next();
System.out.println(s);
}
for(String a:arrayList){//不支持增强for循环中删除操作
if(a.equals("b")){
arrayList.remove(a);
break;
}
}
System.out.println("从后往前遍历");
ListIterator listIterator = arrayList.listIterator(arrayList.size());
//可以从前往后遍历,也可以从后往前遍历,但是在创建迭代器对象是时要先把迭代器指向集合最后一个元素的下一个
while(listIterator.hasPrevious()){
System.out.println(listIterator.previous());
}
}
}
Set接口
-
Set接口继承了Collection接口。
- Set中所存储的元素是不重复的,但是是无序的, Set中的元素是没有索引的
-
Set接口有两个实现类。
-
HashSet
-
HashSet类中的元素不能重复,即彼此调用equals方法比较,都返回false。
-
底层数据结构是哈希表+链表
哈希表依赖于哈希值存储。
-
public class Car { String name; int num; public Car(String name,int num){ this.name=name; this.num=num; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } @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 && name.equals(car.name); } @Override public int hashCode() { return Objects.hash(name, num); } @Override public String toString() { return "Car{" + "name='" + name + ''' + ", num=" + num + '}'; } } public class Test { public static void main(String[] args) { HashSethashSet = new HashSet<>(); Car car = new Car("宝马1",300000); Car car1 = new Car("宝马2",400000); Car car2 = new Car("宝马3",500000); Car car3 = new Car("宝马4",600000); Car car4 = new Car("宝马1",300000); hashSet.add(car); hashSet.add(car1); hashSet.add(car2); hashSet.add(car3); hashSet.add(car4); System.out.println(hashSet);//当没有在Car类中重写equals和hashCode方法时会输出五个,不会去重复 } } - TreeSet
- 可以给Set集合中的元素进行指定方式的排序。存储的对象必须实现Comparable接口。
- TreeSet底层数据结构是二叉树(红黑树是一种自平衡的二叉树)
public class User implements Comparable
{//当自己写的类需要添加到TreeSet中时,需要实现Comparable接口,否则添加时会类型转换(ClassCastException)错误 public int num; public String name; public User (int num,String name){ this.name=name; this.num=num; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return num == user.num && name.equals(user.name); } @Override public int hashCode() { return Objects.hash(num, name); } @Override public String toString() { return "User{" + "num=" + num + ", name='" + name + ''' + '}'; } @Override public int compareTo(User o) { return this.num-o.num; } } public class TreeSetDemo { public static void main(String[] args) { User user1 = new User(101,"yh1"); User user2 = new User(102,"yh2"); User user3 = new User(103,"yh3"); User user4 = new User(104,"yh4"); User user5 = new User(101,"yh1"); TreeSet tset = new TreeSet<>(); tset.add(user3); tset.add(user5); tset.add(user1); tset.add(user4); tset.add(user2); //增强for循环遍历 Iterator iterator = tset.iterator(); for(User a:tset){ System.out.println(a); } //set迭代器遍历: while(iterator.hasNext()){ System.out.println(iterator.next()); } } } -
-
Map接口概述
将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值。
-
Map接口常用方法
-
V put(K key,V value) //向集合中添加键值对key=value V remove(Object key) //根据key删除对应的value值 void clear() //清空map集合 boolean containsKey(Object key) //判断集合中是否存在key键 boolean containsValue(Object value) //判断集合中是否存在value值 boolean isEmpty()//判断集合是否为空 int size() //获取map集合长度 V get(Object key) //根据key键获取对应的value值 Collectionvalues() //方法调用返回 此映射中包含的值 的集合视图。 Hashtable htable = new Hashtable(3); //添加数据 htable.put(1, "TP"); htable.put(2, "IS"); htable.put(3, "THE"); htable.put(4, "BEST"); htable.put(5, "TUTORIAL"); System.out.println(htable.values()); //结果[TUTORIAL, BEST, THE, IS, TP] Set keySet() //方法调用返回 此映射中包含的键 的set视图。 Map weakHashMap = new WeakHashMap (); //添加数据 weakHashMap.put("1", "first"); weakHashMap.put("2", "two"); weakHashMap.put("3", "three"); //返回set视图 Set set = weakHashMap.keySet(); System.out.println(set); //结果[1, 2, 3] Set > entrySet()//方法调用返回 此映射中包含的映射 的set视图。 Hashtable htable = new Hashtable(); //添加数据 htable.put(1, "A"); htable.put(2, "B"); htable.put(3, "C"); htable.put(4, "D"); // 创建视图 Set nset = htable.entrySet(); System.out.println(nset); //结果[4=D, 3=C, 2=B, 1=A] -
HashMap
HashMap中元素的key值不能重复,排列顺序是不固定的,可以存储一个为null的键。
public class HashMapDemo { public static void main(String[] args) { HashMapmap = new HashMap<>(); map.put("s","s"); map.put("a","a"); map.put("c","c"); map.put("b","a"); map.put("s","ss");//如果键相同,值不同,则第二次添加的键的值会覆盖第一次该键的值, System.out.println(map);//无序的,在这里即s==ss,{a=a, b=b, s=ss, c=c} //方法: // map.remove("s");//通过键删除 // System.out.println(map);//{a=a, b=b, c=c} System.out.println(map.get("s"));//ss,通过键获取值 System.out.println(map.containsKey("b"));//true System.out.println(map.containsValue("ss"));//true Set hset = map.keySet(); System.out.println(hset);//[a, b, s, c],把键存储在Set集合中,双链变单链 } } -
TreeMap
TreeMap中所有的元素都保持着某种固定的顺序,如果需要得到一个有序的Map就应该使用TreeMap,key值所在类必须实现Comparable接口。
public class TreeMapDemo { public static void main(String[] args) { TreeMaptset= new TreeMap<>(); tset.put("s","s"); tset.put("a","b"); tset.put("b","d"); tset.put("aa","ab"); tset.put("c","c"); tset.put("s","ss"); tset.put("x","d"); System.out.println(tset); } } -
HashTable
Hahstable是线程安全的但是它不能存储为null的键值,因为在底层没有对获取的哈希值进行处理判断
只有:int hash = key.hashCode()=>null.hashCode()显然会报错
public class EntryDemo {
public static void main(String[] args) {
HashMap hset = new HashMap<>();
hset.put("a","a");
hset.put("s","s");
hset.put("s","ss");
hset.put("b","c");
hset.put("c","d");
System.out.println(hset);
System.out.println("--------------------------");
//map遍历
//相当于两次操作
Set key = hset.keySet();
for(String a:key){
System.out.println(a+"->"+hset.get(a));
}
System.out.println("--------------------------");
//Map底层为了我们方便遍历,将键值对存放在一个Entry对象中,将多个Entry对象放入Set集合中
//建议像这样遍历:
Set> entrySet = hset.entrySet();
for(Map.Entry a:entrySet){
System.out.println(a.getKey()+"->"+a.getValue());
}
}
}
Collections类
- Collections是集合类的工具类,与数组的工具类Arrays类似.
addAll(Collection super T> c, T... elements);
binarySearch(List extends Comparable super T>> list, T key)
sort(List list)
sort(List list, Comparator super T> c)
swap(List> list, int i, int j)
copy(List super T> dest, List extends T> src) ; 注意 dest size需大于等于src.size emptyList() 返回为空的集合,不能添加数据
fill(List super T> list, T obj)
max(Collection extends T> coll)
min(Collection extends T> coll)
replaceAl l(List list, T oldVal, T newVal)
reverse(List> list)
public class CollectionsDemo {
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
Collections.addAll(list,"aa","bb","cc","dd","ee");
System.out.println(list);//[aa, bb, cc, dd, ee]
ArrayList list1 = new ArrayList<>();
list1.add(2);
list1.add(8);
list1.add(7);
list1.add(6);
list1.add(5);
list1.add(1);
list1.add(4);
list1.add(3);
// Collections.sort(list1);//排序1
// Collections.sort(list1, new Comparator() {//排序2,匿名内部类
// @Override
// public int compare(Integer o1, Integer o2) {
// return o1-o2;
// }
// });
Collections.sort(list1,(o1,o2)->{return o1-o2;});//排序3,Lambda表达式
System.out.println(Collections.binarySearch(list1,5));//二分查找,返回索引位置 4
ArrayList list2 = new ArrayList<>();
list2.add(2);
list2.add(2);
list2.add(2);
list2.add(2);
list2.add(2);
list2.add(2);
list2.add(2);
list2.add(2);
list2.add(2);
list2.add(2);
list2.add(2);
Collections.copy(list2,list1);//把list1的元素复制到list2集合,但是list2.size()需要>=list1.size(),否则会出现数组越界异常
System.out.println(list2);//[1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2]
Collections.fill(list2,0);//把集合list2全部填充为0
System.out.println(list2);//[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
System.out.println(Collections.max(list1));//返回list1中最大值8
System.out.println(list1);//[1, 2, 3, 4, 5, 6, 7, 8]
Collections.reverse(list1);//逆序
System.out.println(list1);//[8, 7, 6, 5, 4, 3, 2, 1]
}
}



