你代码中的问号都被我以注释的形式写出来了,你可以参考一下。多看看毕老师讲的视频,自己多体会体会,多看看笔记,我学这一段的时候也是想了很久才想明白的,还有一定要多看API文档。
- <P> import java.util.*;
- class Student implements Comparable<Student>
- /*
- 当一个对象被存入到集合中时,它可以被存入到List与Map中去。如果把他存入到TreeSet或者TreeMap等底层为二叉树结构的集合中时,存入的元素必须要有有可比性!让元素实现可比性的两个方法:1 让存入的对象(例如本例中的Student类就是被存入集合中的元素)本身具有可比性,即实现Comparable接口,2 在构造TreeSet或TreeMap时,传入比较器Comparator对象。
- 如果集合是ArrayList的话,Student类其实根本不用实现Comparable接口,因为ArrayList底层是数组结构,按照自己的编号排序。
- 如果集合是HashSet或者HashMap的话,Student类照样也不用实现Comparable接口,因为它们底层是Hash值,按照自身的Hash值进行排序。
- 让Student类实现Comparable接口的目的,其实只是为了避免Student类被存入到了二叉树结构的集合中。
- 在你这个代码中,最后将Students类存入到了HashMap中,其实完全可以不让Students实现Comparable接口。
- */
- {
- private String name;
- private int age;
- Student(String name,int age)
- {
- this.name=name;
- this.age=age;
- }
- public int compareTo(Student s)
- /*
- 这句话没什么意思。Students类实现了Comparable接口,就要复写Comparable接口中的comparTo方法。不理解的话可以看一下老毕的视频,day07中有关于接口的详细讲解。你自己再查阅一下API文档java.lang.Comparable就能知道了。
- */
- {
- int num=new Integer(this.age).compareTo(new Integer(s.age));
- /*
- 查看API文档,Comparable.compareTo()方法的返回值为int。这句话是什么意思呢?new Integer(this.age).compareTo(new Integer(s.age))其实就是往集合中每存入一个Students类,就把存入的Students的age值与集合中已经存在的Students对象的age值相减!如new Integer(3).compareTo(new Integer(2))=1,详见API文档java.lang.Integer的compareTo方法。
- 其实num的值完全也可以写作 this.age - s.age
- */
- if(num==0)
- /*
- 这句话是说,如果即将存入的Students的age值与集合中某一个Students类的age值相同,那么就让他们的另一个属性,即name属性进行比较。使用的同样也是String类的compareTo方法。String类的compareTo方法是将字符串按字典顺序相减。如: "abc".compareTo("abb")=1
- */
- return this.name.compareTo(s.name);
- return num;
- }
- public int hashCode()
- /*
- 这个是为了保证元素在存入到底层为Hash值的集合时不重复。HashSet和HashMap的底层都是Hash值结构,通过hash值来保证元素的唯一。
- 当Students对象被存入到HashSet或者HashMap中时, hm.put(new Student("lisi1",21),"beijing"),这时new Student("lisi1",21)作为一个匿名对象出现,这个对象会有自己的一个Hash值(具体Hash值的算法我也不知道)。当你再往集合中存入new Student("lisi1",21)时,又会在内存中出现一个匿名对象,他们的Hash值是不同的!所以,如果你的Students类不复写hashCode方法,这两个new Student("lisi1",21),"beijing")都会被存入进去!
- 但是当你复写了hashCode方法以后,这两个匿名对象都不会按照以前的那个方法计算hash值了,而是按照你给定的方法计算各自的hash值。
- */
- {
- return name.hashCode()+age*34;
- /*
- 这个是指你想让Students类怎样计算自己的Hash值。默认Hash值的算法是很麻烦的,基本上new一个对象就有一个hash值。但是你自己手动复写了hash值算法,让他们只比较姓名和年龄,这样的话hash值就会相同。例如:new Student("lisi1",21),如果按照默认的算法,hash值为11223344,当你再new一个Student("lisi1",21),按照默认算法,hash值可能就变成了33445566。但是你的目的是想让姓名年龄相同视为同一个人,所以你就让他们的只比较姓名和年龄这两个元素就可以了。
- age*34是为了Hash值偶然相同。比方说,"lisi"字符串的Hash值为40,年龄为20, 而"wangwu"字符串的hash值为32,年龄为28,name.hashCode()+age都等于60.为了避免出现这样的情况,让就age随便乘以一个基数,那样 40+20*34就不再等于32+28*34了
- */
- }
- public boolean equals(Object obj)
- /*
- 当Hash值相同时,才会调用equals方法对照内容进行比较。比方说,"lisi".hashCode()=40,age =20, "wangwu".hashCode()=720,age=0,那么lisi.hashCode()+age*34正好等于 wangwu.hashCode()+age*34,但是这两个人却不是同一个人!所以此时就需要调用equals方法对内容进行比较!
- */
- {
- if(!(obj instanceof Student))
- throw new ClassCastException("类型不匹配");
- Student s=(Student)obj;
- return this.name.equals(s.name) && this.age==s.age;
- //对学生的姓名和年龄进行比较,如果返回为true,那就说明这个学生已经存入到了集合中,不会再存入,即集合中已经有了一个lisi,20,反之,则存入
- }
- public String getName()
- {
- return name;
- }
- public int getAge()
- {
- return age;
- }
- public String toString()
- {
- return name+".."+age;
- }
- }
- class MapTest
- {
- public static void main(String[] args)
- {
- HashMap<Student,String> hm=new HashMap<Student,String>();
- hm.put(new Student("lisi1",21),"beijing");
- hm.put(new Student("lisi2",22),"shaghan");
- hm.put(new Student("lisi3",23),"nanjing");
- hm.put(new Student("lisi4",24),"wuhan");
- //第一种取出方式 keySet
- Set<Student> keySet=hm.keySet();
- Iterator<Student> it=keySet.iterator();
- while(it.hasNext())
- {
- Student stu=it.next();
- String addr=hm.get(stu);
- System.out.println(stu+".."+addr);
- }
- }
- </P>
复制代码 |