8集合
集合
1 java集合框架概述
数组在存储多个数据方面的特点
- 一旦初始化以后,长度就确定了
- 比如String[] arr需要指明类型,一旦定义好,元素类型就确定了
数组在存储多个数据方面的缺点
- 一旦初始化以后,长度就不可修改了
- 数组中提供的方法有限,对于添加,删除,插入等操作非常不便,效率不高
- 获取数组中实际元素的个数的需求,数组没有现成的方法可用
- 数组存储数据的特点:有序,可重复 对于无序,不重复需求数组不能满足
集合框架
1.1 Colection接口:单列集合,用来存储一个个的对象
- List接口:存储有序的可重复的数据,动态数组(ArrayList LinkedList Vector)
- Set接口:存储无序的不可重复的数据,高中讲的集合(HashSet LinkedHashSet TreeSet)
1.2 Map接口:双列集合,用于存储一对一对的对象,高中函数y=f(x)
- HashMap LinkedHashMap TreeMap Hashtable Properties


2 Collection接口中的方法使用
2.1 常用方法
-
add(Object e):将元素e添加到集合coll中
-
size() :获取添加元素的个数
-
addAll(Collection col1):将col1中的元素添加到当前集合中
-
clear():清空当前集合的元素
-
isEmpty():判断当前集合是否为空
-
contains(Object obj):判断集合中是否存在obj
-
containsall(collection c2):判断c2是否都在当前集合中
-
remove(object obj):删除集合中的obj元素
-
removeAll(Collection c2):从当前集合中移除c2包含元素
-
retainAll(collection c2):获取当前集合和c2集合的交集
-
equals(Object obj): 判断是否相等,是否需要按顺序得看具体容器
-
hashcode():返回当前对象的哈希值
-
toArray():集合-->数组
-
asList():数组-->集合 调用Arrays的静态方法
-
iterator():返回Iterator接口的实例 用于遍历集合元素(具体在2.2展开)
-
注意:向collection接口的实现类的对象中添加数据obj需要重写equals方法(因为涉及到值的比较和地址的比较 重写之后变成值的比较 这样在有些方法中可以更好的表现语义)(涉及到的方法有:remove(), removeAll(), retainAll(), equals(), contains(), containsAll(), hashcode() )
//collection接口的实现类
class Person{
private String name;
private int age;
public Person(){
}
public Person(String name, int age) {
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 +
'}';
}
//注意这里重写equals()方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
}
public class G36Collection {
@Test
public void test1(){
Collection col=new ArrayList();
//add(Object e)将元素e添加到集合coll中
col.add("aa");
col.add("bb");
col.add(123);//自动装箱
col.add(new Date());
//size() 获取添加元素的个数
System.out.println(col.size());//4
//addAll(Collection col1)将col1中的元素添加到当前集合中
Collection col1=new ArrayList();
col1.add(456);
col1.add("Cc");
col.addAll(col1);
System.out.println(col);
//[aa, bb, 123, Thu Sep 02 14:44:13 CST 2021, 456, Cc]
//clear():清空当前集合的元素
col.clear();
//isEmpty():判断当前集合是否为空
System.out.println(col.isEmpty());//true
}
@Test
public void test2(){
Collection col1=new ArrayList();
col1.add(123);
col1.add(456);
col1.add(new String("tom"));
col1.add(false);
col1.add(new Person("fao",18));
//contains(Object obj)
boolean contains=col1.contains(123);
System.out.println(contains);//true
System.out.println(col1.contains(new String("tom")));
//判断内容 因为string重写过equals 所以为true
System.out.println(col1.contains(new Person("fao",18)));
//自定义类没重写就是false 但上面我们自己重写过 所以这里还是ture
//containsall(collection c2) 判断c2是否都在当前集合中
Collection col2=new ArrayList();
System.out.println(col1.containsAll(col2));//true
}
@Test
public void test3(){
Collection col1=new ArrayList();
col1.add(123);
col1.add(456);
col1.add(new String("tom"));
col1.add(false);
col1.add(new Person("fao",28));
//remove(object obj)
col1.remove(123);
System.out.println(col1);//重写equals以后才能移除那些值一样的对象
//[456, tom, false, Person{name='fao', age=28}]
//removeAll(Collection c2) 从当前集合中移除c2包含元素
Collection col2=new ArrayList();
col2.add(123);
col2.add(222);
col2.add(new String("tom"));
col2.add(new Person("fao",28));
col1.removeAll(col2);
System.out.println();
System.out.println(col1);//[456, false]
//retainAll(collection c2) 获取当前集合和c2集合的交集
Collection col3=new ArrayList();
col3.add(456);
col1.retainAll(col3);
System.out.println();
System.out.println(col1);//[456]
//equals(Object obj) 判断是否相等 顺序得看具体容器
System.out.println();
System.out.println(col1.equals(col3));
//true 因为是有序队列,换了顺序序就是false
}
@Test
public void test4(){
Collection col1=new ArrayList();
col1.add(123);
col1.add(456);
col1.add(new String("tom"));
col1.add(false);
col1.add(new Person("fao",28));
//hashcode()返回当前对象的哈希值
System.out.println(col1.hashCode());//698073098
//集合-->数组 toArray
Object[] objects = col1.toArray();
for (int i=0;i<objects.length;i++){
System.out.println(objects[i]);
}
//拓展数组-->集合 调用arrays的静态方法 asList
List<String> strings = Arrays.asList(new String[]{"aa", "bb", "cc"});
System.out.println(strings);//[aa, bb, cc]
}
}
2.2 集合元素遍历:使用迭代器Iterator接口
- Collection接口继承了java.lang.iterable接口,该接口有一个iterator()方法,那么所以事先了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了iterator接口的对象
- iterator仅由于遍历集合,它本身并不提供承载对象的能力,如果需要创建iterator对象,则必须有一个被迭代的集合
- 内部的方法:hasNext()和next()
- 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前
- 内部定义了remove() 可以在遍历时删除集合元素,不同于集合直接调用remove,需要注意重新生成,一定要先next再remove 也不能再下一次next前再调一次remove
- 只遍历collection 不遍历map
- jdk5.0新增了foreach,用于遍历集合和数组

public class G37IteratorTest {
@Test
public void test1(){
Collection col1=new ArrayList();
col1.add(123);
col1.add(456);
col1.add(new String("tom"));
col1.add(false);
col1.add(new Person("fao",28));
Iterator iterator = col1.iterator();
//方式1 不用
// System.out.println(iterator.next());//123
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());//多写一下就报异常
//方式二 也不用
// for (int i=0;i<col1.size();i++){
// System.out.println(iterator.next());
// }
//方式三:推荐
while (iterator.hasNext()){
//next:指针下移,然后返回指针所指元素
System.out.println(iterator.next());
}
}
@Test
public void test2(){
Collection col1=new ArrayList();
col1.add(123);
col1.add(456);
col1.add(new String("tom"));
col1.add(false);
col1.add(new Person("fao",28));
Iterator iterator = col1.iterator();
//删除集合中的tom
while (iterator.hasNext()){
Object next = iterator.next();
if ("tom".equals(next)){//注意这里"tom"放前面防止空指针
iterator.remove();
}
}
//因为指针已经末尾了 所以要重新上传!!
iterator=col1.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());//此时tom已经被删了
}
}
@Test
public void test3(){
Collection col1=new ArrayList();
col1.add(123);
col1.add(456);
col1.add(new String("tom"));
col1.add(false);
col1.add(new Person("fao",28));
//for(集合中元素的类型 局部变量: 集合对象)也可以是数组
//内部仍然调用迭代器
for (Object obj:col1){
System.out.println(obj);
}
int[] ints = {1, 2, 3, 4};
for (int i:ints){
System.out.println(i);
}
System.out.println();
String[] arr = {"mm", "mm", "mm"};
//普通for循环
for (int i=0;i<arr.length;i++){
arr[i]="gg";
}
for (int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
String[] arr1 = {"mm", "mm", "mm"};
//增强for循环
for(String s:arr1){
s="gg";
}
for (String s:arr1){
System.out.println(s);
}
}
}
3 Collection子接口-List接口
3.1 概述
- List接口:存储有序的可重复的数据,动态数组
- ArrayList LinkedList Vector
- ArrayList:作为List接口的主要实现类,线程不安全的,效率高,底层使用Objcet[]数组存储
- LinkedList:对于频繁插入删除操作比ArrayList高,底层使用双向链表存储
- Vector:作为List接口的古老实现类,线程安全的,效率低,底层使用Objcet[]数组存储
3.2 ArrayList源码分析:JDK7和JDK8不同
JDK7
- ArrayList list=new ArrayList();//底层创建了长度是10的Object数据elementData[]
- list.add(123);//如果添加导致容量不够 扩容 默认扩充1.5倍 同时将原来数组复制到新的数组中
- 结论:建议开发中使用带参的构造器 实现决定好容量 ArrayList(int capacity)
JDK8
- ArrayList list=new ArrayList();底层Object数据elementData[]并没有创建长度为10的数组
- list.add(123)第一次调用add()时,底层才创建了长度10的数组
- 后续操作和前面一样
- 小结:7中ArrayList对象创建类似于饿汉式,8中ArrayList对象创建类似于懒汉式
3.3 LinkedList源码分析
- LinkedList list=new LinkList()内部声明了Node类型的first和last
- 其中Node定义看源码 就是双向列表
3.4 Vector源码分析
- 创建了长度为10的数组
- 扩容扩展为原来2倍
3.5 新增方法
- void add(int index,Object ele):在Index位置插入ele元素
- boolean addAll(int index,Collection eles):从index位置开始讲eles中的所有元素添加进来
- Object get(int index):获取指定index位置的元素
- int indexOf(Object obj):返回obj在集合中首次出现的位置
- int lastindexOf(Object obj):返回obj在集合中最后出现的位置
- Object remove(int index):移除指定index位置的元素,并返回此元素
- Object set(int index,Object ele):设置指定Index位置的元素为ele
- List subList(int fromIndex, int toIndex):返回从fromIndex到tolndex位置的子集合
3.6 总结常用方法
- 增 add(Object obj)
- 删 remove(int index)/ remove(Object obj)
- 改 set(int index, Object ele)
- 查 get(int index)
- 插 add(int index, Object ele)
- 长度 size()
- 遍历 1Iterator 2增强for循环 3普通循环
public class G38List {
@Test
public void test1(){
ArrayList list=new ArrayList();
list.add(123);
list.add(456);
list.add("aa");
list.add(new Person("aoao",22));
list.add(456);
System.out.println(list);
//[123, 456, aa, Person{name='aoao', age=22}, 456]
//void add(int index, Object ele)在index位置插入ele
list.add(1,"bb");
System.out.println(list);
//[123, bb, 456, aa, Person{name='aoao', age=22}, 456]
//void add(int index, Collection eles)在index位置插入eles
ArrayList list1=new ArrayList();
list1.add("fao");
list1.add("shuaiqi");
list.addAll(4,list1);
System.out.println(list);
//[123, bb, 456, aa, fao, shuaiqi, Person{name='aoao', age=22}, 456]
//Object get(int index)获取index位置元素
System.out.println(list.get(1));//bb
//int indexOf(Object obj)返回当前元素在指定集合所在索引位置没有返回-1
System.out.println(list.indexOf("fao"));//4
//int LastindexOf(Object obj)返回当前元素在指定集合最后所在索引位置没有返回-1
//Object remove(int index)删除指定位置的元素 和Collection不一样 这里是位置
System.out.println();
Object remove = list.remove(4);
System.out.println(list);
//[123, bb, 456, aa, shuaiqi, Person{name='aoao', age=22}, 456]
System.out.println(remove);
//fao
//Object set(int index, Object ele)设置指定index位置为ele
list.set(0,"zzz");
System.out.println(list);
//[zzz, bb, 456, aa, shuaiqi, Person{name='aoao', age=22}, 456]
//List subList(int fromIndex, int toIndex)返回从fromIndex到toIndex的子集合左闭右开
List list2 = list.subList(1, 3);
System.out.println();
System.out.println(list2);
//[bb, 456]
System.out.println(list);
//[zzz, bb, 456, aa, shuaiqi, Person{name='aoao', age=22}, 456]
}
//遍历
@Test
public void test2(){
ArrayList list=new ArrayList();
list.add(123);
list.add(456);
list.add("aa");
list.add(new Person("aoao",22));
list.add(456);
//方式1:iterator
Iterator iterator=list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//方式二:增强for循环
System.out.println();
for (Object obj:list){
System.out.println(obj);
}
//方式三:普通for循环
System.out.println();
for (int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
}
4 Collection子接口-Set接口
4.1 简介
- Set接口是Collection子接口,set接口没有提供额外的方法
- Set接口:存储无序的不可重复的数据,高中讲的集合
- Set集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set集合中,则添加失败
- HashSet LinkedHashSet TreeSet
- HashSet:作为set接口的主要实现类,线程不安全的,可以存储null值
- LinkedHashSet:HashSet子类,遍历其内部数据时可以按照添加数据遍历
- TreeSet:红黑树存储,可以按照添加对象的指导属性进行排序,只能添加统一类数据
- Set判断两个对象是否相同不是使用==运算符,而是根据equals()方法
- 要求:向set中添加的数据,其所在类一定要重写hashcode()和equals()
- hashcode()和equals()要保持一致性,即相同的对象要有相同的哈希值
4.2 特点
- set:存储无序的,不可重复的数据(以HashSet为例说明)
- 无序性:不等于随机性,存储的数据在底层数组中并非按照数组索引的顺序添加;而是根据数据的Hash值确定的
- 不可重复性:保证添加的元素按照equals判断时,不能返回true;相同的元素只能添加一个
4.3 添加元素的过程(HashSet为例)
- 1我们想在HashSet中添加a,首先调用a的hashCode方法,计算a哈希值
- 2此哈希值通过哈希函数计算出hashset数组存放位置
- 3数组此位置上是否已经有元素
- 3.1如果此位置没有元素,则a添加成功--情况1; 3.2 如此位置有其他元素b(或链表形式存在的多个元素)
- 4比较ab哈希值:
- 4.1哈希值不同,则添加成功--情况2;如果相同
- 5 进而需要调元素a的equals方法
- 5.1 equals方法返回false则添加成功,--情况3,; 如果返回true 则添加失败
- 对于添加成功情况2和情况3 a和已经存储元素按照链表方式存储(jdk7中a放到数组中,指向原来元素;jdk8中原来元素在数组中,指向a,(七上八下))
- Hashset底层就是数组+链表方式
//Class一 PERSON-重写了equals方法和hashcode方法
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name, int age){
this.name=name;
this.age=age;
}
public void walk(){
System.out.println("人走路");
}
public void eat(){
System.out.println("人吃饭");
}
}
//Class二 USER-重写了equals方法和hashcode方法
class User implements Comparable{
private String name;
private int age;
public User(){
}
public User(String name, int age) {
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 "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//注意equals要和hashCode判定方式一样
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age && Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
//按照姓名从小到大排序
@Override
public int compareTo(Object o) {
if (o instanceof User) {
User user=(User) o;
return this.name.compareTo(user.name);
}else{
throw new RuntimeException("不匹配");
}
}
}
4.4 Set实现类一:HashSet
- HashSet是Set接口的典型实现,大多数时候使用Set集合时都使用这个类
- HashSet按Hash算法来存储集合中的元素,因此具有很好的存取,查找,删除性能
- HashSet具有以下特点:a不能保证元素的排列顺序 bHashSet不是线程安全的 c集合元素可以是null
- HashSet集合判断两个元素相等的标准:两个对象通过hashCode()方法比较相等,并且两个对象的equals()方法返回值也相等
- 对于存放在Set容器的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等的规则,即“相等的对象必须具有相等的散列码”
@Test
public void test1(){
Set set=new HashSet();
set.add(456);
set.add(123);
set.add("aa");
set.add("cc");
set.add(new Person("p",99));
set.add(new Person("p",99));//没有重写equals和hashcode就会添加重复
set.add(new User("u",99));
set.add(new User("u",99));
set.add(123);
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//aa
//cc
//Person{name='p', age=99}
//Person{name='p', age=99} 重复了!
//456
//User{name='u', age=99}
//123
}
4.5 Set实现类二:LinkedHashSet
- LinkedHashSet是HashSet的子类
- LinkedHashSet根据元素的hashCode只来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的
- LinkedHashSet插入性能略低于HashSet,但在迭代访问Set里的全部元素时有很好的性能(即对于频繁的遍历操作要比hashcode更高效)
- LinkedHashSet不允许集合元素重复
@Test
public void test2(){
Set set=new LinkedHashSet();
set.add(456);
set.add(123);
set.add("aa");
set.add("cc");
set.add(new Person("p",99));
set.add(new Person("p",99));
set.add(new User("u",99));
set.add(new User("u",99));
set.add(123);
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//456
//123
//aa
//cc
//Person{name='person', age=99}
//Person{name='person', age=99} 重复
//User{name='user', age=99}
}
4.6 Set实现类三:TreeSet
- TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态,需要内部元素一致
- TreeSet底层使用红黑树结构存储数据
- TreeSet两种方法:自然排序(comparable接口)和定制排序(comparator),默认情况下,TreeSet采用自然排序
- 自然排序中,比较两个对象是否相等的标准为compareto方法是否返回0不再是equals方法
- 定制排序中,比较两个对象是否相等的标准为compare()方法是否为0,不再是equals方法
//自然排序
@Test
public void test3(){
TreeSet set=new TreeSet();
//失败的 ClassCastException
// set.add(456);
// set.add(123);
// set.add("aa");
// set.add(new Person("lala",99));
//举例1
//set.add(32);
//set.add(33);
//set.add(-82);
//set.add(92);
//set.add(132);
//System.out.println(set);
//举例2
set.add(new User("tom",22));
set.add(new User("fa",32));
set.add(new User("aa",21));
set.add(new User("zt",5));
set.add(new User("ee",55));
set.add(new User("ee",55));
System.out.println(set);
}
//定制排序
@Test
public void test4(){
Comparator com=new Comparator() {
//按照年龄从小到大排列
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof User && o2 instanceof User){
User u1=(User) o1;
User u2=(User) o2;
return Integer.compare(u1.getAge(),u2.getAge());
}else {
throw new RuntimeException("不一致");
}
}
};
TreeSet set=new TreeSet(com);
set.add(new User("tom",22));
set.add(new User("fa",22));
set.add(new User("aa",21));
set.add(new User("zt",5));
set.add(new User("ee",55));
set.add(new User("ee",55));
System.out.println(set);
//[User{name='zt', age=5}, User{name='aa', age=21}, User{name='tom', age=22}, User{name='ee', age=55}]
//相同年龄的会没有
}
5 Map接口

5.1 简介
-
Map接口:双列集合,用于存储一对一对的对象,高中函数y=f(x)
-
分为:HashMap( LinkedHashMap )TreeMap Hashtable ( Properties)
-
HashMap:作为map的主要实现类,线程不安全,效率高,可以存储null的key和value;HashMap底层:数组+链表(jdk7之前),数组+链表+红黑树(jdk8之后)
-
LinkedHashMap:保证在遍历map元素时,可以按照添加顺序进行遍历;原因:在原有基础上添加了前后指针,对于频繁的遍历操作效率更高
-
TreeMap:保证按照添加的key-value进行排序,此时考虑key的自然排序或定制排序;底层使用的红黑树
-
Hashtable:古老实现类,线程安全,效率低,不可以存储null的key和value
-
Properties:常用来处理配置文件,key和value都是string类型的
5.2 Map结构理解
-
Map中的key:无序的,不可重复的,使用set存储所有key--->key所在类重写equals和hashcode(以hashmap来说)
-
Map中的value:无序的,可重复的,使用collection存储所有的value-->value所在类重写equals
-
一个键值队:key-value构成Entry对象,
-
Map中的Entry:无序的,不可重复的,使用set存储所有entry
5.3 Map常用方法
- Object put(Object key,Object value):将指定key-value添加到或修改到当前map对象中
- void putAll(Map m):将m中的所有key-value对存放到当前map中
- Object remove(Object key):移除指定key的key-value对,并返回value
- void clear():清空当前map中的所有数据
- Object get(Object key):获取指定key对应的value
- boolean containsKey(Object key):是否包含指定的key
- boolean containsValue(Object value):是否包含指定的value
- int size():返回map中的key-value对的个数
- boolean isEmpty():判断当前map是否为空
- boolean equals(Object obj):判断当前map和参数对象obj是否相等
- Set keySet():返回所有key构成的Set集合
- Collection values():返回所有value构成的Collection集合
- Set entrySet():返回所有key-value对构成的Set集合
- Map接口定义方法总结
- 增 put
- 删 remove
- 改 put
- 查 get
- 长度 size
- 遍历 keySet values entrySet
5.4 HashMap
HashMap底层实现原理(JDK7)
- a.实例化:HashMap map=new HashMap()
- 在实例化以后底层创建了长度是16的一维数组Entry[] table
- b.添加:map.put(key1,value1);
- 首先调用key1所在的类的hashcode()就是key1的哈希值,通过哈希函数得到Entry数组中的位置
- 如果此位置上数据为空,此时key1-value1添加成功--情况1
- 如果此位置上数据不为空,即存在一个或多个数据(链表)比较key1和存在数据的key的哈希值
- 如果key1哈希值和它们都不一样,则添加成功--情况2
- 如果key1哈希值和某一个相同,继续比较key1所在的equals方法
- 如果equals放回false,则添加成功--情况3
- 如果equals返回true,使用value1替换相同key的value值(新的换旧的)
- 关于情况2和情况3:此时key1和value1和原来数组以链表方式存储
- 在不断添加过程中,会涉及扩容问题:当超出临界值(且要存放位置非空时)扩容为原来容量2倍,并将原来数据复制过来
HashMap底层实现原理(JDK8)
- HashMap map=new HashMap()底层没有创建一个长度16的数组
- 底层的数组是Node[] 而不是Entry[],换了个名字
- 首次调用put方法时,底层创建长度是16的数组
- jdk7底层结构只有数组+链表 8变成数组+链表+红黑树
- 当数组某一个索引位置上元素以链表形式存在的数据个数>8且当前数组长度>64(小于64先扩容), 此时索引位置上的所有数据改为红黑数存储
HashMap源码中的重要常量
- DEFAULT_INITIAL_CAPACITY:HashMap的默认容量,16
- MAXIMUN_CAPACITY:HashMap的最大支持容量,2^30
- DEFUAL_LOAD_FACTOR:默认加载因子,0.75
- loadFactor:填充因子
- threshold:扩容的临界值=容量*填充因子
5.5 LinkedHashMap(底层结构了解即可)
//HashMap中的内部类
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
}
//LinkedHashMap中的内部类
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
public class G41Map {
@Test
public void test1(){
//put
Map map199=new LinkedHashMap();
Map map=new HashMap();
map.put("aa",123);
map.put("bb",222);
map.put("cc",123);
map.put("aa",923);
System.out.println(map);
//{aa=923, bb=222, cc=123}
//putall
Map map1=new HashMap();
map1.put("ee",273);
map1.put("dd",444);
map.putAll(map1);
System.out.println(map);
//{aa=923, bb=222, cc=123, ee=273, dd=444}
//remove(key)
Object cc = map.remove("cc");//不存在返回null
System.out.println(cc);//123
System.out.println(map);
//{aa=923, bb=222, ee=273, dd=444}
//clear
map.clear();
System.out.println(map);//{}
System.out.println(map.size());//0
}
@Test
public void test2(){
Map map=new HashMap();
map.put("aa",123);
map.put("bb",222);
map.put("cc",123);
//get(key)
System.out.println(map.get("cc"));//123
//containsKey(key)
boolean bb = map.containsKey("bb");
System.out.println(bb);//true
//containsValue(value)
System.out.println(map.containsValue(123));//true
//size
System.out.println(map.size());//3
//isEmpty
//boolean equals(Object obj)
}
//遍历 元视图操作
@Test
public void test3(){
Map map=new HashMap();
map.put("aa",123);
map.put("bb",222);
map.put("cc",123);
//遍历所有key集 keySet()
Set set = map.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());// aa bb cc
}
//遍历所有value values()
Collection values = map.values();
Iterator iterator1 = values.iterator();
while (iterator1.hasNext()){
System.out.println(iterator1.next());//123 222 123
}
//遍历所有key-value entrySet()
Set set1 = map.entrySet();
Iterator iterator2 = set1.iterator();
// while (iterator2.hasNext()){
// System.out.println(iterator2.next());
// }
while (iterator2.hasNext()){
Object obj = iterator2.next();
//entrySet集合中的元素都是entry
Map.Entry entry=(Map.Entry) obj;
System.out.println(entry.getKey()+"-->"+entry.getValue());
}
//方式二
Set set2 = map.keySet();
Iterator iterator3 = set2.iterator();
while (iterator3.hasNext()){
Object key = iterator3.next();
Object value=map.get(key);
System.out.println(key+"--->"+value);
}
}
}
5.6 treeMap
- 向treemap中添加key-value要求key必须是同一类创建的对象
- 因为要按照key进行自然排序,定制排序
public class G42TreeMap {
//自然排序
@Test
public void test1(){
TreeMap map=new TreeMap();
User u1=new User("fao",22);
User u2=new User("tom",12);
User u3=new User("jack",33);
User u4=new User("zz",55);
map.put(u1,98);
map.put(u2,88);
map.put(u3,89);
map.put(u4,68);
Set set1 = map.entrySet();
Iterator iterator2 = set1.iterator();
while (iterator2.hasNext()){
Object obj = iterator2.next();
//entrySet集合中的元素都是entry
Map.Entry entry=(Map.Entry) obj;
System.out.println(entry.getKey()+"-->"+entry.getValue());
}
//Person{name='fao', age=22}-->98
//Person{name='jack', age=33}-->89
//Person{name='tom', age=12}-->88
//Person{name='zz', age=55}-->68
}
//定制排序
@Test
public void test2(){
Comparator comparator=new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof User && o2 instanceof User){
User u1=(User) o1;
User u2=(User) o2;
return Integer.compare(u1.getAge(),u2.getAge());
}else {
throw new RuntimeException("不一致");
}
}
};
TreeMap map1=new TreeMap(comparator);
User u1=new User("fao",22);
User u2=new User("tom",12);
User u3=new User("jack",33);
User u4=new User("zz",55);
map1.put(u1,98);
map1.put(u2,88);
map1.put(u3,89);
map1.put(u4,68);
System.out.println(map1);
//{Person{name='tom', age=12}=88, Person{name='fao', age=22}=98, Person{name='jack', age=33}=89, Person{name='zz', age=55}=68}
}
}
class User implements Comparable{
private String name;
private int age;
public User(){
}
public User(String name, int age) {
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 o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age && Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
//按照姓名从小到大排序
@Override
public int compareTo(Object o) {
if (o instanceof User) {
User user=(User) o;
return this.name.compareTo(user.name);
}else{
throw new RuntimeException("不匹配");
}
}
}
5.7 Properties
- Properties类是Hashtable的子类,该对象用于处理属性文件
- 由于属性文件里的key,value都是字符串类型,所以Properties里的key和value都是字符串类型
- 存取数据时,建议使用setProperty(String key, String value)方法和getProperty(String key)方法
public class G43Properties {
public static void main(String[] args) throws Exception{
Properties properties=new Properties();
FileInputStream fis=new FileInputStream("jdbc.properties");
properties.load(fis);
String name = properties.getProperty("name");
String password = properties.getProperty("password");
System.out.println(name);//Tom
System.out.println(password);//abc123
}
}
//jdbc.properties中
name=Tom
password=abc123
6 Collections工具类
简介
- Collections是一个操作Set,List,Map等集合的工具类
- Collections中提供了一系列静态的方法堆集合元素进行排序,查询和修改等操作,还提供了对集合对象设置不可变,对集合对象实现同步控制等方法
常用方法
- reverse(List):反转List中元素的顺序
- shuffle(List):对List集合进行随机排序
- sort(List):根据元素的自然排序对指定List集合元素进行升序排序
- sort(List, Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
- swap(List,int , int):将指定list集合中的i处元素和j处元素进行排序
- Object max(Collection):根据元素的自然排序,返回指定集合中的最大元素,后面参数加Comparator就是定制排序
- Objectmin(Collection):根据元素的自然排序,返回指定集合中的最小元素,后面参数加Comparator就是定制排序
- int frequency(Collection, Object):返回指定集合中指定元素的出现次数
- void copy(List dest,List src):将src中的内容复制到dest中
- boolean replaceAll(List list,Object oldVal, Object newVal):使用新值替换List对象的所有旧值
public class G44CollectionsGongJuLei {
@Test
public void test1(){
List list=new ArrayList();
list.add(123);
list.add(73);
list.add(1);
list.add(999);
System.out.println(list);//[123, 73, 1, 999]
//reverse(list)
Collections.reverse(list);
System.out.println(list);//[999, 1, 73, 123]
//shuffle(list)随机排列
Collections.shuffle(list);
System.out.println(list);//[123, 1, 999, 73]
//sort(list, comparator) 自然排序
Collections.sort(list);
System.out.println(list);//[1, 73, 123, 999]
//swap(list,index1,index2)
Collections.swap(list,1,2);
System.out.println(list);//[1, 123, 73, 999]
//max(list)最大值
//min(list)
//frequency(list,data)
System.out.println( Collections.frequency(list,1));//1
}
@Test
public void test2(){
List list=new ArrayList();
list.add(123);
list.add(73);
list.add(1);
list.add(999);
//copy
//错误的 size不够
// List dest=new ArrayList();
// Collections.copy(dest,list);
// System.out.println(dest);
//正确的
List dest= Arrays.asList(new Object[list.size()]);
System.out.println(dest.size());//4
Collections.copy(dest,list);
System.out.println(dest);//[123, 73, 1, 999]
//replaceAll()
//Collections提供了多个synchronizedXxx方法将线程不安全的转换为线程安全的
List list1 = Collections.synchronizedList(list);
//返回的list1就是线程安全的list1
}
}

浙公网安备 33010602011771号