Java的集合框架
1、 集合的概念
- 概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能(实现了对对象的操作)。
- 集合与数组的区别
- 数组长度固定,集合长度不固定。
- 数组可以存储基本类型和引用类型,集合只能存储引用类型。
- 位置:
java.util.*;
2、 Collection 体系集合

3、 Collection 接口
3.1 Collection父接口
- 特点:代表一组任意类型的对象,无序、无下标、不能重复。
- 方法:
boolean add(Object obj):添加一个对象boolean addAll(Collection c):将一个结合中的所有对象添加到此集合中void clear():清空此集合中的所有对象boolean contains(Object o):检查此集合中是否包含o对象boolean equals(Object o):比较此集合是否与指定对象相等boolean isEmpty():判断此集合是否为空boolean remove(Object o):在此集合中移除o对象int size():返回此集合中的元素个数Object[] toArray():将此集合转换成数组
3.2 案例(一)
package com.goshawk.chapter_02.section_7;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* Collection接口的使用
* (1)添加元素
* (2)删除元素
* (3)遍历元素
* (4)判断
*/
public class Demo1 {
public static void main(String[] args) {
// 创建集合
Collection collection = new ArrayList();
// 添加元素
collection.add("苹果");
collection.add("香蕉");
collection.add("榴莲");
collection.add("西瓜");
System.out.println("元素个数:"+collection.size());
System.out.println(collection);
// 删除元素
collection.remove("榴莲");
System.out.println("删除之后:"+collection.size());
// 遍历
// 增强for
for (Object object : collection){
System.out.println(object);
}
// 使用迭代器(迭代器专门用来遍历集合的一种方式)
// hasNext() 有没有下一个元素
// next() 获取下一个元素
// remove() 删除当前元素
Iterator it = collection.iterator();
while (it.hasNext()){
String s = (String) it.next();
System.out.println(s);
// collection.remove(s); 不能使用collection删除方法,否则会抛出并发修改异常
it.remove();
}
System.out.println("元素个数:"+collection.size());
// 判断
System.out.println(collection.contains("西瓜"));
System.out.println(collection.isEmpty());
}
}
3.3 案例(二)
package com.goshawk.chapter_02.section_7;
public class Student {
private String name;
private int age;
public Student(){}
public Student(String name, int age) {
super();
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 +
'}';
}
}
package com.goshawk.chapter_02.section_7;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* Collection的使用:保存学生信息
*/
public class Demo2 {
public static void main(String[] args) {
// 创建Collection对象
Collection collection = new ArrayList();
Student s1 = new Student("张三", 20);
Student s2 = new Student("李四", 21);
// 添加数据
collection.add(s1);
collection.add(s2);
System.out.println("元素个数:"+collection.size());
System.out.println(collection.toString());
// 删除
// collection.remove(s1);
// collection.remove(new Student("李四", 21));
// collection.clear();
// System.out.println("删除之后:"+collection.size());
// 遍历
// 增强for
for (Object obejct : collection) {
Student s = (Student) obejct;
System.out.println(s.toString());
}
// 迭代器 : hasNext() next() remove() ;迭代过程中不能使用collection的删除方法
Iterator it = collection.iterator();
while (it.hasNext()){
Student s = (Student) it.next();
System.out.println(s.toString());
}
// 判断是否存在
System.out.println(collection.contains(s1));
System.out.println(collection.isEmpty());
}
}
4、 List 集合
4.1 List子接口
- 特点:有序、有下标、元素可以重复
- 方法:
void add(int index, Object o):在index位置插入对象oboolean addAll(int index, Collection c):将一个集合中的元素添加到此集合中的index位置。Object get(int index):返回集合中指定位置的元素List subList(int fromIndex, int toIndex):返回fromIndex和toIndex之间的集合元素。
4.1.1 案例(一)
package com.goshawk.chapter_02.section_8;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* List子接口的使用
*/
public class Demo1 {
public static void main(String[] args) {
// 创建集合对象
List list = new ArrayList<>();
// 添加元素
list.add("苹果");
list.add("小米");
list.add("华为");
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());
// 删除元素
// list.remove("苹果");
list.remove(0);
System.out.println("删除之后:"+list.size());
System.out.println(list.toString());
// 遍历
// 使用for遍历
for (int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
// 增强for
for (Object object : list) {
System.out.println(object);
}
// 迭代器
Iterator it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
// 使用列表迭代器,和Iterator的区别:ListIterator可以向前或向后遍历,添加、删除、修改元素
ListIterator list1 = list.listIterator();
System.out.println("使用列表迭代器从前往后");
while (list1.hasNext()){
System.out.println(list1.nextIndex()+":"+list1.next());
}
System.out.println("使用列表迭代器从后往前");
while (list1.hasPrevious()){
System.out.println(list1.previousIndex()+":"+list1.previous());
}
// 判断
System.out.println(list.contains("苹果"));
System.out.println(list.isEmpty());
// 获取位置
System.out.println(list.indexOf("华为"));
}
}
4.1.2 案例(二)
package com.goshawk.chapter_02.section_8;
import java.util.ArrayList;
import java.util.List;
public class Demo2 {
public static void main(String[] args) {
// 创建集合
List list = new ArrayList();
// 添加数字数据(自动装箱)
list.add(20);
list.add(30);
list.add(40);
list.add(50);
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());
// 删除操作
// list.remove(0);
// list.remove((Object) 20);
list.remove(new Integer(20));
System.out.println("删除之后:"+list.size());
System.out.println(list.toString());
// subList() 返回子集合,含头不含尾
List subList = list.subList(1, 3);
System.out.println(subList.toString());
}
}
4.2 List 实现类
ArrayList:- 数组结构实现,查询快、增删慢;
JDK1.2版本,运行效率快、线程不安全。
Vector:- 数组结构实现,查询快、增删慢;
JDK1.0版本,运行效率慢、线程安全。
LinkedList:- 链表结构实现,增删快、查询慢。
4.2.1 ArrayList的使用
4.2.1.1 案例(一)
package com.goshawk.chapter_02.section_7;
public class Student {
private String name;
private int age;
public Student(){}
public Student(String name, int age) {
super();
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 +
'}';
}
public boolean equals(Object obj){
// 判断是不是同一个对象
if (this==obj){
return true;
}
// 判断是否为空
if (obj==null){
return false;
}
// 判断是否是Student类型
if (obj instanceof Student){
Student s = (Student) obj;
// 比较属性
if (this.name.equals(s.getName())&&this.age==s.getAge()){
return true;
}
}
// 不满足
return false;
}
}
package com.goshawk.chapter_02.section_8;
import com.goshawk.chapter_02.section_7.Student;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
/**
* ArrayList的使用
* 存储结构:数组,查找遍历速度快,查询慢
*/
public class Demo3 {
public static void main(String[] args) {
// 创建集合
ArrayList arrayList = new ArrayList<>();
// 添加元素
Student s1 = new Student("刘德华", 20);
Student s2 = new Student("郭富城", 21);
Student s3 = new Student("梁朝伟", 22);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println("元素个数:"+arrayList.size());
System.out.println(arrayList.toString());
// 删除元素
arrayList.remove(s1);
/**
* arrayList.remove(new Student("刘德华", 20));
* 这种方式为什么删除不掉。因为在进行equals(this==obj)是取地址来进行比较的
* 如果想要使用这种方式删除,则需要重写equals方法
*/
System.out.println("删除之后:"+arrayList.size());
// 遍历元素
// 使用迭代器
Iterator it = arrayList.iterator();
while (it.hasNext()){
Student s = (Student) it.next();
System.out.println(s.toString());
}
// 列表迭代器
ListIterator lit = arrayList.listIterator();
while (lit.hasNext()){
Student s = (Student) lit.next();
System.out.println(s.toString());
}
// 逆序列表迭代器
while (lit.hasPrevious()){
Student s = (Student) lit.previous();
System.out.println(s.toString());
}
// 判断
System.out.println(arrayList.contains(new Student("梁朝伟",22)));
System.out.println(arrayList.isEmpty());
// 查找
System.out.println(arrayList.indexOf(new Student("梁朝伟", 22)));
}
}
4.2.1.2 ArrayList源码分析
默认容量:
DEFAULT_CAPACITY = 10如果没有向集合中添加任何元素时,则容量为0;添加一个元素之后,则容量为10;
扩容:每次扩容的大小是原来的1.5倍。
存放元素的数组:
elementData实际元素个数:
size




4.2.2 Vector的使用
4.2.2.1 案例(一)
package com.goshawk.chapter_02.section_9;
import java.util.Enumeration;
import java.util.Vector;
/**
* Vector集合的使用
* 存储结构:数组
*/
public class Demo1 {
public static void main(String[] args) {
// 创建集合
Vector vector = new Vector<>();
// 添加元素
vector.add("草莓");
vector.add("芒果");
vector.add("西瓜");
System.out.println("元素个数:"+vector.size());
// 删除
// vector.remove(0);
// vector.remove("西瓜");
// vector.clear();
// 遍历
// 使用枚举器
Enumeration en = vector.elements();
while (en.hasMoreElements()){
String o = (String) en.nextElement();
System.out.println(o);
}
// 判断
System.out.println(vector.contains("西瓜"));
System.out.println(vector.isEmpty());
// Vector其他方法
// firsetElement lastElement ElementAt()
}
}
4.2.3 LinkedList的使用
4.2.3.1 案例(一)
package com.goshawk.chapter_02.section_7;
public class Student {
private String name;
private int age;
public Student(){}
public Student(String name, int age) {
super();
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 +
'}';
}
public boolean equals(Object obj){
// 判断是不是同一个对象
if (this==obj){
return true;
}
// 判断是否为空
if (obj==null){
return false;
}
// 判断是否是Student类型
if (obj instanceof Student){
Student s = (Student) obj;
// 比较属性
if (this.name.equals(s.getName())&&this.age==s.getAge()){
return true;
}
}
// 不满足
return false;
}
}
package com.goshawk.chapter_02.section_9;
import com.goshawk.chapter_02.section_7.Student;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
/**
* LinkedList的使用
* 存储接口:双向链表
*/
public class Demo2 {
public static void main(String[] args) {
// 创建集合
LinkedList linkedList = new LinkedList<>();
// 添加元素
Student s1 = new Student("刘德华", 18);
Student s2 = new Student("郭富城", 19);
Student s3 = new Student("梁朝伟", 20);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
linkedList.add(s3);
System.out.println("元素个数:"+linkedList.size());
System.out.println(linkedList.toString());
// 删除
// linkedList.remove(s3);
// linkedList.remove(new Student("刘德华", 18));
// 遍历
// for遍历
for (int i=0;i<linkedList.size();i++){
System.out.println(linkedList.get(i));
}
// 增强for
for (Object object : linkedList){
Student s = (Student) object;
System.out.println(s.toString());
}
// 使用迭代器
Iterator it = linkedList.iterator();
while (it.hasNext()){
Student s = (Student) it.next();
System.out.println(s.toString());
}
// 列表迭代器
ListIterator lit = linkedList.listIterator();
while (lit.hasNext()){
Student s = (Student) lit.next();
System.out.println(s.toString());
}
// 判断
System.out.println(linkedList.contains(s1));
System.out.println(linkedList.isEmpty());
// 获取
System.out.println(linkedList.indexOf(s1));
}
}
4.2.3.2 LinkedList源码分析
sizefirstlast



4.2.4 ArrayList与LinkedList的区别
- 不同结构实现方式

ArrayList:必须开辟连续空间,查询快,增删慢。LinkedList:无需开辟连续空间,查询慢,增删快。
5、 泛型和工具类
5.1 泛型概述
Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。- 常见形式有泛型类、泛型接口、泛型方法。
- 语法:
<T,...>:T称为类型占位符,表示一种引用类型。
- 优点:
- 提高代码的复用性
- 防止类型转换异常,提高 代码的安全性
5.2 泛型类
5.2.1 案例(一)
package com.goshawk.chapter_02.section_10;
import java.security.PublicKey;
/**
* 泛型类
* 语法:类名<T>
* T 是类型占位符,表示一种引用类型,如果编写多个使用逗号隔开
*/
public class MyGeneric<T> {
// 使用泛型T
// 创建变量
T t;
// 泛型作为方法的参数
public void show(T t){
System.out.println(t);
}
// 泛型作为方法的返回值
public T getT(){
return t;
}
}
package com.goshawk.chapter_02.section_10;
public class TestMyGeneric {
public static void main(String[] args) {
// 使用过泛型类创建对象
/**
* 注意:
* 1、泛型只能使用引用类型
* 2、不同泛型类型对象之间不能相互复制
*/
MyGeneric<String> myGeneric = new MyGeneric<>();
myGeneric.t = "hello";
myGeneric.show("大家好");
String string = myGeneric.getT();
MyGeneric<Integer> myGeneric1 = new MyGeneric<Integer>();
myGeneric1.t = 100;
myGeneric1.show(200);
Integer integer = myGeneric1.getT();
// MyGeneric<String> myGeneric2 = myGeneric1; 不同泛型类型对象之间不能相互复制,因为myGeneric1上面已经声明了MyGeneric<Integer> myGeneric1
}
}
5.3 泛型接口
5.3.1 案例(一)
- 创建一个接口
GenericInterface:
package com.goshawk.chapter_02.section_10;
/**
* 泛型接口
* 语法:接口名<T>
* 注意:不能泛型静态常量
* @param <T>
*/
public interface GenericInterface<T> {
String name = "张三";
T server(T t);
}
- 创建接口的实现类
GenericInterfaceImp:
package com.goshawk.chapter_02.section_10;
public class GenericInterfaceImp implements GenericInterface<String>{
@Override
public String server(String t) {
System.out.println(t);
return t;
}
}
- 创建第二个接口的实现类
GenericInterfaceImp1:
package com.goshawk.chapter_02.section_10;
public class GenericInterfaceImp1<T> implements GenericInterface<T>{
@Override
public T server(T t) {
System.out.println(t);
return t;
}
}
- 测试实现类
package com.goshawk.chapter_02.section_10;
public class TestGenericInterfaceImp {
public static void main(String[] args) {
GenericInterfaceImp imp1 = new GenericInterfaceImp();
imp1.server("abcd");
GenericInterfaceImp1<Integer> imp2 = new GenericInterfaceImp1<>();
imp2.server(1000);
}
}
5.4 泛型方法
- 应用:方法不确定传入的参数类型
package com.goshawk.chapter_02.section_10;
/**
* 泛型方法
* 语法;<T> 返回值类型
*/
public class GenericMethod {
// 泛型方法
public <T> void show(T t){
System.out.println("泛型方法");
}
public <T> T show1(T t){
System.out.println("泛型方法:" + t);
return t;
}
}
package com.goshawk.chapter_02.section_10;
public class TestGenericMethod {
public static void main(String[] args) {
GenericMethod genericMethod = new GenericMethod();
// 类型由传入的参数决定
genericMethod.show("今天天气雨天");
genericMethod.show(200);
genericMethod.show(3.14);
}
}
5.5 泛型集合
- 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
- 特点:
- 编译时即可检查,而非运行时抛出异常。
- 访问时,不必类型转换(拆箱)。
- 不同泛型之间引用不能相互赋值,泛型不存在多态。
5.5.1 案例(一)
- 无效案例
package com.goshawk.chapter_02.section_10;
import java.util.ArrayList;
/**
* 泛型集合 - 抛出异常
*/
public class GenericCollection {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList<>();
arrayList.add("xxx");
arrayList.add("yyy");
arrayList.add(10);
for(Object object : arrayList){
String str = (String) object;
System.out.println(str);
}
}
}
- 有效案例
package com.goshawk.chapter_02.section_10;
import com.goshawk.chapter_02.section_7.Student;
import java.util.ArrayList;
import java.util.Iterator;
/**
* 泛型集合
*/
public class GenericCollection {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("xxx");
arrayList.add("yyy");
// arrayList.add(10);
for(String string : arrayList){
System.out.println(string);
}
// 确定使用类型
ArrayList<Student> arrayList1 = new ArrayList<Student>();
Student s1 = new Student("刘德华", 20);
arrayList1.add(s1);
Iterator<Student> it = arrayList1.iterator();
while (it.hasNext()){
Student s = it.next();
System.out.println(s.toString());
}
}
}
6、Set 集合
6.1 Set的使用
package com.goshawk.chapter_02.section_11;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* Set接口的使用
* 特点:无序、没有下标、不能重复
*/
public class Demo1 {
public static void main(String[] args) {
// 创建集合
Set<String> set = new HashSet<>();
// 添加数据
set.add("苹果");
set.add("华为");
set.add("小米");
System.out.println("数据个数:"+set.size());
System.out.println(set.toString());
// 删除
// set.remove("小米");
// System.out.println(set.toString());
// 遍历
// 使用增强for
for (String string : set){
System.out.println(string);
}
// 使用迭代器
Iterator<String> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
// 判断
System.out.println(set.contains("华为"));
System.out.println(set.isEmpty());
}
}
6.2 Set子接口
- 特点:无序、无下标、元素不可重复。
- 方法:全部继承自
Collection中的方法。
6.3、Set实现类
HashSet:- 基于
HashCode实现元素不重复。 - 当存入元素的哈希码相同时,会调用
equals进行确认,如结果为true,则拒绝后者存入。
- 基于
TreeSet:- 基于排列顺序实现元素不重复。
- 实现了
SortedSet接口,对集合元素自动排列。 - 元素对象的类型必须实现
Comparable接口,指定排序规则。 - 通过
CompareTo方法确定是否为重复元素。
6.3.1 HashSet的使用
6.3.1.1 案例(一)
package com.goshawk.chapter_02.section_11;
import java.util.HashSet;
import java.util.Iterator;
/**
* HashSet集合的使用
* 存储结构:哈希表(数组+链表+红黑树)
*/
public class Demo2 {
public static void main(String[] args) {
// 创建集合
HashSet<String> hashSet = new HashSet<String>();
// 添加元素
hashSet.add("刘德华");
hashSet.add("梁朝伟");
hashSet.add("郭富城");
System.out.println("元素个数:"+hashSet.size());
System.out.println(hashSet.toString());
// 删除
// hashSet.remove("刘德华");
// System.out.println("删除之后:"+hashSet.size());
// 遍历
// 增强for
for (String string : hashSet){
System.out.println(string);
}
// 使用迭代器
Iterator<String> it = hashSet.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
// 判断
System.out.println(hashSet.contains("刘德华"));
System.out.println(hashSet.isEmpty());
}
}
6.3.1.2 案例(二)
package com.goshawk.chapter_02.section_11;
import java.util.Objects;
public class Person {
private String name;
private int age;
public Person(){
}
public Person(String name, int age) {
super();
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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
/**
* 第一种重写方式
@Override
public int hashCode() {
int n1 = this.name.hashCode();
int n2 = this.age;
return n1+n2;
}
@Override
public boolean equals(Object obj) {
if (this==obj){
return true;
}
if (obj==null){
return false;
}
if (obj instanceof Person){
Person p = (Person) obj;
if (this.name.equals(p.getName())&&this.age==p.getAge()){
return true;
}
}
return false;
}
*/
// 第二种重写方式
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
if (age != person.age) return false;
if (name == null){
if (person.name != null) return false;
} else if (!name.equals(person.name))
return false;
return true;
}
@Override
public int hashCode() {
// (1)31是一个质数(可以被1和本身整除),尽量减少散列冲突
// (2)31可以提高执行效率 31*i=(i<<5)-i --> 表示i左移5位,当i=2时即等同于2的6次方
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
}
package com.goshawk.chapter_02.section_11;
/**
* HashSet的使用
*
* 存储过程(重复依据):
* (1)根据hashcode计算保存的位置,如果此位置为空,则直接保存,如果不为空执行第二步。
* (2)再执行equals方法,如果equals方法返回为true,则认为是重复,否则形成链表。
*/
import java.util.HashSet;
import java.util.Iterator;
public class Demo3 {
public static void main(String[] args) {
// 创建集合
HashSet<Person> persons = new HashSet<>();
// 添加数据
Person p1 = new Person("刘德华", 18);
Person p2 = new Person("林志玲", 19);
Person p3 = new Person("梁朝伟", 20);
persons.add(p1);
persons.add(p2);
persons.add(p3);
persons.add(new Person("梁朝伟", 20)); // 没有重写equals之前是可以添加重复,重写之后是不能添加重复的 判断名称与年龄一样即表示重复
System.out.println("元素个数:"+persons.size());
System.out.println(persons.toString());
// 删除操作
// persons.remove(p1);
// persons.remove(new Person("刘德华", 18)); // 重写equals之前这种方式是不能删除的
// System.out.println("删除之后:"+persons.size());
// 遍历
// 增强for
for (Person person : persons){
System.out.println(person.toString());
}
// 迭代器
Iterator<Person> it = persons.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
// 判断
System.out.println(persons.contains(p1));
System.out.println(persons.contains(new Person("刘德华", 18))); // 此时这种方式也是可以判断的,因为已经重写了haseCode与equals
System.out.println(persons.isEmpty());
}
}
6.3.2 TreeSet的使用
6.3.2.1 案例(一)
package com.goshawk.chapter_02.section_11;
import java.util.Iterator;
import java.util.TreeSet;
/**
* TreeSet的使用
* 存储结构:红黑树
*/
public class Demo4 {
public static void main(String[] args) {
// 创建集合
TreeSet<String> treeSet = new TreeSet<>();
// 添加元素
treeSet.add("xxx");
treeSet.add("yyy");
treeSet.add("abc");
System.out.println("元素个数:"+treeSet.size());
System.out.println(treeSet.toString());
// 删除
treeSet.remove("xxx");
System.out.println("删除之后:"+treeSet.toString());
// 遍历
// 增强for
for (String string : treeSet){
System.out.println(string);
}
// 迭代器
Iterator<String> it = treeSet.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
// 判断
System.out.println(treeSet.contains("abc"));
}
}
6.3.2.2 案例(二)
package com.goshawk.chapter_02.section_11;
import java.util.Objects;
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person(){
}
public Person(String name, int age) {
super();
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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
/**
* 第一种重写方式
@Override
public int hashCode() {
int n1 = this.name.hashCode();
int n2 = this.age;
return n1+n2;
}
@Override
public boolean equals(Object obj) {
if (this==obj){
return true;
}
if (obj==null){
return false;
}
if (obj instanceof Person){
Person p = (Person) obj;
if (this.name.equals(p.getName())&&this.age==p.getAge()){
return true;
}
}
return false;
}
*/
// 第二种重写方式
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
if (age != person.age) return false;
if (name == null){
if (person.name != null) return false;
} else if (!name.equals(person.name))
return false;
return true;
}
@Override
public int hashCode() {
// (1)31是一个质数(可以被1和本身整除),尽量减少散列冲突
// (2)31可以提高执行效率 31*i=(i<<5)-i --> 表示i左移5位,当i=2时即等同于2的6次方
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
// 先按姓名比较,再按年龄比较
@Override
public int compareTo(Person o) {
int n1 = this.getName().compareTo(o.getName());
int n2 = this.age-o.getAge();
return n1==0?n2:n1;
}
}
package com.goshawk.chapter_02.section_11;
import java.util.Iterator;
import java.util.TreeSet;
/**
* 使用TreeSet保存数据
* 存储结构:红黑数
* 要求:元素必须要实现Comparable接口,compareTo()方法返回值为0,认为是重复元素
*/
public class Demo5 {
public static void main(String[] args) {
// 创建集合
TreeSet<Person> peoples = new TreeSet<>();
// 添加元素
Person p1 = new Person("刘德华", 18);
Person p2 = new Person("梁朝伟", 19);
Person p3 = new Person("林志玲", 20);
peoples.add(p1);
peoples.add(p2);
peoples.add(p3);
System.out.println("元素个数:"+peoples.size());
System.out.println(peoples.toString());
// 删除
peoples.remove(p1);
System.out.println("删除之后:"+peoples.size());
// 遍历
// 增强for
for (Person person : peoples){
System.out.println(person.toString());
}
// 迭代器
Iterator<Person> it = peoples.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
// 判断
System.out.println(peoples.contains(p1));
System.out.println(peoples.contains(new Person("刘德华", 18)));
}
}
6.3.2.3 案例(三)–> Comparator 接口
package com.goshawk.chapter_02.section_11;
import java.util.Objects;
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person(){
}
public Person(String name, int age) {
super();
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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
if (age != person.age) return false;
if (name == null){
if (person.name != null) return false;
} else if (!name.equals(person.name))
return false;
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
// 先按姓名比较,再按年龄比较
@Override
public int compareTo(Person o) {
int n1 = this.getName().compareTo(o.getName());
int n2 = this.age-o.getAge();
return n1==0?n2:n1;
}
}
package com.goshawk.chapter_02.section_11;
import java.util.Comparator;
import java.util.TreeSet;
/**
* TreeSet集合的使用
* Comparator:实现定制比较(比较器)
* Comparable:可比较的
*/
public class Demo6 {
public static void main(String[] args) {
// 创建集合,并指定比较规则
TreeSet<Person> peoples = 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("xyz", 18);
Person p2 = new Person("abc", 19);
Person p3 = new Person("zhangsan", 20);
Person p4 = new Person("lisi", 20);
peoples.add(p1);
peoples.add(p2);
peoples.add(p3);
peoples.add(p4);
System.out.println(peoples.toString());
}
}
6.3.2.4 案例(四)
package com.goshawk.chapter_02.section_11;
import java.util.Comparator;
import java.util.TreeSet;
/**
* 要求:使用TreeSet结合实现字符串按照长度进行排序
* helloword zhangsan lisi wangwu beijing shanghai nanjing xian
* Comparator接口实现定制比较
*/
public class Demo7 {
public static void main(String[] args) {
// 创建集合,并指定比较规则
TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int n1 = o1.length()-o2.length();
int n2 = o1.compareTo(o2);
return n1 == 0?n2:n1;
}
});
// 添加数据
treeSet.add("helloword");
treeSet.add("zhangsan");
treeSet.add("lisi");
treeSet.add("wangwu");
treeSet.add("beijing");
treeSet.add("nanjing");
treeSet.add("shanghai");
treeSet.add("xian");
System.out.println(treeSet.toString());
}
}
7、Map 体系集合

7.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集合。
7.1.1 案例(一)

package com.goshawk.chapter_02.section_12;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map接口的使用
* 特点:
* (1)存储键值对
* (2)键不能重复,值可以重复
* (3)无序
*/
public class Demo1 {
public static void main(String[] args) {
// 创建Map集合
Map<String, String> map = new HashMap<>();
// 添加元素
map.put("cn", "中国");
map.put("uk", "英国");
map.put("usa", "美国");
map.put("cn", "zhongguo"); // 添加重复,会替换之前的值
System.out.println("元素个数:"+map.size());
System.out.println(map.toString());
// 删除
// map.remove("usa");
// System.out.println("删除之后:"+map.size());
// 遍历
// 使用keySet()
for (String key : map.keySet()){
System.out.println(key+": "+map.get(key));
}
// 等同于上方的代码
Set<String> keyset = map.keySet();
for (String key : keyset){
System.out.println(key+": "+map.get(key));
}
// 使用entrySet()
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries){
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 等同于上方的代码
for (Map.Entry<String, String> entry : map.entrySet()){
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 判断
System.out.println(map.containsKey("cn"));
System.out.println(map.containsValue("泰国"));
}
}
7.2 Map集合的实现类
HashMap:JDK1.2版本,线程不安全,运行效率快;允许用null作为key或者value。
Hashtable:JDK1.0版本,线程安全,运行效率慢;不允许null作为key或是value。
Properties:Hashtable的子类,要求key和value都是String。通常用于配置文件的读取。
TreeMap:- 实现了
SortrfMap接口(是Map的子接口),可以对key自动排序。
- 实现了
7.2.1 HashMap的使用
7.2.1.1 案例(一)
package com.goshawk.chapter_02.section_12;
import java.util.Objects;
public class Student {
private String name;
private int stuNo;
public Student(){
}
public Student(String name, int stuNo) {
super();
this.name = name;
this.stuNo = stuNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getStuNo() {
return stuNo;
}
public void setStuNo(int stuNo) {
this.stuNo = stuNo;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", stuNo=" + stuNo +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return stuNo == student.stuNo && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, stuNo);
}
}
package com.goshawk.chapter_02.section_12;
import java.util.HashMap;
import java.util.Map;
/**
* HashMap集合的使用
* 存储结构:哈希表(数组+链表+红黑树)
*
* 使用key的hashCode()和equals()作为重复依据
*/
public class Demo2 {
public static void main(String[] args) {
// 创建集合
HashMap<Student, String> students = new HashMap<Student, String>();
// 添加元素
Student s1 = new Student("孙一", 100);
Student s2 = new Student("孙二", 101);
Student s3 = new Student("孙三", 102);
students.put(s1, "北京");
students.put(s2, "上海");
students.put(s3, "杭州");
// students.put(s3. "南京"); 重复
students.put(new Student("孙三", 102), "杭州");
System.out.println("元素个数:"+students.size());
System.out.println(students.toString());
// 删除
students.remove(s1);
System.out.println("删除之后:"+students.size());
// 遍历
// 使用keySet() 进行遍历
for (Student key : students.keySet()){
System.out.println(key.toString() + ": " + students.get(key));
}
// 使用entrySet() 进行遍历
for (Map.Entry<Student, String> entry : students.entrySet()){
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 判断
System.out.println(students.containsKey(s1));
System.out.println(students.containsKey(new Student("孙一", 100)));
System.out.println(students.containsValue("杭州"));
}
}
7.2.2 HashMap 源码分析
hashMap默认的初始容量大小:16。hashMap的数组最大容量大小:2的30次方。默认加载因子:
0.75f,大于这个值说明需要扩容。树的阈值:
TREEIFY_THRESHOLD = 8:jdk1.8链表的长度大于8时,并且数组的长度大于64,就会把链表调整成红黑树。不可恢复阈值:
UNTREEIFY_THRESHOLD = 6:jdk1.8当链表长度小于6时,调整为链表。最小的容量大小:
MIN_TREEIFY_CAPACITY = 64:jdk1.8当链表长度大于8时,并且集合元素个数大于等于64时,调整成红黑树。transient Node<K, V>[] table;:哈希表中的数组。size:元素个数。无参构造
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
// 创建集合
HashMap<Student, String> students = new HashMap<Student, String>();
// 刚创建hashmap之后没有添加元素table=null size=0;目的是为了节省空间
- 添加元素
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
(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以后是尾插入。
7.2.3 TreeMap 的使用
7.2.3.1 案例(一)
package com.goshawk.chapter_02.section_12;
import java.util.Objects;
public class Student implements Comparable<Student>{
private String name;
private int stuNo;
public Student(){
}
public Student(String name, int stuNo) {
super();
this.name = name;
this.stuNo = stuNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getStuNo() {
return stuNo;
}
public void setStuNo(int stuNo) {
this.stuNo = stuNo;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", stuNo=" + stuNo +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return stuNo == student.stuNo && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, stuNo);
}
@Override
public int compareTo(Student o) {
int n2 = this.stuNo-o.getStuNo();
return n2;
}
}
package com.goshawk.chapter_02.section_12;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
/**
* TreeMap的使用
* 存储结构:红黑树
*/
public class Demo3 {
public static void main(String[] args) {
// 创建集合
TreeMap<Student, String> treeMap = new TreeMap<Student, String>();
/**
* 定制比较
TreeMap<Student, String> treeMap1 = new TreeMap<Student, String>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return 0;
}
});
*/
// 添加元素
Student s1 = new Student("孙一", 100);
Student s2 = new Student("孙二", 101);
Student s3 = new Student("孙三", 102);
treeMap.put(s1, "北京");
treeMap.put(s2, "上海");
treeMap.put(s3, "深圳");
treeMap.put(new Student("孙三", 102), "南京"); // 替换
System.out.println("元素个数:"+treeMap.size());
System.out.println(treeMap.toString());
// 删除
// treeMap.remove(s3);
// treeMap.remove(new Student("孙二", 101));
// System.out.println("删除之后:"+treeMap.size());
// 遍历
// 使用keySet()进行遍历
for (Student key : treeMap.keySet()){
System.out.println(key + ": " + treeMap.get(key));
}
// 使用entrySet()进行遍历
for (Map.Entry<Student, String> entry : treeMap.entrySet()){
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 判断
System.out.println(treeMap.containsKey(new Student("孙三", 102)));
}
}
8、Collections 工具类
- 概念:集合工具类,定义了除了存取以外的集合常用方法。
- 方法:
public static void reverse(List<?> list):反转集合中元素的顺序。public static void shuffle(List<?> list):随机重置集合元素的顺序。public static void sort(List<T>, list):升序排序(元素类型必须实现Comparable接口)。
8.1 案例(一)
package com.goshawk.chapter_02.section_12;
import java.util.*;
/**
* Collections 工具类的使用
*/
public class Demo4 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(20);
list.add(5);
list.add(13);
list.add(56);
list.add(4);
// sort() 排序
System.out.println("排序之前:"+list.toString());
Collections.sort(list);
System.out.println("排序之后:"+list.toString());
// binarySearch
int i = Collections.binarySearch(list, 14); // 返回负数 表示没有找到
System.out.println(i);
// copy() 复制
List<Integer> dest = new ArrayList<>();
for (int k=0;k<list.size();k++){
dest.add(0);
}
Collections.copy(dest, list);
System.out.println(dest.toString());
// reverse() 反转
Collections.reverse(list);
System.out.println("反转之后:"+list);
// shuffle 打乱
Collections.shuffle(list);
System.out.println("打乱之后:"+list);
// list转成数组
Integer[] arr = list.toArray(new Integer[10]);
System.out.println(arr.length);
System.out.println(Arrays.toString(arr));
// 数组转成集合
String[] names = {"张三", "李四", "王武"};
// 这个集合是一个受限集合,不能添加和删除
List<String> list2 = Arrays.asList(names);
System.out.println(list2);
// 把基本类型数组转成集合时,需要修改为包装类型
// int[] nums1 = {100, 200, 300, 400, 500};
// List<int[]> list3 = Arrays.asList(nums1); 类型不只是数字
Integer[] nums = {100, 200, 300, 400, 500};
List<Integer> list4 = Arrays.asList(nums);
System.out.println(list4);
}
}
9、集合总结
- 集合的概念
- 对象的容器,和数组类似,定义了对多个对象进行操作的常用方法。
List集合- 有序、有下标、元素可以重复。(
ArrayList、LinkedList、Vector)
- 有序、有下标、元素可以重复。(
Set集合- 无序、无下标、元素不可重复。(
HashSet、TreeSet)
- 无序、无下标、元素不可重复。(
Map集合- 存储一对数据,无序、无下标、键不可重复,值可以重复。(
HashMap、HashTable、TreeMap)
- 存储一对数据,无序、无下标、键不可重复,值可以重复。(
Collections- 集合工具类,定义了除了存取以外的集合常用方法。
版权声明:本文为weixin_40960688原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。