JavaSe总结-17- 集合框架(3)

来源:互联网 发布:mac珊瑚红是什么色号 编辑:程序博客网 时间:2024/05/23 00:37

17.01 ArrayList集合的toString()方法源码解析
17.02 Set集合概述及特点
17.03 HashSet存储字符串并遍历
17.04 HashSet保证元素唯一性的源码解析
17.05 HashSet存储自定义对象并遍历
17.06 HashSet保证元素唯一性的代码体现
17.07 LinkedHashSet的概述和使用
17.08 TreeSet存储Integer类型的元素并遍历
17.09 TreeSet保证元素排序的源码解析
17.10 TreeSet保证元素唯一性和自然排序的原理和图解
17.11 TreeSet存储自定义对象并遍历练习1
17.12 TreeSet存储自定义对象并遍历练习2
17.13 TreeSet保证元素唯一性和比较器排序的原理及代码实现
17.14 TreeSet对元素排序的总结
17.15 产生10个1-20之间的随机数要求随机数不能重复案例简洁版
17.16 键盘录入学生信息按照总分排序后输出在控制台案例

17.01 ArrayList集合的toString()方法源码解析

代码:

Collection c = new ArrayList();

c.add("hello");

c.add("world");

c.add("java");

 

System.out.println(c);

  

输出c时默认调用的是c的toString()方法

A:Collection c = new ArrayList();

这是多态,所以输出c的 toString()方法,其实是输出ArrayList的toString()方法

B:看 ArrayList 的 toString()方法

在ArrayList里面却没有发现toString()。应该去父类查找→ AbstractList → AbstractCollection

C:toString()的方法源码

 1 public String toString()  2 { 3     Iterator<E> it = iterator(); //集合本身调用迭代器方法,得到集合迭代器 4     if (! it.hasNext()) 5         return "[]"; 6  7     StringBuilder sb = new StringBuilder(); 8     sb.append('['); 9     for (;;) 10     {11         E e = it.next(); //e=hello,world,java12         sb.append(e == this ? "(this Collection)" : e);13         if (! it.hasNext())14             //[hello, world, java]15             return sb.append(']').toString();16         sb.append(',').append(' ');17     }18 }

17.02 Set集合概述及特点

Set接口概述:一个不包含重复元素的 collection

特点:

无序(存入与取出的顺序不一致)

唯一(存入集合的元素唯一)

17.03 HashSet存储字符串并遍历

HashSet类概述:不保证 set 的迭代顺序,特别是它不保证该顺序恒久不变。此类允许使用 null 元素。

例:

复制代码
 1 public class Practice  2 { 3     public static void main(String[] args) 4     { 5         HashSet<String> hs = new HashSet<String>(); 6         hs.add("hello"); 7         hs.add("world"); 8         hs.add("world"); 9         hs.add("java");10         11         for (String s : hs) 12         {13             System.out.println(s);14         }15     }16 }
复制代码

运行结果:

hellojavaworld

17.04 HashSet保证元素唯一性的源码解析

复制代码
 1 interface Collection 2 {...} 3  4 interface Set extends Collection  5 {...} 6  7 class HashSet implements Set  8 { 9     private static final Object PRESENT = new Object();10     private transient HashMap<E,Object> map;11     12     public HashSet() 13     {14         map = new HashMap<>();15     }16     17     public boolean add(E e) 18     { //e=hello,world19         return map.put(e, PRESENT)==null;20     }21 }22 23 class HashMap implements Map 24 {25     public V put(K key, V value) 26     { //key=e=hello,world27     28         //看哈希表是否为空,如果空,就开辟空间29         if (table == EMPTY_TABLE) 30         {31             inflateTable(threshold);32         }33         34         //判断对象是否为null35         if (key == null)36             return putForNullKey(value);37         38         int hash = hash(key); //和对象的hashCode()方法相关39         40         //在哈希表中查找hash值41         int i = indexFor(hash, table.length);42         for (Entry<K,V> e = table[i]; e != null; e = e.next) 43         {44             //这次的e其实是第一次的world45             Object k;46             if (e.hash == hash && ((k = e.key) == key || key.equals(k))) 47             {48                 V oldValue = e.value;49                 e.value = value;50                 e.recordAccess(this);51                 return oldValue;52                 //走这里其实是没有添加元素53             }54         }55 56         modCount++;57         addEntry(hash, key, value, i); //把元素添加58         return null;59     }60     61     transient int hashSeed = 0;62     63     final int hash(Object k) 64     { //k=key=e=hello,65         int h = hashSeed;66         if (0 != h && k instanceof String) 67         {68             return sun.misc.Hashing.stringHash32((String) k);69         }70 71         h ^= k.hashCode(); //这里调用的是对象的hashCode()方法72 73         // This function ensures that hashCodes that differ only by74         // constant multiples at each bit position have a bounded75         // number of collisions (approximately 8 at default load factor).76         h ^= (h >>> 20) ^ (h >>> 12);77         return h ^ (h >>> 7) ^ (h >>> 4);78     }79 }
复制代码

通过查看add方法的源码,知道这个方法底层依赖两个方法:hashCode()和equals()。

 

判断元素唯一性的方式:通过对象的hashCode和equals方法来完成元素唯一性

如果对象的hashCode值不同,那么不用判断equals方法,就直接存储到哈希表中。

如果对象的hashCode值相同,那么要再次判断对象的equals方法是否为true。

如果为true,视为相同元素,不存。如果为false,那么视为不同元素,就进行存储。

 

如果类没有重写这两个方法,默认使用的Object()。一般来说不会相同。

17.05 HashSet存储自定义对象并遍历

复制代码
 1 public class Practice  2 { 3     public static void main(String[] args) 4     { 5         HashSet<Student> hs = new HashSet<Student>(); 6          7         hs.add(new Student("小明",23)); 8         hs.add(new Student("旺财",12)); 9         hs.add(new Student("旺财",12));10         hs.add(new Student("小强",24));11         hs.add(new Student("小明",22));12         hs.add(new Student("小红",22));13         14         for(Student s : hs)15         {16             System.out.println(s.getName()+":"+s.getAge());17         }18     }19 }
复制代码

 17.06 HashSet保证元素唯一性的代码体现

上例中重复元素被存入到了集合中,因为Student没有重写hashCode和equals方法,默认使用的Object()的hashCode和equals方法,一般来说结果不会相同,所以存入到了集合中,Student类应重写hashCode和equals方法(自动生成)。

复制代码
 1    @Override 2     public int hashCode()  3     { 4         final int prime = 31; 5         int result = 1; 6         result = prime * result + age; 7         result = prime * result + ((name == null) ? 0 : name.hashCode()); 8         return result; 9     }10 11     @Override12     public boolean equals(Object obj) 13     {14         if (this == obj)15             return true;16         if (obj == null)17             return false;18         if (getClass() != obj.getClass())19             return false;20         Student other = (Student) obj;21         if (age != other.age)22             return false;23         if (name == null) 24         {25             if (other.name != null)26                 return false;27         } else if (!name.equals(other.name))28             return false;29         return true;30     }
复制代码

 17.07 LinkedHashSet的概述和使用

LinkedHashSet类概述:

元素有序唯一:由链表保证元素有序、由哈希表保证元素唯一

例:

复制代码
 1 public class Practice  2 { 3     public static void main(String[] args) 4     { 5         LinkedHashSet<String> hs = new LinkedHashSet<String>(); 6         hs.add("hello"); 7         hs.add("world"); 8         hs.add("world"); 9         hs.add("java");10         11         for(String s : hs)12         {13             System.out.println(s);14         }15     }16 }
复制代码

 运行结果:

helloworldjava

17.08 TreeSet存储Integer类型的元素并遍历

TreeSet类概述:使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。

例:

复制代码
 1 public class Practice  2 { 3     public static void main(String[] args) 4     { 5         TreeSet<Integer> ts = new TreeSet<Integer>(); 6         ts.add(20); 7         ts.add(18); 8         ts.add(23); 9         ts.add(22);10         ts.add(17);11         ts.add(24);12         ts.add(19);13         ts.add(18);14         15         for(Integer i : ts)16         {17             System.out.print(i+" ");18         }19     }20 }
复制代码

运行结果:

17 18 19 20 22 23 24 

17.09 TreeSet保证元素排序的源码解析

复制代码
 1 interface Collection {...} 2  3 interface Set extends Collection {...} 4  5 interface NavigableMap {} 6  7 class TreeMap implements NavigableMap  8 { 9      public V put(K key, V value) 10     {11         Entry<K,V> t = root;12         if (t == null) 13         {14             compare(key, key); // type (and possibly null) check15 16             root = new Entry<>(key, value, null);17             size = 1;18             modCount++;19             return null;20         }21         int cmp;22         Entry<K,V> parent;23         // split comparator and comparable paths24         Comparator<? super K> cpr = comparator;25         if (cpr != null) 26         {27             do 28             {29                 parent = t;30                 cmp = cpr.compare(key, t.key);31                 if (cmp < 0)32                     t = t.left;33                 else if (cmp > 0)34                     t = t.right;35                 else36                     return t.setValue(value);37             } while (t != null);38         }39         else 40         {41             if (key == null)42                 throw new NullPointerException();43             Comparable<? super K> k = (Comparable<? super K>) key;44          do 45             {46                 parent = t;47                 cmp = k.compareTo(t.key);48                 if (cmp < 0)49                     t = t.left;50                 else if (cmp > 0)51                     t = t.right;52                 else53                     return t.setValue(value);54             } while (t != null);55         }56         Entry<K,V> e = new Entry<>(key, value, parent);57         if (cmp < 0)58             parent.left = e;59         else60             parent.right = e;61         fixAfterInsertion(e);62         size++;63         modCount++;64         return null;65     }66 }67 68 class TreeSet implements Set 69 {70     private transient NavigableMap<E,Object> m;71     72     public TreeSet() 73     {74          this(new TreeMap<E,Object>());75     }76 77     public boolean add(E e) 78     {79         return m.put(e, PRESENT)==null;80     }81 }
复制代码

 

 

真正的比较是依赖于元素的compareTo()方法,而这个方法是定义在 Comparable里面的。

所以,要想重写该方法,就必须是先实现 Comparable接口。这个接口表示的就是自然排序。

17.10 TreeSet保证元素唯一性和自然排序的原理和图解

 

17.11 TreeSet存储自定义对象并遍历练习1

Student类实现自然排序接口Comparable,重写compareTo()方法

复制代码
1 @Override2 public int compareTo(Student s) 3 {4     //主要条件,按年龄排5     int num = this.age - s.age;6     //次要条件,年龄相同按姓名排7     int num2 = (num == 0)?this.name.compareTo(s.name):num;8     return num2;9 }
复制代码

 

17.12 TreeSet存储自定义对象并遍历练习2

Student类实现自然排序接口Comparable,重写compareTo()方法

复制代码
 1 @Override 2 public int compareTo(Student s)  3 { 4     // 主要条件 姓名的长度 5     int num = this.name.length() - s.name.length(); 6     // 姓名的长度相同,比较姓名的内容是否相同 7     int num2 = num == 0 ? this.name.compareTo(s.name) : num; 8     // 姓名的长度和内容相同,比较年龄是否相同,继续判断年龄 9     int num3 = num2 == 0 ? this.age - s.age : num2;10     return num3;11 }
复制代码

 

17.13 TreeSet保证元素唯一性和比较器排序的原理及代码实现

复制代码
 1 // 比较器排序,让集合具备比较性,匿名内部类实现 2 TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>()  3 { 4     @Override 5     public int compare(Student s1, Student s2)  6     { 7         // 姓名长度 8         int num = s1.getName().length() - s2.getName().length(); 9         // 姓名内容10         int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;11         // 年龄12         int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;13         return num3;14     }15     16 });
复制代码

 

17.14 TreeSet对元素排序的总结

唯一性:根据比较的返回的是否是0来决定

排序: 1.自然排序,一个类的元素想要进行自然排序就必须实现自然排序接口Comparable(元素具备比较性)

     2.比较器排序,让集合的构造方法接收一个比较器接口的子类对象Comparator(集合具备比较性)

17.15 产生10个1-20之间的随机数要求随机数不能重复案例简洁版

编写一个程序,获取10个1至20的随机数,要求随机数不能重复。

复制代码
 1 public class Practice  2 { 3     public static void main(String[] args) 4     { 5         // 创建随机数对象 6         Random r = new Random(); 7  8         // 创建一个Set集合 9         HashSet<Integer> ts = new HashSet<Integer>();10 11         // 判断集合的长度是不是小于1012         while (ts.size() < 10) 13         {14             int num = r.nextInt(20) + 1;15             ts.add(num);16         }17 18         // 遍历Set集合19         for (Integer i : ts) 20         {21             System.out.println(i);22         }23     }24 }
复制代码

 

17.16 键盘录入学生信息按照总分排序后输出在控制台案例

Student类

复制代码
 1 public class Student 2 { 3     private String name; 4     private int chinese; 5     private int math; 6     private int english; 7     public Student(String name, int chinese, int math, int english)  8     { 9         super();10         this.name = name;11         this.chinese = chinese;12         this.math = math;13         this.english = english;14     }15     public String getName() 16     {17         return name;18     }19     public void setName(String name) 20     {21         this.name = name;22     }23     public int getChinese() 24     {25         return chinese;26     }27     public void setChinese(int chinese) 28     {29         this.chinese = chinese;30     }31     public int getMath() 32     {33         return math;34     }35     public void setMath(int math) 36     {37         this.math = math;38     }39     public int getEnglish() 40     {41         return english;42     }43     public void setEnglish(int english) 44     {45         this.english = english;46     }47     48     public int getSum()49     {50         return this.chinese+this.english+this.math;51     }52 }
复制代码

 

测试类

复制代码
 1 public class Practice  2 { 3     public static void main(String[] args) 4     { 5         TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>()  6         { 7             @Override 8             public int compare(Student s1, Student s2)  9             {10                 //按总分比较11                 int num1 = s2.getSum() - s1.getSum();12                 //总分相同按语文成绩比较13                 int num2 = num1==0?s1.getChinese() - s2.getChinese():num1;14                 //语文成绩相同按数学成绩比较15                 int num3 = num2==0?s1.getMath() - s2.getMath():num2;16                 //数学成绩相同按英语成绩比较17                 int num4 = num3==0?s1.getChinese() - s2.getChinese():num3;18                 //英语成绩相同按姓名比较19                 int num5 = num4==0?s1.getName().compareTo(s2.getName()):num4;20                 return num5;21             }22         });23         for (int i = 1; i <= 5; i++) 24         {25             Scanner sc = new Scanner(System.in);26             System.out.println("请输入第"+i+"位学生的姓名");27             String name = sc.nextLine();28             System.out.println("请输入第"+i+"位学生的语文成绩");29             String chinese = sc.nextLine();30             System.out.println("请输入第"+i+"位学生的数学成绩");31             String math = sc.nextLine();32             System.out.println("请输入第"+i+"位学生的英语成绩");33             String english = sc.nextLine();34             35             Student s = new Student(name, Integer.parseInt(chinese), Integer.parseInt(math), Integer.parseInt(english));36             ts.add(s);37         }38         System.out.println("学生信息如下");39         System.out.println("姓名\t语文\t数学\t英语\t总分");40         for(Student s:ts)41         {42             System.out.println(s.getName()+"\t"+s.getChinese()+"\t"+s.getMath()+"\t"+s.getEnglish()+"\t"+s.getSum());43         }44     }45 }
复制代码

 

运行结果:

0 0
原创粉丝点击