1.Map接口
1.1概述
java。util接口Map<k,v>
类型参数:K-表示此映射所维护的键V-表示此映射所维护的对应的值
也叫做哈希表,散列表,常用于键值对结构的数据,其中键不能重复,值可以重复
1.2特点:
1。Map可以根据键来提取对应的值
2.Map的键不容许重复,对应的值会被覆盖
3.Map存放的都是无序的数据
4.Map的初始容量是16,默认的加载因子是0.75
TIPS源码摘抄
static final int DEFAULT_INTIAL_CAPACITY = 1<<4;
初始容量是1<<4,相当于1*(2^4),也就是16
static final floatDEFAULT_LOAD_FACTOR = 0.75f.
默认的加载因子是0.75f,也就是存到75%扩容,按照2的次幂进行扩容
1.3继承结构
1.4常用方法
学习Map中的方法即可
1.5练习:Map常用方法测试
2.HashMap
2.1前言
2.2HashMap的存储过程
1.HashMap的结构是数组+链表 或者 数组+红黑树 的形式
2.HashMap底层的Entry[] 数组初始容量为16,加载因子是0.75,扩容按约为2倍扩容。
3.当存放数据时,会根据hash(key)%n算法来计算数据的存放位置,n就是数组的长度,其实也就是集合的容量。
4.当计算到的位置之前没有存过数据的时候,会直接存放数据。
5.当计算的位置,有数据时,会发生hash冲突、hash碰撞
解决的办法就是采用链表的结构,在数组指定位置处以后元素之后插入新的元素
也就是说数组中的元素都是最早加入的节点。
6,如果链表的长度>8且数组长度>64时,链表会转为红黑树,当链表的长度<6时,红黑树会重新恢复成链表。
/*本类用于完成Map集合的相关练习*/
//需求:提示并接收用户输入的一串字符,并统计输出每个字符出现的次数
TestHashMap{
//1.提示并接收用户输入的数据
P(“ ”);
String input = new Scannre(System.in).nextLine();
//fhiuwhfw
//2.生成对应的map集合,格式:{f-2,h=2,i=1.。。。}
/*统计的是每个字符出现的次数,所以字符是char类型,次数是int类型
*但注意:字符不能重复,所以作为KEY,泛型使用时需要转成引用类型*/
Map<Character,Integer> map = new HashMap<>();
//3.循环遍历用户输入的字符串
//String底层维护的是char[],从0开始,最大下标是字符串的长度-1
for(int i = 0; i < input.length(); i++){
char key = input.charAt(i);
P(“”+i+“”+key);
/*字符统计案例*/
//4.统计当前字符之前是否存过
Integer value = map.get(key);//先拿着key到map中找对应次数value
if(value == null){//为null说明这个字符之前没存过,第一次出现
map.put(key,1);//存的数据就是当前字符的次数为1
}else{//如果不为null,说明之前存过
map.put(key,value+1);//存的数据就是当前字符的次数+1
}
}
P(“ ”);
P(map);
}
Set
3.1概述
1、set是一个不包含重复数据的Collection。
2,Set集合中的数据是无序的,(因为Set集合没有下标)。
3.Set集合中的元素不可以重复-常用来给数据去重。
3.2.Set集合的特点
1.数据无序且数据不容许重复。
2.HashSet:底层是哈希表,包装了HashMap。相当于向HashSet中存入数据时,会把数据作为K
,存入内部的HashMap中。当然K仍然不许重复。
3.TreeSet:底层是TreeMap,也是红黑树的形式,便于查找数据。
/*本类用于测试Set*/
TestSet{
main{
//1.创建集合对象
//Set<String> set = new Set();
Set<String> set = new HashSet<>();
//2.存入数据
set.add("ad");
set.add("ja");
set.add("ja");
P(set);
set.add(null);向set集合存入null值
set.add("null");向set集合存入null字符串
/*1.set集合中的元素都是无序的*/
/*2.set结合中的元素不重复*/
/*3.set集合容许存放null值,但也最多存一个*/
//3.常用方法测试
//clear();
//contains()
//hashCode();
//isEmpty();
//remove();
//size();
//toArray();
集合间的操作
//addAll();
//containsAll();
removeAll();
retainAll();
//5集合的迭代--iterator();
/*总结:自定义对象Student如果想要去重*
*需要在Student类中手动添加重写的HashCode()与equals()*
*这样重写后就根据对象的类型+属性值判断是否为同一个对象了*
*而不是根据对象的地址值判断,因为Object默认实现判断的是==地址值*/
//6.自定义对象去重
Set<Student> set2 = new HashSet<>();
Student s1 = new Student(age,name,gender);
Student s2 = new Student(age,name,gender);
Student s3 = new Student(age,name,gender);
set2.add(s1);
set2.add(s2);
set2.add(s3);
P(set2)://打印的是地址值。在Student里重写toString
//3创建多个手机类对象
Phone p1 = new Phone();
Phone p2 = new Phone();
Phone p3 = new Phone();
//4.1创建一个新集合用来存放手机对象
Set<Phone> set2 = new HashSet<>():
//4.2将创建好的自定义类的对象存入set中
set.add(p1);
set.add(p2);
set.add(p3);
P(set2);
P(p1 == p2);//false
/*在手机类Phone中添加了重写的equals()与hashCode()以后
*p1与p3对象就是不再判断地址值了,而是根据类型与所有属性值做比较*
*如果两个对象的类型与所有属性值一致,就认为是同一个对象*
*这样就实现了set集合自定义对象的去重效果。*/
P(p2);
}
}
public class Student{
//2创建属性
String name;
int id;
//3提供本类的全参构造
public Student(String name, int id){
this.name = name;
this.id = id;
}
//3.2提供学生类的toString()
@Override
puvlic String toString(){
return "Student{" +
"name=' " + name + '\' ' +
", id =" + id +
'}';
}
//3.3添加学生类重写的equals()与hashCode()
@Override
public boolean equals(Object o){
if (this == o) return true;
if (o == null || getClass() != o.getclass()) return false;
Student student = (Student) o;
return id == student.id && Objects.equals(name,student.name);
}
@Override
public int hashCode(){
return Objects.hash(name, id);
}
}
/*创建自定义类手机类*/
public class Phone{
//1.提供手机类的属性
String brand;//品牌
double price;//价格
String color;//颜色
//2生成全参构造
//右键-》Generate——》Constructor——》全选属性——》OK
public Phone(String brand,double price,String color){
this.brand =brand;
this.price = price;
this.color = color;
}
//3,如果不重写,默认使用的是Object的toStrign(),
打印的是对象的地址值。
@Override
public String toString(){
return "Phone{"+"brand'"+brand+'\''+",color'"+color+'\' '+'}';
}
}
set集合的特点
1.set集合没有重复的元素
2.set集合的元素是无序的
3.set集合可以存null值,并且null最多有一个
4.我们自定义对象如果想去重,需要在自定义类中添加重写的equals()与
hashCode()。
##集合学习的方法
学习父级的公共方法,学习子类的创建方式,学习各种集合的特点。
关于List大多都是与下标有关的操作
关于Set通常都是去重的操作
关于map通常都是映射关系,也就是键值对
API要常练习,方法之间没有任何关系,用哪个,查哪个。
4.拓展
HashMap扩容
成长因子
static final float DEFAULT_LOAD_FACTOR = 0.75f.
前面的讲述已经发现,当你空间只有仅仅为10的时候是很容易造成2个对象的hashcode多对应的地址
是一个位置的情况。这样就会造成2个对象后形成散列桶(链表)。这时就有一个加载因子的参数,值默认为0.75,如果你hashmap的空间有100,俺么当你插入了75个元素的时候hashmap就需要扩容了,不然会形成很长的散列桶结构,对于查询和插入都会增加时间,因为他要一个一个的equals比较。但又不能让加载因子很小,如0.01,这样显然是不合适的,频繁扩容会大大消耗你的内存。这时就存在着一个平衡,jdk中默认是0.75.当然负载因子可以根据自己的实际情况进行调整。