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条)