# Java 集合框架
# 集合
# 1、集合的概念
对象的容器,实现对对象的常用操作,类似数组功能
# 2、集合和数组的区别
(1) 数组长度固定,集合长度不固定
(2) 数组可以存储基本类型和引用类型,集合只可以存储基本类型
# 3、位置
java.util*
# Collection 父接口
特点:代表一组任意类型的对象,无序,无下标、不能重复。
方法:
使用:
public class demo1 {
public static void main(String[] args) {
//创建集合
Collection collection = new ArrayList();
//(1)添加元素
collection.add("苹果");
collection.add("西瓜");
System.out.println("元素个数:"+collection.size());
System.out.println(collection);
//(2)删除元素
//collection.remove("苹果");
//collection.clear();//清空
//(3)遍历元素 (重点)
//3.1增强for
System.out.println("========3.1增强for=========");
for (Object object:collection
) {
System.out.println(object);
}
//3.2 使用迭代器(Iterator迭代器专门用来遍历集合的一种方式)
//hasNext();有没有下一个元素
//next();获取下一个元素
//remove();删除当前元素
System.out.println("========3.2 使用迭代器=========");
Iterator it = collection.iterator();
while (it.hasNext()){
String s = (String)it.next();
System.out.println(s);
//在迭代过程中不能使用collection的删除方法
//collection.remove(s);
it.remove();
}
//(4)判断
System.out.println(collection.contains("苹果"));
System.out.println(collection.isEmpty());
}
}
public class demo2 {//保存学生信息
public static void main(String[] args) {
//新建collection对象
Collection collection = new ArrayList();
Student s1 = new Student("张三",10);
Student s2 = new Student("李四",10);
Student s3= new Student("王五",10);
//(1)添加数据
collection.add(s1);
collection.add(s2);
collection.add(s3);
System.out.println("元素个数"+collection.size());
System.out.println(collection.toString());
//(2)删除
collection.remove(s1);
//(3)遍历元素 (重点)
//3.1增强for
System.out.println("========3.1增强for=========");
for (Object object:collection
) {
Student s = (Student)object;
System.out.println(s.toString());
}
//3.2 使用迭代器(Iterator迭代器专门用来遍历集合的一种方式)
System.out.println("========3.2 使用迭代器=========");
Iterator it = collection.iterator();
while (it.hasNext()){
Student s = (Student)it.next();
System.out.println(s.toString());
}
//(4)判断
System.out.println(collection.contains("s1"));
System.out.println(collection.isEmpty());
}
}
# List 子接口
特点:有序、有下标、元素可以重复
方法:
使用:
public class demo3 {
public static void main(String[] args) {
//先创建集合对象
List list = new ArrayList<>();
//(1)添加元素
list.add("苹果");
list.add("小米");
list.add("华为");
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());
//(2)删除元素
//list.remove("苹果");
//list.remove(0);
System.out.println("删除之后:"+list.size());
System.out.println(list.toString());
//(3)遍历
//3.1使用for遍历
System.out.println("=========使用for遍历=========");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//3.2增强for
System.out.println("=========增强for=========");
for (Object object :
list) {
System.out.println(object);
}
//3.3使用迭代器
System.out.println("=========使用迭代器=========");
Iterator it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//3.4使用列表迭代器,和Iterator区别,ListIterator可以向前或向后遍历,添加、删除、修改元素
ListIterator lit = list.listIterator();
System.out.println("=========使用列表迭代器从前往后=========");
while (lit.hasNext()){
System.out.println(lit.nextIndex()+":"+lit.next());
}
System.out.println("=========使用列表迭代器从后往前=========");
while (lit.hasPrevious()){
System.out.println(lit.previousIndex()+":"+lit.previous());
}
//(4)判断
System.out.println(list.contains("苹果"));
System.out.println(list.isEmpty());
//(5)获取位置
System.out.println(list.indexOf("华为"));
}
}
public class demo4 {
public static void main(String[] args) {
//创建集合
List list = new ArrayList();
//(1)添加数字数据(自动装箱)
list.add(20);
list.add(30);
list.add(40);
list.add(50);
list.add(60);
System.out.println("元素个数"+list.size());
System.out.println(list.toString());
//(2)删除元素
list.remove(0);
list.remove(new Integer(20));
//(3)补充方法 subList,返回子集合 ,含头不含尾
List subList = list.subList(1, 3);
System.out.println(subList.toString());//[40,50]
}
}
# List 实现类
# ArrayList【重点】:
数组结构实现,查询快 、增删慢;
jdk1.2 版本,运行效率快、线程不安全。
public class demo5 { | |
public static void main(String[] args) { | |
// 创建集合 size 0 容量 0 扩容原来的 1.5 倍 | |
ArrayList arrayList = new ArrayList<>(); | |
//1、添加元素 | |
Student s1 = new Student("刘德华",20); | |
Student s2= new Student("郭富城",22); | |
Student s3 = new Student("梁朝伟",18); | |
arrayList.add(s1); | |
arrayList.add(s2); | |
arrayList.add(s3); | |
System.out.println("元素个数"+arrayList.size()); | |
System.out.println(arrayList.toString()); | |
//2、删除元素 | |
//arrayList.remove(s1); | |
//arrayList.remove (new Student ("刘德华",20));// 这样删除的是新实例的 student,equals(this==obj) 需要重写 equals 方法 | |
//System.out.println ("删除之后"+arrayList.size () );//2 | |
//3、遍历元素【重点】 | |
//3.1 使用迭代器 | |
System.out.println("===========使用迭代器============"); | |
Iterator it = arrayList.iterator(); | |
while(it.hasNext()){ | |
Student s = (Student)it.next(); | |
System.out.println(s.toString()); | |
} | |
//3.2 使用列表迭代器 | |
System.out.println("===========使用列表迭代器============"); | |
ListIterator lit = arrayList.listIterator(); | |
while(lit.hasNext()){ | |
Student s = (Student)lit.next(); | |
System.out.println(s.toString()); | |
} | |
//4、判断 | |
System.out.println(arrayList.contains(new Student("梁朝伟",18)));// 已经重写过 equals 方法 | |
System.out.println(arrayList.isEmpty()); | |
//5、查找 | |
System.out.println(arrayList.indexOf(s1)); | |
} | |
} |
重写 equals 方法
@Override | |
public boolean equals(Object obj) { | |
//1、判断是不是一个对象 | |
if(this == obj){ | |
return true; | |
} | |
//2、判断是否为空 | |
if(obj == null){ | |
return false; | |
} | |
//3、判断受否是 Student 类型 | |
if(obj instanceof Student){ | |
Student s = (Student)obj; | |
//4、比较属性 | |
if(this.name.equals(s.getName())&&this.age == s.getAge()){ | |
return true; | |
} | |
} | |
//5、不满足条件返回 flase | |
return false; | |
} |
源码分析:
DEFAULT_CAPACITY = 10; 默认容量
注: 如果没有向集合中添加任何元素时,容量为 0;添加任意一个元素时,容量为 10 每次扩容大小是原来的 1.5 倍
elementData 存放元素的数组
size 实际的元素个数
add() 添加元素
public boolean add(E e) { | |
ensureCapacityInternal(size + 1); // Increments modCount!! | |
elementData[size++] = e; | |
return true; | |
} | |
private void ensureCapacityInternal(int minCapacity) { | |
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); | |
} | |
private static int calculateCapacity(Object[] elementData, int minCapacity) { | |
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { | |
return Math.max(DEFAULT_CAPACITY, minCapacity); | |
} | |
return minCapacity; | |
} | |
private void ensureExplicitCapacity(int minCapacity) { | |
modCount++; | |
// overflow-conscious code | |
if (minCapacity - elementData.length > 0) | |
grow(minCapacity); | |
} | |
private void grow(int minCapacity) { | |
// overflow-conscious code | |
int oldCapacity = elementData.length; | |
int newCapacity = oldCapacity + (oldCapacity >> 1); | |
if (newCapacity - minCapacity < 0) | |
newCapacity = minCapacity; | |
if (newCapacity - MAX_ARRAY_SIZE > 0) | |
newCapacity = hugeCapacity(minCapacity); | |
// minCapacity is usually close to size, so this is a win: | |
elementData = Arrays.copyOf(elementData, newCapacity); | |
} |
# Vector:
数组结构实现,查询快、增删慢;
jdk1.0 版本,运行效率慢、线程安全
public class demo6 { | |
public static void main(String[] args) { | |
Vector vector = new Vector<>(); | |
vector.add("苹果"); | |
vector.add("西瓜"); | |
//3、遍历 使用枚举器 | |
Enumeration en = vector.elements(); | |
while(en.hasMoreElements()){ | |
String o = (String)en.nextElement(); | |
System.out.println(o); | |
} | |
} |
# LinkedList:
链表结构实现,增删快,查询慢。
使用:
public class demo7 { | |
public static void main(String[] args) { | |
// 创建集合 | |
LinkedList linkedList = new LinkedList<>(); | |
//1、添加元素 | |
Student s1 = new Student("刘德华",20); | |
Student s2= new Student("郭富城",22); | |
Student s3 = new Student("梁朝伟",18); | |
linkedList.add(s1); | |
linkedList.add(s2); | |
linkedList.add(s3); | |
System.out.println("元素个数"+linkedList.size()); | |
System.out.println(linkedList.toString()); | |
//2、删除 | |
//linkedList.remove(s1); | |
//System.out.println ("删除之后"+linkedList.size ()); | |
//linkedList.clear(); | |
//3、遍历 | |
//3.1 for 遍历 | |
System.out.println("==========for============="); | |
for (int i = 0; i < linkedList.size(); i++) { | |
System.out.println(linkedList.get(i)); | |
} | |
//3.2 增强 for | |
System.out.println("==========增强for============="); | |
for (Object object : | |
linkedList) { | |
Student s = (Student) object;// 因为拿到以后变成 Object 所以需要强制类型转换 | |
System.out.println(s.toString()); | |
} | |
//3.3 迭代器 | |
System.out.println("==========迭代器============="); | |
Iterator iterator = linkedList.iterator(); | |
while (iterator.hasNext()) { | |
Student s = (Student)iterator.next(); | |
System.out.println(s.toString()); | |
} | |
//3.4 使用列表迭代器 | |
//4、判断 | |
System.out.println(linkedList.contains(s1)); | |
System.out.println(linkedList.isEmpty()); | |
//5、获取 | |
System.out.println(linkedList.indexOf(s1)); | |
} | |
} |
源码分析:
int size 集合的大小
Node first 链表的头节点
Node last 链表的尾节点
void linkLast(E e) { | |
final Node<E> l = last; | |
final Node<E> newNode = new Node<>(l, e, null); | |
last = newNode; | |
if (l == null) | |
first = newNode; | |
else | |
l.next = newNode; | |
size++; | |
modCount++; | |
} | |
private static class Node<E> { | |
E item; | |
Node<E> next; | |
Node<E> prev; | |
Node(Node<E> prev, E element, Node<E> next) { | |
this.item = element; | |
this.next = next; | |
this.prev = prev; | |
} | |
} |
# ArrayList 和 LinkedList 区别
# 泛型
# 泛型概述
Java 泛型是 JDK1.5 中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
常见形式有泛型类、泛型接口、泛型方法。
语法:
<T,....> T 称为类型占位符,表示一种引用类型
好处:
(1) 提高代码的重用性
(2)防止类型转换异常,提高代码的安全性
# 泛型类
语法:类名 <T>
public class MyGeneric<T> {// 泛型类 | |
// 使用泛型 | |
//1、创建变量 | |
T t; | |
//2、泛型作为方法的参数 | |
public void show(T t){ | |
System.out.println(t); | |
} | |
//3、泛型作为方法的返回值 | |
public T getT(){ | |
return t; | |
} | |
} |
public class TestGeneric { | |
public static void main(String[] args) { | |
// 使用泛型类创建对象 | |
// 注意: 1、泛型只能使用引用类型, 2、不同泛型对象不能相互赋值 | |
MyGeneric<String> myGeneric = new MyGeneric<String>() ; | |
myGeneric.t = "hello"; | |
myGeneric.show("大家好"); | |
String string = myGeneric.getT(); | |
MyGeneric<Integer> myGeneric2 = new MyGeneric<>(); | |
myGeneric2.t = 10; | |
myGeneric2.show(20); | |
Integer integer = myGeneric2.getT(); | |
} | |
} |
# 泛型接口
语法:接口名 <T>
注意:不能泛型静态常量
public interface MyInterface <T>{// 泛型接口 | |
String name = "张三"; | |
T server(T t); | |
} | |
public class MyInterfaceImpl implements MyInterface<String>{ | |
//1、实现类时确定泛型类型 | |
@Override | |
public String server(String t) { | |
System.out.println(t); | |
return t; | |
} | |
} | |
MyInterfaceImpl impl = new MyInterfaceImpl(); | |
impl.server("xsdfdf"); | |
public class MyInterfaceImpl2<T> implements MyInterface<T>{ | |
//2、实现类时继续使用泛型,实例时确认泛型 | |
@Override | |
public T server(T t) { | |
System.out.println(t); | |
return t; | |
} | |
} | |
MyInterfaceImpl2<Integer> impl2 = new MyInterfaceImpl2<>(); | |
impl2.server(10000); |
# 泛型方法
语法:<t> 返回值类型
public class MyGenericMethod { | |
// 泛型方法 | |
public <T> void show(T t){ | |
System.out.println("泛型方法"+t); | |
} | |
} | |
// 泛型方法 类型由传递的数据决定 | |
MyGenericMethod myGenericMethod = new MyGenericMethod(); | |
myGenericMethod.show("张三"); | |
myGenericMethod.show(200); |
# 泛型集合
概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
特点:
编译时即可检查,而非运行时抛出异常。
访问时,不必类型转换 (拆箱)。
不同泛型之间引用不能相互赋值,泛型不存在多态。
ArrayList arrayList = new ArrayList(); |
不使用泛型创建的是 object 对象,添加不同类型数据时遍历需要判断不同类型会报错
public class demo8 { | |
public static void main(String[] args) { | |
ArrayList<String> arrayList = new ArrayList<String>(); | |
arrayList.add("aaa"); | |
arrayList.add("bbb"); | |
//arrayList.add (111);// 类型确定无法添加 | |
for (String string : | |
arrayList) { | |
System.out.println(string); | |
} | |
ArrayList<Student> arrayList2 = new ArrayList<Student>(); | |
Student s1 = new Student("刘德华",20); | |
Student s2= new Student("郭富城",22); | |
Student s3 = new Student("梁朝伟",18); | |
arrayList2.add(s1); | |
arrayList2.add(s2); | |
arrayList2.add(s3); | |
Iterator<Student> it = arrayList2.iterator(); | |
while(it.hasNext()){ | |
Student s = it.next();// 省去强制类型转换 | |
System.out.println(s.toString()); | |
} | |
} | |
} |
# Set 子接口
特点:无序、无下标、元素不可重复。
方法:全部继承自 Collection 中的方法。
public class demo1 {//Set 接口使用 | |
public static void main(String[] args) { | |
// 创建集合 | |
Set<String> set = new HashSet<>(); | |
//1、添加数据 | |
set.add("苹果"); | |
set.add("华为"); | |
set.add("小米"); | |
//set.add ("小米");// 元素不可以重复 | |
System.out.println("数据个数"+set.size());//3 | |
System.out.println(set.toString()); | |
//2、删除数据 | |
set.remove("小米"); | |
//3、遍历 | |
//3.1、增强 for | |
System.out.println("==========增强for==========="); | |
for (String string : | |
set) { | |
System.out.println(string); | |
} | |
//3.2、使用迭代器 | |
System.out.println("==========使用迭代器==========="); | |
Iterator<String> iterator = set.iterator(); | |
while (iterator.hasNext()) { | |
System.out.println(iterator.next()); | |
} | |
//4、判断 | |
System.out.println(set.contains("华为")); | |
System.out.println(set.isEmpty()); | |
} | |
} |
# HashSet【重点】
基于 HashCode 计算元素存放位置。
当存入元素的哈希码相同时,会调用 equals 进行确认,如结果为 true,则拒绝后者存入。
存储结构:哈希表(数组+链表+红黑树)
// 新建集合 后面 new 的 HashSet 的 & lt;> 中的 String jdk1.8 后可以不用写 | |
HashSet<String> hashSet = new HashSet<String>(); |
public class demo2 {//HashSet 集合的使用 | |
// 存储结构:哈希表(数组 + 链表 + 红黑树) | |
public static void main(String[] args) { | |
// 新建集合 | |
HashSet<String> hashSet = new HashSet<String>(); | |
//1、添加元素 | |
hashSet.add("刘德华"); | |
hashSet.add("梁朝伟"); | |
hashSet.add("周润发"); | |
//hashSet.add ("刘德华");// 重复添加不进去 | |
System.out.println("元素个数:"+hashSet.size()); | |
System.out.println(hashSet.toString());// 无序 | |
//2、删除数据 | |
//hashSet.remove ("刘德华"); | |
//3、遍历 | |
//3.1 增强 for | |
//3.2、迭代器 | |
//4、判断 | |
} | |
} |
# 存储过程:
(1) 根据 hashcode 计算保存的位置,如果这个位置为空,则直接保存,如果不为空,则执行第二步。
(2) 再执行 equals 方法,如果 equals 方法为 true,则认为是重复,否则,形成链表
// 快捷重写 hashCode 和 equals 右键 ----》generate====》hascode and equals
@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; | |
} | |
//idea 生成的重写 | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (!(o instanceof Person)) return false; | |
Person person = (Person) o; | |
return getAge() == person.getAge() && Objects.equals(getName(), person.getName()); | |
} | |
@Override | |
public int hashCode() { | |
return Objects.hash(getName(), getAge()); | |
} |
重写的 hashCode 方法
(1) 31 是一个质数,减少散列冲突
(2) 31 提高执行效率 31*i = (i<<5)-i
public class demo3 { | |
public static void main(String[] args) { | |
HashSet<Person> persons = new HashSet<>(); | |
//1、添加数据 | |
Person p1 = new Person("刘德华", 20); | |
Person p2 = new Person("张学友", 22); | |
Person p3 = new Person("梁朝伟", 18); | |
persons.add(p1); | |
persons.add(p2); | |
persons.add(p3); | |
//persons.add (p3);// 重复 | |
persons.add(new Person("刘德华",20));// 可以加进去,加的时候是 new Person | |
// 重写 hashcode 方法和 equals 方法后就加不进去了 同理删除也可以了 | |
System.out.println("元素个数:"+persons.size());//3 | |
System.out.println(persons.toString());// 无序 | |
//2、删除 | |
//persons.remove(p1); | |
//persons.remove (new Person ("刘德华",20); | |
//3、遍历 | |
//3.1、增强 for | |
for (Person person : | |
persons) { | |
System.out.println(persons.toString()); | |
} | |
//3.2、迭代器 | |
Iterator<Person> iterator = persons.iterator(); | |
while (iterator.hasNext()) { | |
System.out.println(iterator.next()); | |
} | |
//4、判断 | |
System.out.println(persons.contains(p1)); | |
System.out.println(persons.isEmpty()); | |
} | |
} |
# TreeSet
基于排列顺序实现元素不重复
实现了 SortedSet 接口,对集合元素自动排序
元素对象的类型必须实现 Comparable 接口,指定排序规则
public class Person implements Comparable<Person>{ | |
// 先按姓名比,再按年龄比 返回 0 则说明两个数据重复 | |
@Override | |
public int compareTo(Person o) { | |
int n1 = this.getName().compareTo(o.getName()); | |
int n2 = this.getAge() - o.getAge(); | |
return n1 == 0?n2:n1; | |
} |
通过 CompareTo 方法是否为重复元素。
存储结构:红黑树(二叉查找树)
public class demo4 {//TreeSet 使用 | |
// 存储结构:红黑树 | |
// 要求:元素必须实现 Comparable 接口,comparareTo () 方法返回值为 0,认为是重复元素 | |
public static void main(String[] args) { | |
// 创建集合 | |
TreeSet<Person> person = new TreeSet<>(); | |
//1、添加元素 | |
Person p1 = new Person("abc",20); | |
Person p2 = new Person("dsdf",18); | |
Person p3= new Person("dvd",11); | |
person.add(p1); | |
person.add(p2); | |
person.add(p3); | |
System.out.println("元素个数:"+person.size()); | |
System.out.println(person.toString()); | |
//2、删除 u | |
//person.remove("abc",20); | |
//3、遍历 | |
//4、判断 | |
} | |
} |
基于红黑树排序
# Comparator 接口
实现 Comparator 定制比较
匿名内部类:匿名内部类可以使你的代码更加简洁,你可以在定义一个类的同时对其进行实例化。它与局部类很相似,不同的是它没有类名,java 如果某个局部类你只需要用一次,那么你就可以使用匿名内部类
TreeSet<Person> persons = new TreeSet<>(new Comparator<Person>() |
public class demo5 {//Comparator 实现定制比较(比较器) | |
public static void main(String[] args) { | |
// 创建集合,并指定比较规则 | |
TreeSet<Person> persons = 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; | |
} | |
}); | |
//1、添加元素 | |
Person p1 = new Person("abc",20); | |
Person p2 = new Person("dsdf",18); | |
Person p3= new Person("dvd",11); | |
persons.add(p1); | |
persons.add(p2); | |
persons.add(p3); | |
System.out.println("元素个数:"+persons.size()); | |
System.out.println(persons.toString()); | |
} | |
} |
# TreeSet 案例
要求:使用 TreeSet 集合实现字符串按照长度进行排序
*helloword zhang lisi wnagwu beijing xian nanjing
public class demo6 { | |
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("kisi"); | |
treeSet.add("beijing"); | |
treeSet.add("nanjing"); | |
treeSet.add("xian"); | |
System.out.println(treeSet.toString()); | |
} | |
} |
# Map 集合
# Map 父接口
特点:存储一对数据(Key--Value),无序、无下标,键不可重复,值可重复。
方法:
使用:
无法添加重复的key 但是会把重复key的value替换掉 |
遍历:
1、使用 keySet();
Set<String> keySet = map.keySet();// 返回一个包含所有 key 的 set 集合 |
2、使用 entrySet 方法
一个 Entry 就是一个映射对
Set<Map.Entry<String, String>> entries = map.entrySet();// 返回 entry 映射对 |
entrySet 比 keySet 方法效率高
public class demo1 {//Map 接口使用 | |
public static void main(String[] args) { | |
// 创建集合 | |
Map<String,String> map = new HashMap<>(); | |
//1、添加元素 | |
map.put("CN","中国"); | |
map.put("UK","英国"); | |
map.put("USA","美国"); | |
//map.put ("CN","zhongguo");// 无法添加重复的 key 但是会把重复 key 的 value 替换掉 | |
System.out.println("元素个数"+map.size()); | |
System.out.println(map.toString()); | |
//2、删除元素 | |
map.remove("USA"); | |
//3、遍历 | |
//3.1 使用 keySet (); | |
System.out.println("========使用keySet();=========="); | |
//Set<String> keySet = map.keySet ();// 返回一个包含所有 key 的 set 集合 | |
for (String key : | |
map.keySet()) { | |
System.out.println(key+"-------"+map.get(key)); | |
} | |
//3.2、使用 entrySet 方法 | |
System.out.println("========使用entrySet方法=========="); | |
Set<Map.Entry<String, String>> entries = map.entrySet();// 返回 entry 映射对 | |
for (Map.Entry<String, String> entry : | |
entries) { | |
System.out.println(entry.getKey()+"----------"+entry.getValue()); | |
} | |
//4、判断 | |
System.out.println(map.containsKey("CN")); | |
System.out.println(map.containsValue("中国")); | |
} | |
} |
# Map 集合的实现类
# HashMap
jdk1.2 版本,线程不安全,运行效率快;允许用 null 作为 key 或者 value
存储结构:哈希表(数组 + 链表 + 红黑树)
存储:使用 key 的 hashcode 和 equals 作为重复依据 参考 HashSet
public class demo2 {//HashMap 的使用 | |
public static void main(String[] args) { | |
HashMap<Student, String> students = new HashMap<>(); | |
//1、添加元素 | |
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 (new Student ("孙悟空",100),"北京");// 可以添加,否则要重写 equals 和 hashcode 方法 | |
System.out.println("元素个数"+students.size()); | |
System.out.println(students.toString()); | |
//2、删除 | |
//students.remove(s1); | |
//3、遍历 | |
//3.1 使用 keySet (); | |
for (Student key : | |
students.keySet()) { | |
System.out.println(key+students.get(key)); | |
} | |
//3.2 使用 entrySet (); | |
for (Map.Entry<Student, String> entry : | |
students.entrySet()) { | |
System.out.println(entry.getKey()+entry.getValue()); | |
} | |
//4、判断 | |
System.out.println(students.containsKey(s1)); | |
System.out.println(students.containsValue("北京")); | |
} | |
} |
源码分析:
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //aka 16//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;//jkd1.8 当链表长度大于 8 时,并且集合元素个数大于等于 64 时调整成红黑苏 | |
transient Node<K,V>[] table;// 哈希表中的数组 | |
size;// 元素个数 |
刚创建 hashmap 之后没有添加元素时 table=null size=0 目的节省空间
public HashMap() { | |
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted | |
} |
put 方法 没添加之前时 null 添加第一个元素长度为 16
public V put(K key, V value) { | |
return putVal(hash(key), key, value, false, true); | |
} | |
static final int hash(Object key) { | |
int h; | |
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); | |
} |
总结:
(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后是尾插入
HashSet 和 HashMap
实际上 hashSet 里面用的就是 hashMap
# Hashtable
jdk1.0 版本,线程安全,运行效率慢;不允许 null 作为 key 或者 value
# Properties
Hashtable 的子类,要求 key 和 value 都是 String。通常用于配置文件的读取。
# TreeMap
实现了 SortedMap 接口(是 Map 的子接口),可以对 key 自动排序。
使用:
需要实现 compara 方法
@Override | |
public int compareTo(Student o) { | |
int n2 = this.stuNo - o.getStuNo(); | |
return n2; | |
} |
public class demo3 {//TreeMap 的使用 | |
public static void main(String[] args) { | |
TreeMap<Student, String> treeMap = new TreeMap<>();// 也可以定制比较参考 Comparator 接口 | |
//1、添加元素 | |
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()); | |
//2、删除 | |
//treeMap.remove(s1); | |
//treeMap.remove (new Student ("孙悟空",100),"北京"); | |
//3、遍历 | |
//3.1 使用 keySet (); | |
for (Student key : | |
treeMap.keySet()) { | |
System.out.println(key+treeMap.get(key)); | |
} | |
//3.2 使用 entrySet (); | |
for (Map.Entry<Student, String> entry : | |
treeMap.entrySet()) { | |
System.out.println(entry.getKey()+entry.getValue()); | |
} | |
//4、判断 | |
System.out.println(treeMap.containsKey(s1)); | |
System.out.println(treeMap.containsValue("北京")); | |
} | |
} |
# Colletions 工具类
概念:集合工具类,定义了除了存取以外的集合常用方法
方法:
// 数组转成集合后变成受限集合,大小固定,不能添加和删除 | |
List<String> list2 = Arrays.asList(names); |
public class demo1 {//Collections 工具类使用 | |
public static void main(String[] args) { | |
List<Integer> list = new ArrayList<>(); | |
list.add(20); | |
list.add(10); | |
list.add(15); | |
list.add(30); | |
list.add(40); | |
list.add(50); | |
//sort 排序 | |
System.out.println("排序之前"+list.toString());//[20, 10, 15, 30, 40, 50] | |
Collections.sort(list); | |
System.out.println("排序之后"+list.toString());//[10, 15, 20, 30, 40, 50] | |
//binarySearch 二分查找 | |
int i = Collections.binarySearch(list,15); | |
System.out.println(i);//1 | |
//copy 复制 | |
List<Integer> dest = new ArrayList<>(); | |
for (int k = 0; i < list.size(); k++) {//copy 需要两个集合大小一样,所以拿 0 填充 | |
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[0]);// 创建的数组大小小于集合大小则数组大小变成和集合大小一样,大于集合大小超出的为 null | |
System.out.println(arr.length); | |
System.out.println(Arrays.toString(arr)); | |
// 数组转成集合 | |
System.out.println("数组变成集合"); | |
String[] names = {"张三","李四","王五"}; | |
// 数组转成集合后变成受限集合,大小固定,不能添加和删除 | |
List<String> list2 = Arrays.asList(names); | |
System.out.println(list2); | |
} | |
} |