
P519set接口实现类HashSet
public class HashSetStructure {
public static void main(String[] args) {
//模拟一个HashSet的底层(HashMap的底层)
//1.创建1个数组,数组的类型是Node[]
//2.有些人直接把Node数组成为表
Node[] table =new Node[16];
System.out.println("table="+table);
//3.创建结点
Node john = new Node("john2",null);
table[2]=john;
Node jack=new Node("jack3",null);
john.next=jack;//将jack挂点挂载到john
Node rose = new Node("Rose4", null);
Node lucy = new Node("lucy5", null);
table[3]=lucy;//把lucy放到table表的索引
jack.next=rose;//将rose结点挂载到jack
System.out.println("table="+table);
}
}
class Node {//结点存储数据,可以指向下一个,从而形成链表
Object item;//存放数据
Node next;//指向下一个结点
public Node(Object item, Node next) {
this.item = item;
this.next = next;
}
}
P520HashSet扩容机制
到达8个进行树化
P521HashSet源码解读
public class HashSetSource {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
hashSet.add("java");//到此位置,第1 次add 分析完毕.
hashSet.add("php");//到此位置,第2 次add 分析完毕
hashSet.add("java");
System.out.println("set=" + hashSet);//输出set=[java, php]
}
}
P523JavaSet底层机制说明,分析HashSet的扩容和转成红黑树机制
public class HashSetSource {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
for (int i = 1; i <=7 ; i++) {//在table 的某一条链表上添加了7 个A 对象
hashSet.add(new A(i));
}
for (int i = 1; i <=7 ; i++) {//在table 的另一条链表上添加了7 个B 对象
hashSet.add(new B(i));
}
System.out.println(hashSet);
}
}
class B{
private int n;
public B(int n) {
this.n = n;
}
@Override
public int hashCode(){
return 50;
}
}
class A{
private int n;
public A(int n) {
this.n = n;
}
@Override
public int hashCode(){
return 100;
}
}
P525set接口实现类
public class HashSetE1 {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
hashSet.add(new E("y1",1));
hashSet.add(new E("y2",2));
hashSet.add(new E("y1",1));
System.out.println(hashSet);
}
}
class E{
private String name;
private int age;
public E(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "E{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {//如果name 和age 值相同,则返回相同的equals
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
E e = (E) o;
return age == e.age &&
Objects.equals(name, e.name);
}
@Override
public int hashCode() //如果name 和age 值相同,则返回相同的hash 值
return Objects.hash(name, age);
}
}
复习,之前先算hashcode()转换成索引值,如该位置无,直接添加。
若已经有了,进行equals进行判断,相等就不加,不等的话就在后面添加为链表
public class HSE2 {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
hashSet.add(new Em("y1",111,new MyDate(21,1,1)));
hashSet.add(new Em("y1",111,new MyDate(21,2,1)));
hashSet.add(new Em("y1",111,new MyDate(21,1,1)));
System.out.println(hashSet);
}
}
class Em{
private String name;
private double sal;
private MyDate birthday;
public Em(String name, double sal, MyDate birthday) {
this.name = name;
this.sal = sal;
this.birthday = birthday;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Em em = (Em) o;
return Objects.equals(name, em.name) &&
Objects.equals(birthday, em.birthday);
}
@Override
public int hashCode() {
return Objects.hash(name, birthday);
}
@Override
public String toString() {
return "Em{" +
"name='" + name + ''' +
", sal=" + sal +
", birthday=" + birthday +
'}';
}
}
class MyDate{
private int year;
private int moth;
private int day;
public MyDate(int year, int moth, int day) {
this.year = year;
this.moth = moth;
this.day = day;
}
@Override
public String toString() {
return "MyDate{" +
"year=" + year +
", moth=" + moth +
", day=" + day +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyDate myDate = (MyDate) o;
return year == myDate.year &&
moth == myDate.moth &&
day == myDate.day;
}
@Override
public int hashCode() {
return Objects.hash(year, moth, day);
}
}
P527linkedHashSet
public class linkedHashSetSource {
public static void main(String[] args) {
Set set = new linkedHashSet();
set.add(new String("A"));
set.add(456);
set.add(456);
set.add(new Customer("liu",1001));
set.add(123);
set.add("HSP");
System.out.println(set);//输出[A, 456, New.Customer@10f87f48, 123, HSP]
//1.linkedHHashSet加入顺序和取出元素的顺序
//2.linkedHHashSet底层维护的是一个linkedHHashMap(是HashMap的子类)
//3.linkedHashSet底层结构i(数组table和双向链表)
//4.添加第一次的时候,直接将数组Table扩容到16,存放的结点类型是linkedHashMap$Entry
//5.数组是HashMap$Node[]存放的元素/数据是linkedHashMap$Entry类型
}
}
class Customer{
private String name;
private int no;
public Customer(String name, int no) {
this.name = name;
this.no = no;
}
}
P529set接口实现类
public class linkedHashSetE {
public static void main(String[] args) {
linkedHashSet lkht = new linkedHashSet();
lkht.add(new Car("1a",1));
lkht.add(new Car("1B",2));
lkht.add(new Car("1c",3));
lkht.add(new Car("1d",4));
lkht.add(new Car("1c",5));
lkht.add(new Car("1B",2));
System.out.println(lkht);
}
}
class Car{
private String name;
private double price;
public Car(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Car car = (Car) o;
return Double.compare(car.price, price) == 0 &&
Objects.equals(name, car.name);
}
@Override
public int hashCode() {
return Objects.hash(name, price);
}
@Override
public String toString() {
return "nCar{" +
"name='" + name + ''' +
", price=" + price +
'}';
}
}
P530Map接口的特点
public class Map_ {
public static void main(String[] args) {
//老韩解读Map 接口实现类的特点, 使用实现类HashMap
// 1. Map 与Collection 并列存在。用于保存具有映射关系的数据:Key-Value(双列元素)
// 2. Map 中的key 和value 可以是任何引用类型的数据,会封装到HashMap$Node 对象中
// 3. Map 中的key 不允许重复,原因和HashSet 一样,前面分析过源码.
// 4. Map 中的value 可以重复
// 5. Map 的key 可以为null, value 也可以为null ,
// 注意key 为null,只能有一个,value 为null ,可以多个
//6. 常用String 类作为Map 的key
//7. key 和value 之间存在单向一对一关系,即通过指定的key 总能找到对应的value
Map map = new HashMap();
map.put("n1","1y");
map.put("n2","2y");
map.put("n1","3y");//输入{n1=3y, n2=2y},当有相同的K,就相当于替换
map.put("n3","3y");//输出{n1=3y, n2=2y, n3=3y}
//3.4.5
map.put(null,null);//{null=null, n1=3y, n2=2y, n3=3y}
map.put(null,"abc");//{null=abc, n1=3y, n2=2y, n3=3y},替换
map.put("n4",null);//{null=abc, n1=3y, n2=2y, n3=3y, n4=null}
//6
map.put(1,"m1");//{null=abc, 1=m1, n1=3y, n2=2y, n3=3y, n4=null}
System.out.println(map);//输出{n1=1y, n2=2y}
//7. 通过get 方法,传入key ,会返回对应的value
System.out.println(map.get("n1"));//输出3y
}
}
P531Map接口的特点2
public class MapSource {
public static void main(String[] args) {
Map map = new HashMap();
map.put("no1", "韩顺平");//k-v
map.put("no2", "张无忌");//k-v
//1.k-v最后是HashMap$Node node=newNode(hash,key,value,null)
//2.k-v为了程序员的遍历,还会创建EntrySet集合,该集合存放的元素的类型是Entry
//而一个Entry对象就有k,v EntrySet,
// 即为transient Set> entrySet;
//3.entrySet中,定义类型是Map.Entry,但是实际上存放的还是HashMap$Node
//这个是因为HashMap$Node implement Map.Entry
//4.当把HashMap$Node 对象存放到entrySet就方便我们遍历,因为Map.entry提供了重要的方法
//一个是getValue,一个是getkey();
Set set=map.entrySet();
System.out.println(set.getClass());//输出class java.util.HashMap$EntrySe
for (Object oBJ :set) {
System.out.println(oBJ.getClass());
//输出class java.util.HashMap$Node class java.util.HashMap$Node
//为了从 HashMap$Node中取出K-V
//先进行一个向下转型
Map.Entry entry=(Map.Entry) oBJ;
System.out.println(entry.getKey()+"t"+entry.getValue());
//输出 no2 张无忌 no1 韩顺平
}
Set set1=map.keySet();
System.out.println(set1.getClass());
Collection values = map.values();
System.out.println(values.getClass());
//输出class java.util.HashMap$KeySet,
// class java.util.HashMap$Value
}
}
P532Map接口方法
public class MapMethod {
public static void main(String[] args) {
//演示map 接口常用方法
//1.添加
Map map = new HashMap();
map.put("邓超", new Book("",100));//OK
map.put("邓超", "孙俪");//替换-> 一会分析源码
map.put("王宝强", "马蓉");//OK
map.put("宋喆", "马蓉");//OK
map.put("刘令博", null);//OK
map.put(null, "刘亦菲");//OK
map.put("gj", "gjl");//OK
map.put("hsp", "hsp 的老婆");
System.out.println("map=" + map);
// remove:根据键删除映射关系
map.remove(null);
System.out.println("map=" + map);//此时输出null=刘亦菲没有了
// get:根据键获取值
Object val = map.get("gj");
System.out.println("val=" + val);//输出val=gjl
// size:获取元素个数
System.out.println("k-v=" + map.size());//目前有6个
// isEmpty:判断个数是否为0
System.out.println(map.isEmpty());//F
// clear:清除k-v
// map.clear();
System.out.println("map=" + map);//输出{}
// containsKey:查找键是否存在
System.out.println("结果=" + map.containsKey("hsp"));//T
}
}
class Book{
private String name;
private int num;
public Book(String name, int num) {
this.name = name;
this.num = num;
}
}
P533Map的六种遍历方式
public class MapMethod {
public static void main(String[] args) {
Map map = new HashMap();
map.put("邓超", "1孙俪");//替换-> 一会分析源码
map.put("王宝强", "2马蓉");//OK
map.put("宋喆", "3马蓉");//OK
map.put("刘令博", null);//OK
map.put(null, "5刘亦菲");//OK
map.put("gj", "6gjl");//OK
map.put("hsp", "7hsp 的老婆");
System.out.println("map=" + map);
//第一组: 先取出所有的Key , 通过Key 取出对应的Value
Set keySet = map.keySet();
Iterator iterator = keySet.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(map.get(next));
}
for (Object key :keySet) {
System.out.println(map.get(key));
//输出1孙俪//3马蓉//null//5刘亦菲//6gjl//7hsp 的老婆
}
//第二组取出所有的values
Collection values = map.values();
//这里可以使用所有的collection遍历方式,增强for,iterator,
//第三组通过entrySet来取出k-v,将Node做成Entry放入Set中
Set entrySet = map.entrySet();
for (Object entry :entrySet) {
//将entry转成Map.Entry
Map.Entry m = (Map.Entry) entry;
//m提供了两个方法,getkey和getvalue
System.out.println(m.getKey()+"-"+m.getValue());
//输出邓超-1孙俪//宋喆-3马蓉//刘令博-null//null-5刘亦菲
// gj-6gjl//hsp-7hsp 的老婆//王宝强-2马蓉
}
//迭代器
Iterator iterator3 = entrySet.iterator();
while (iterator3.hasNext()) {
Object entry = iterator3.next();
//System.out.println(next.getClass());
// HashMap$Node -实现-> Map.Entry (getKey,getValue)
// 向下转型Map.Entry
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "-" + m.getValue());
}
}
}
P535课堂练习
public class MapE1 {
public static void main(String[] args) {
Map hashMap = new HashMap();
hashMap.put(1,new EM(1,111));
hashMap.put(2,new EM(2,112));
hashMap.put(3,new EM(3,113));
for (Object key : hashMap.keySet()) {
EM em = (EM) hashMap.get(key);
if(em.getSal()>112) {
System.out.println(em);
//EM{id=3, sal=113.0}
}
}
//迭代器
Set entryset = hashMap.entrySet();
Iterator iterator = entryset.iterator();
while (iterator.hasNext()) {
//Object next = iterator.next();//拿出的是Mapentry
Map.Entry entry = (Map.Entry) iterator.next();
//entry的运行类型是hashmap$Node
//通过entry取得getkey和getvalue
EM em1 = (EM) entry.getValue();
if (em1.getSal() > 112) {
System.out.println(em1);
//EM{id=3, sal=113.0}
}
}
}
}
class EM{
private int id;
private double sal;
public EM(int id, double sal) {
this.id = id;
this.sal = sal;
}
@Override
public String toString() {
return "EM{" +
"id=" + id +
", sal=" + sal +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
}
P536HMap底层机构
P537HMap的底层机制及源码剖析
public class HashMapSource1 {
public static void main(String[] args) {
HashMap map = new HashMap<>();
map.put("java", 10);//ok
map.put("php", 10);//ok
map.put("java", 20);//替换value,此时
System.out.println("map=" + map);//
}
}
P538HMap扩容树化触发
public class HashMapSource2 {
public static void main(String[] args) {
HashMap hashMap = new HashMap();
for (int i = 1; i <=12; i++) {
hashMap.put(new A(i),"hello");
}
hashMap.put("aaa","bb");
//当8的时候不树话,9扩容32,10的时候扩容64,加入11进行treeNode
System.out.println(hashMap);
//布置一个任务,自己设计代码去验证,table 的扩容
// 0 -> 16(12) -> 32(24) -> 64(64*0.75=48)-> 128 (96) ->
// 自己设计程序,验证-》增强自己阅读源码能力. 看别人代码.
}
}
class A{
private int num;
public A(int num) {
this.num = num;
}
@Override//所以对象的hashcode都一样
public int hashCode() {
return 100;
}
@Override
public String toString() {
return "nA{" +
"num=" + num +
'}';
}
}
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)