目录
- 一、什么是集合
- 二、Collection体系集合
- 2.1 Collection父接口
- 2.2 List实现类
- 2.2.1 ArrayList
- 2.2.2 LinkedList
- 2.2.3 不同结构的实现方式
- 2.3 Set子接口
- 2.4 Set的实现类
- 3.1.1 HashSet
- 3.1.2 TreeSet
- 三、Map集合
- 3.1 Map父接口
- 3.2 Map集合的实现类
- 3.2.1 HashMap
- 3.2.2 TreeMap
- 四、Collections工具类
一、什么是集合
- 概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能。
- 和数组的区别:
- 数组长度固定,集合长度不固定。
- 数组可以存储基本类型和引用类型,而集合只能存储引用类型。
- 位置:java.util.*;
集合有两个基本接口:Collection和Map。下面对这两个接口进行分析。
二、Collection体系集合
2.1 Collection父接口
- 特点:代表一组任意类型的对象,无序、无下标、不能重复。
- 方法:
-
boolean add(Object obj)
//添加一个对象 -
boolean addAll(Collection c)
//将一个集合中的所有对象添加到此集合中 -
void clear()
//清空此集合中的所有对象 -
boolean contains(Object o)
//检查此集合中是否包含o对象 -
boolean equals(Object o)
//比较此集合中是否与指定对象相等。 -
boolean isEmply()
//判断此集合是否为空 -
boolean remove(Object o)
//在此集合中移除o对象 -
int size()
//返回此集合中的元素个数 -
Object[] toArray()
//将此集合转换为数组
使用
/**
* Collection接口的使用
* @author: Radish
* @date: 2020-10-04 15:40
*/
public class collection {
public static void main(String[] args) {
//1 创建一个集合
Collection collection = new ArrayList();
//2 往集合中添加元素
collection.add("苹果");
collection.add("香蕉");
collection.add("葡萄");
System.out.println("个数:"+collection.size());
System.out.println(collection);
//3 删除元素
// collection.remove("苹果");
// collection.clear();
//4 遍历
//foreach
for (Object o : collection) {
System.out.println(o);
}
//使用迭代器
//hashNext();
//next();
//remove();
Iterator it = collection.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
// collection.remove(s); ConcurrentModificationException并发修改异常,不可同时使用
it.remove();
}
System.out.println(collection);
//5 判断
System.out.println(collection.contains("苹果"));
System.out.println(collection.isEmpty());
}
}
2.2 List实现类
- ArrayList:
- 数组结构实现,查询快、增删慢;
- JDK1.2版本,运行效率快、线程不安全。
- Vector:
- 数组结构实现,查询快、增删慢;
- JDK1.0版本,运行效率慢,线程安全。
- LinkedList:
- 链表结构实现,增删快,查询慢。
List子接口的使用
/**
* List子接口的使用
* 特点:1 有序有下标 2 可重复
*/
public class Demo3 {
public static void main(String[] args) {
//先创建集合对象
List list = new ArrayList<>();
list.add("苹果");
list.add("小米");
list.add(0,"华为");
System.out.println(list);
// list.remove(1);
//遍历
//1、使用for遍历
for (int i = 0; i < list.size();i++) {
System.out.println(list.get(i));
}
//2、foreach
for (Object o : list) {
System.out.println(o);
}
//3、迭代器
Iterator it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
//4、列表迭代器,和Iterator的区别:ListIterator可以向前或向后遍历,添加、删除、修改元素
ListIterator listIterator = list.listIterator();
System.out.println("-------使用列表迭代器从前往后--------");
while (listIterator.hasNext()) {
System.out.println(listIterator.nextIndex()+":"+listIterator.next());
}
//从后往前
System.out.println("-------使用列表迭代器从后往前--------");
while (listIterator.hasPrevious()) {
System.out.println(listIterator.previousIndex()+":"+listIterator.previous());
}
//判断 一样
//获取位置
System.out.println(list.indexOf("华为"));
}
}
注意:集合中只能放入引用类型,如果在集合中放入基本类型,它会自动装箱,变成一个包装类
2.2.1 ArrayList
使用
/**
* ArrayList的使用
*/
public class Demo5 {
public static void main(String[] args) {
//扩容原来的1.5倍
ArrayList arrayList = new ArrayList<>();
Student s1 = new Student("郭富城","21");
Student s2 = new Student("张国荣","23");
Student s3 = new Student("刘德华","24");
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println("元素个数"+arrayList.size());
System.out.println(arrayList);
arrayList.remove(new Student("刘德华","24")); //调用equals方法比较,重写后可用
System.out.println(arrayList);
System.out.println("----------使用迭代器---------");
Iterator it = arrayList.iterator();
while (it.hasNext()) {
Student student = (Student) it.next();
System.out.println(student);
}
System.out.println("----------使用列表迭代器(正序)---------");
ListIterator listIterator = arrayList.listIterator();
while (listIterator.hasNext()){
Student next = (Student) listIterator.next();
System.out.println(next);
}
System.out.println("----------使用列表迭代器(逆序)---------");
while (listIterator.hasPrevious()) {
Student stu = (Student) listIterator.previous();
System.out.println(stu);
}
//判断
System.out.println(arrayList.contains(new Student("张国荣", "23")));
System.out.println(arrayList.isEmpty());
//查找
System.out.println(arrayList.indexOf(new Student("张国荣","23")));
}
}
注意:代码中arrayList.contains(new Student("张国荣", "23"))
的contains方法和indexof方法以及remove方法本质上是equals方法进行比较,因此需重写equals方法才能实现
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(name, student.name) &&
Objects.equals(age, student.age);
}
源码分析
2.2.2 LinkedList
使用
public class Demo2 {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList<>();
Student s1 = new Student("郭富城","21");
Student s2 = new Student("张国荣","23");
Student s3 = new Student("刘德华","24");
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
System.out.println("元素个数:"+linkedList.size());
System.out.println(linkedList.toString());
linkedList.remove(new Student("张国荣","23"));
System.out.println(linkedList);
}
}
注意:代码中linkedList.remove(new Student("张国荣","23"))
的remove方法和indexof方法以及contains方法本质上是equals方法进行比较,因此需重写equals方法才能实现
源码分析
2.2.3 不同结构的实现方式
2.3 Set子接口
- 特点:无序、无下标、元素不可重复
- 方法:全部继承自Collection中的方法
Set接口的使用
/**
* 测试Set接口的使用
* 特点:无序,无下标 不能重复
* @author: Radish
* @date: 2020-10-05 13:59
*/
public class Demo1 {
public static void main(String[] args) {
//创建集合
Set<String> set = new HashSet<>();
set.add("小米");
set.add("华为");
set.add("苹果");
System.out.println(set);
//删除
set.remove("小米");
System.out.println(set);
//遍历
System.out.println("--------foreach---------");
for (String s : set) {
System.out.println(s);
}
System.out.println("--------使用迭代器---------");
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String next = it.next();
System.out.println(next);
}
}
}
2.4 Set的实现类
- HashSet:
- 基于HashCode实现元素不重复
- 当存入元素的哈希码相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入。
- TreeSet:
- 基于排列顺序实现元素不重复
- 实现了SortedSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则
- 通过CompareTo方法确定是否为重复元素。
3.1.1 HashSet
使用
/**
* HashSet集合的使用
* 存储结构:哈希表(数组+链表+红黑树)
* @author: Radish
* @date: 2020-10-05 14:15
*/
public class Demo2 {
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<String>();
hashSet.add("刘德华");
hashSet.add("周星驰");
hashSet.add("周润发");
hashSet.add("成龙");
System.out.println(hashSet);
hashSet.remove("成龙");
System.out.println(hashSet);
for (String s : hashSet) {
System.out.println(s);
}
Iterator<String> it = hashSet.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println(hashSet.contains("成龙"));
System.out.println(hashSet.isEmpty());
}
}
/**
* HashSet的使用
* 存储结构:哈希表(数组+链表+红黑树)
* 存储过程:
* (1)根据hashCode计算保存的位置,如果此位置为空,则直接保存,如果不为空执行第二步。
* (2)再执行equals方法,如果equals方法为true,则认为是重复,否则,形成链表
* @author: Radish
* @date: 2020-10-05 14:26
*/
public class Demo3 {
public static void main(String[] args) {
HashSet<Person> hashSet = new HashSet<Person>();
Person p1 = new Person("刘德华",22);
Person p2 = new Person("成龙",24);
Person p3 = new Person("周润发",23);
Person p4 = new Person("林志玲",21);
hashSet.add(p1);
hashSet.add(p2);
hashSet.add(p3);
hashSet.add(p4);
hashSet.add(new Person("刘德华",22));
System.out.println(hashSet);
System.out.println("删除后:");
hashSet.remove(new Person("刘德华",22));
System.out.println(hashSet);
System.out.println("-------------------");
for (Person person : hashSet) {
System.out.println(person);
}
System.out.println("-------------------");
Iterator<Person> iterator = hashSet.iterator();
while (iterator.hasNext()){
Person next = iterator.next();
System.out.println(next);
}
System.out.println(hashSet.contains(new Person("成龙", 24)));
System.out.println(hashSet.isEmpty());
}
}
注意:HashSet的存储过程:
(1)根据hashCode计算保存的位置,如果此位置为空,则直接保存,如果不为空执行第二步。
(2)再执行equals方法,如果equals方法为true,则认为是重复,否则,形成链表
因此,要想实现hashSet.add(new Person("刘德华",22));
不加入重复对象,需重写hashCode()和equals()
3.1.2 TreeSet
/**
* TreeSet的使用
* 存储结构:红黑树
* @author: Radish
* @date: 2020-10-05 15:08
*/
public class Demo4 {
public static void main(String[] args) {
TreeSet<String> treeSet = new TreeSet<String>();
treeSet.add("sdf");
treeSet.add("asdf");
treeSet.add("rtew");
treeSet.add("qrs");
System.out.println(treeSet);
treeSet.remove("sdf");
System.out.println(treeSet);
System.out.println("--------------");
for (String s : treeSet) {
System.out.println(s);
}
System.out.println("--------------");
Iterator<String> it = treeSet.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
treeSet.contains("sdf");
}
}
自动排序
/**
* 使用TreeSet保存数据
* 存储结构:红黑树
* 要求:元素必须实现Comparable接口
* @author: Radish
* @date: 2020-10-05 15:15
*/
public class Demo5 {
public static void main(String[] args) {
TreeSet<Person> treeSet = new TreeSet<Person>();
Person p1 = new Person("dfs",23);
Person p2 = new Person("hello",21);
Person p3 = new Person("good",22);
Person p4 = new Person("cat",24);
treeSet.add(p1);
treeSet.add(p2);
treeSet.add(p3);
treeSet.add(p4);
System.out.println(treeSet);
treeSet.remove(new Person("cat",24));
System.out.println(treeSet);
System.out.println("--------------");
for (Person person : treeSet) {
System.out.println(person);
}
System.out.println("--------------");
Iterator<Person> it = treeSet.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
注意:TreeSet存入的元素必须实现Comparable接口,若没有实现,则会报错
public class Person implements Comparable<Person>
也可以使用Comparator比较器实现定制比较
/**
* TreeSet集合的使用
* Comparator:实现定制比较(比较器)
* Comparable:可比较的
* @author: Radish
* @date: 2020-10-05 16:48
*/
public class Demo6 {
public static void main(String[] args) {
TreeSet<Person> treeSet = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
int n1 = o1.getAge() - o2.getAge();
int n2 = o1.getName().compareTo(o2.getName());
return n1 == 0? n2:n1;
}
});
Person p1 = new Person("dsf",23);
Person p2 = new Person("asg",21);
Person p3 = new Person("wer",23);
Person p4 = new Person("zcv",24);
treeSet.add(p1);
treeSet.add(p2);
treeSet.add(p3);
treeSet.add(p4);
System.out.println(treeSet);
}
}
三、Map集合
3.1 Map父接口
- 特点:存储一对数据(Key-Value),无序、无下标,键不可重复,值可以重复。
- 方法:
-
V put(K key, V value)
//将对象存入到集合中,关联键值。key重复则覆盖原值。 -
Object get(Object key)
//根据键获取对应的值 -
Set\<K\>
//返回所有的key -
Collection\<V\> values()
//返回包含所有值的Collection集合 -
Set\<Map.Entry\<K,V>>
//键值匹配的Set的集合
Map接口的使用
/**
* Map接口的使用
* 特点:(1)存储键值对 (2)键不能重复,值可以重复 (3)无序
* @author: Radish
* @date: 2020-10-05 17:07
*/
public class Demo1 {
public static void main(String[] args) {
//创建Map集合
Map<String, String> map = new HashMap<String,String>();
map.put("cn","中国");
map.put("usa","美国");
map.put("uk","英国");
map.put("usa","meiguo");
System.out.println(map);
//删除
map.remove("usa");
System.out.println(map);
//遍历
//使用keySet();
System.out.println("--------keySet()----------");
// Set<String> keySet = map.keySet();
for (String s : map.keySet()) {
System.out.println(s+":"+map.get(s));
}
//使用entrySet()方法
System.out.println("--------entrySet()-------");
Set<Map.Entry<String, String>> entrySet = map.entrySet();
for (Map.Entry<String, String> entry : entrySet) {
System.out.println(entry.getKey()+"-----"+entry.getValue());
}
//判断
System.out.println(map.containsKey("cn"));
System.out.println(map.containsValue("美国"));
}
}
3.2 Map集合的实现类
- HashMap:
- JDK1.2版本,线程不安全,运行效率快;允许用null作为key或是value.
- HashTable:
- JDK1.0版本,线程安全,运行效率慢;不允许null作为key或是value
- Properties:
- Hashtable的子类,要求key和value都是String。通常用于配置文件的读取。
- TreeMap:
- 实现了SortedMap接口(是Map的子接口),可以对key自动排序。
3.2.1 HashMap
使用
/**
* HashMap集合的使用
* 存储结构:哈希表(数组+链表+红黑树)
* 使用key的hashcode和equals作为重复依据
* @author: Radish
* @date: 2020-10-05 19:38
*/
public class Demo2{
public static void main(String[] args) {
HashMap<Student, String> hashMap = new HashMap<Student,String>();
//刚创建HashMap时没有添加元素 table=null size=0 目的是节省空间
Student s1 = new Student("牛顿","1234");
Student s2 = new Student("刘邦","124");
Student s3 = new Student("项羽","123");
hashMap.put(s1, "上海");
hashMap.put(s2, "深圳");
hashMap.put(s3, "广州");
hashMap.put(new Student("牛顿","1234"),"北京");
System.out.println(hashMap);
hashMap.remove(s1);
System.out.println(hashMap);
System.out.println("-------keySet-------");
for (Student student : hashMap.keySet()) {
System.out.println(student+"======"+hashMap.get(student));
}
System.out.println("-------entrySet-------");
for (Map.Entry<Student, String> entry : hashMap.entrySet()) {
System.out.println(entry.getKey()+"======"+entry.getValue());
}
System.out.println(hashMap.containsKey(s2));
System.out.println(hashMap.containsValue("广州"));
System.out.println(hashMap.isEmpty());
}
}
源码分析
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //hashMap初始容量大小
static final int MAXIMUM_CAPACITY = 1 << 30;//hashMap的数组最大容量
static final float DEFAULT_LOAD_FACTOR = 0.75f;//默认加载因子
static final int TREEIFY_THRESHOLD = 8;//jdk1.8 当链表长度大于8时,调整成红黑树
static final int UNTREEIFY_THRESHOLD = 6;//jdk1.8 当链表长度小于6时,调整成链表
static final int MIN_TREEIFY_CAPACITY = 64;//jdk1.8 当链表长度大于8时,并且集合元素个数大于等于64时,调整成红黑树
transient Node<K,V>[] table;//哈希表中的数组
size;//元素个数
总结:
(1)当HashMap刚创建时,table是null,为了节省空间,当添加第一个元素时,table容量调整为16
(2)当元素个数大于阈值(16*0.75=12)时,会进行扩容,扩容后大小为原来的2倍。目的是减少调整元素的个数
(3)jdk1.8 当每个链表长度大于8,并且数组元素个数大于等于64时,会调整为红黑树,目的是为了提高效率
(4)jdk1.8 当链表长度小于6时,调整成链表
(5)jdk1.8以前,链表是头插入,jdk1.8以后是尾插入
3.2.2 TreeMap
使用
/**
* TreeMap的使用
* 存储结构:红黑树
* @author: Radish
* @date: 2020-10-05 21:56
*/
public class Demo3 {
public static void main(String[] args) {
TreeMap<Student, String> treeMap = new TreeMap<Student, String>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getSno().compareTo(o2.getSno());
}
});
Student s1 = new Student("sfd","214");
Student s2 = new Student("xcvb","124");
Student s3 = new Student("erwt","456");
Student s4 = new Student("gfd","4532");
Student s5 = new Student("vcxb","346");
treeMap.put(s1, "广州");
treeMap.put(s2, "深圳");
treeMap.put(s3, "上海");
treeMap.put(s4, "东莞");
treeMap.put(s5, "惠州");
System.out.println(treeMap);
//删除
treeMap.remove(s1);
System.out.println(treeMap);
System.out.println("-------keySet--------");
//遍历
for (Student student : treeMap.keySet()) {
System.out.println(student+"==========="+treeMap.get(student));
}
System.out.println("-------entrySet--------");
for (Map.Entry<Student, String> entry : treeMap.entrySet()) {
System.out.println(entry.getKey()+"==============="+entry.getValue());
}
System.out.println(treeMap.containsKey(s2));
System.out.println(treeMap.containsValue("上海"));
}
}
四、Collections工具类
- 概念:集合工具类,定义了除了存取以外的集合常用方法
- 方法:
使用
/**
* 演示Collections工具类的使用
* @author: Radish
* @date: 2020-10-05 22:11
*/
public class Demo4 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(123);
list.add(23);
list.add(43);
list.add(25);
list.add(2);
System.out.println("=============排序前=============");
System.out.println(list);
//sort排序
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
System.out.println("=============排序后=============");
System.out.println(list);
//binarySearch 二分查找
int i = Collections.binarySearch(list, 2235);
System.out.println(i);
//copy复制
ArrayList<Integer> list2 = new ArrayList<>();
for (int k = 0; k < list.size(); k++) {
list2.add(0);
}
Collections.copy(list2, list);
System.out.println(list2);
//reverse反转
Collections.reverse(list);
System.out.println("反转之后"+list);
//shuffle 打乱
Collections.shuffle(list);
System.out.println("打乱之后"+list);
//补充:list转成数组
System.out.println("-------list转成数组-------");
Integer[] array = list.toArray(new Integer[0]);
System.out.println(array.length);
System.out.println(Arrays.toString(array));
//数组转成集合
System.out.println("-------数组转成集合-------");
String[] names = {"张三", "李四", "王五"};
//这个集合是一个受限的集合,不能增加和删除
List<String> list3 = Arrays.asList(names);
System.out.println(list3);
//把基本类型数组转成集合时,需要修改为包装类
Integer[] nums= {100,200,300,400,500};
List<Integer> list4 = Arrays.asList(nums);
System.out.println(list4);
}
}