zoukankan      html  css  js  c++  java
  • 大数据第十九天

    Set集合概述

    一个不包含重复元素的 collection。

    Set集合类似于一个罐子,程序中可以把多个对象放进Set集合,但是Set集合通常不能记住这些元素的添加顺序,Set集合与Collection基本相同,没有提供额外的方法,实际上Set就是Collection,只不过是行为略有不同(不允许元素重复)

    如果试图把两个相同的元素放入同一个Set集合的话,则添加失败,add方法返回值为false,并且新元素不会被加入

    上面的这些特性是Set集合的特性,它的实现类完全符合这些特征,另外还有自己的特色

    比如:TreeSet可以排序,LinkedHashSet能保证元素有序等等

    Set集合基本功能演示

    存储字符串对象的引用并遍历

    虽然Set集合的元素无序,但是,作为集合来说,它肯定有它自己的存储顺序,而当你存放的顺序恰好和它的存储顺序一致时,会让你误以为Set是有序的,你可以多存储一些数据,就能看到效果。

    最经常使用的就是它的实现子类HashSet

    import java.util.HashSet;

    import java.util.Set;

    public class SetDemo {

        public static void main(String[] args) {

           // 创建集合对象,加泛型

           Set<String> set = new HashSet<String>();

           // 创建并添加元素

           set.add("hello");

           set.add("java");

           set.add("world");

           set.add("java");//重复字符串,不能添加

           set.add("world");

           // 增强for遍历

           for (String s : set) {

               System.out.println(s);

           }

           //除了增强for,还有其他的遍历方式么?迭代器

           //没有索引,普通for不能用;直接打印的仅是toString结果

        }

    }

    HashSet类概述

    HashSet是Set接口的典型实现,大多数情况下,都是使用的HashSet这个实现类。

    HashSet按hash算法来存储集合中的元素,因此具有很好的存取和查询性能。

    HashSet有以下特点:

    不保证元素的排列顺序,有可能与添加的顺序相同,有可能与添加的顺序不同

    特别是它不保证该顺序恒久不变,也就是说元素的顺序有可能会变化

    HashSet一般使用案例

    import java.util.HashSet;

    public class HashSetDemo {

        public static void main(String[] args) {

           // 创建集合对象,没使用多态

           HashSet<String> hs = new HashSet<String>();

           // 创建并添加元素

           hs.add("hello");

           hs.add("world");

           hs.add("java");

           hs.add("world");//想添加重复的字符串,不能添加成功

           //在访问时,有可能打印出来的结果并不是存储时的顺序

           //增强for遍历

           for (String s : hs) {

               System.out.println(s);

           }

           //迭代器遍历,这样遍历有什么好处?

           Iterator<String> it = hs.iterator();

           while(it.hasNext()){

               System.out.println(it.next());

           }

     

           for(Iterator it = hs.iterator();it.hasNext();){

               System.out.println(it.next());

           }

        }

    }

    总结:

    HashSet并不保证存储元素的顺序

    当元素个数增加时,元素的顺序会重新计算

    HashSet存储结构示意图

     

     

    HashSet如何保证元素唯一性

    HashSet保持元素唯一性的概述

    • HashSet底层数据结构是哈希表,哈希表按哈希值来存储,HashSet集合中有若干个存储区域,而每个对象可以计算出一个hash值,对应一个存储区域
    • 当添加新元素时,系统会调用这个元素的hashCode方法,计算出这个元素的hash值,然后跟存储区域的每一个元素进行比较,如果不相同则添加该新元素(占用一个新的槽位)。如果相同表明槽位已经有元素了,那么再调用元素的equals方法比较,若为false,则添加该元素到这个槽位后的链表上;若为true,则这个元素就添加不进去。
    • 简单说就是通过元素的两个方法,hashCode()和equals()来完成,如果元素的hashCode()返回值相同,再判断equals()返回值是否为true,若为true就存不进去;如果元素的hashCode()返回值不同,不会调用equals()方法,直接就能存进去

    add()方法在底层所依赖的两个方法

    保证元素唯一性就是在元素添加的时候,看集合中是否已经有相同的元素了,hashSet就是在使用add方法时,对元素是否已经存在作出判断,如果已经存在了,就不会添加,否则就添加,从而保证了集合中元素的唯一性,add方法在底层依赖以下两个方法

    • int hashCode():调用系统本地方法,返回一个int值
    • boolean equals(Object obj):默认比较的是两个对象的内存地址

    当往HashSet中添加元素时,先比较hashCode的返回值,如果相同,再调用元素的equals方法

    验证以上两个方法中,到底是谁决定了HashSet的唯一性

    //class A只重写了hashCode方法

    public class A {

        @Override

        public int hashCode() {

           return 1;//意味着所有A对象的hashCode方法返回值都为1

        }

    }

    //class B只重写了equals方法

    public class B {

        @Override

        public boolean equals(Object obj) {

           return true;//意味着所有B对象的equals方法返回值都为true

        }

    }

    //class C重写了hashCode和equals方法

    public class C {

        @Override

        public int hashCode() {

           return 2;

    //意味着所有C对象的hashCode返回值都为2,注意:与类A的对象返回值不同

        }

        @Override

        public boolean equals(Object obj) {

           return true; //意味着所有C对象的equals方法返回值都为true

        }

    }

    //测试类

    public class HashSetDemo {

        public static void main(String[] args) {

           HashSet set = new HashSet<>();

            //分别添加多个ABC对象,看最后到底有几个能被添加

           set.add(new A());

           set.add(new A());

     

           set.add(new B());

           set.add(new B());

     

           set.add(new C());

           set.add(new C());

          

           for (Object object : set) {

               System.out.println(object);

           }

        }

    }

    //打印结果,[类名]+[@]+[hashCode返回值]

    cn.test.hashset.A@1

    cn.test.hashset.A@1

    cn.test.hashset.C@2      //由于只有一个C的对象,所以这里只有一个元素

    cn.test.hashset.B@15db9742

    cn.test.hashset.B@6d06d69c

    说明:

    • 单纯的重写hashCode方法,让不同的对象hashCode返回值相同,并不能保证元素唯一性,因为还要去比较equals方法的返回值
    • 单纯的重写equals方法,让不同对象的equals返回值为true,也不能保证元素唯一性,因为hashCode方法返回值不同的话,根本就不调用此方法

    小结:

    1.自定义类创建的对象如果想要放进HashSet集合中,通常需要重写hashCode和equals方法,系统判断两个元素是相同元素的标准就是:两个元素的hashCode返回值相同并且equals方法返回值为true,所以,我们就要告诉系统什么情况下能达到上述条件

    2.当两个对象的hashCode不等的时候,直接能放进HashSet集合中不同的桶

    3.当两个对象的hashCode相等时,后一个元素是否能够添加进HashSet集合,取决于这个对象的equals方法的返回值,若为true,则不能添加,若为false,则可以添加

    4.相同hashCode,并且equals返回值为false的多个元素会以链表形式存放在同一个桶中,这样会影响集合性能,所以,在重写两个方法的时候,一定要保证equals方法返回值为false的元素hashCode方法的返回值不同,这样做是为了保证它们能分散在不同的桶中

     

     

    自定义类重写hashCode方法的原则

    重写hashCode方法的目的在于,让不同的对象能尽量落在不同的桶中,尽量避免没有关系的两个元素hashCode返回值恰巧相等,因为这样还得去比较两个元素的equals方法返回值。

    重写hashCode方法的原则有:

    • 在程序运行过程中,同一个对象多次调用hashCode方法应该返回相同的值(如果不相同的话,意味着它对应的集合中的存储位置就不同了,也就是说同一个对象可以多次添加到这个集合了)。
    • 当两个对象通过equals方法比较返回值为true时,这两个对象的hashCode方法的返回值应该为相等的值,也就是说,这两个对象是相同元素,只能添加一个
    • 对象中用作equals方法比较标准的实例变量,都应该用于计算hashCode的值

    当重写的hashCode方法返回值相同,而equals方法返回值为false的时候,这样的元素是被放在同一个桶中的,这样会影响集合的性能,如何进行优化呢?

    优化的办法就是尽可能的让equals方法返回值为false的两个元素的hashCode值尽可能的不同,也就是说,尽可能的让单个元素占用一个“桶”,而不是多个元素共用一个“桶”

    那么如何让不同的对象调用hashCode方法时返回值不同呢?

     

    由于各个对象的实例变量值一般是不同的,比如Person类中的姓名,年龄,身份证号等,这些属性值重复的概率是很低的,那就可以在hashCode方法中使用本对象的这些属性值来构建一个hash值,这样,不同的对象之间hashCode相同的概率就大大降低了

    在使用实例变量的时候需要注意,如果实例变量是一个基本数据类型的话,那就可以直接使用了,如果是一个引用数据类型的话,应该考虑到这个数据是否为null,如果为null,就用0代替,如果不是null,那就求出其对应的hash值来使用(由于是引用数据类型,其父类Object已经有了一个hashCode的方法,可以直接用)

    光是考虑这些条件就够麻烦的了,有没有简便一些的方法呢?

    当然有,强大的IDE已经为我们实现了

    自动生成hashCode和equals方法的例子

    定义完成员变量之后,从Source中自动生成重写后的hashCode和equals

    public class Student {

        private String name;

        private int age;

        public Student() {   }

        public Student(String name, int age) {

           this.name = name;

           this.age = age;

        }

        public String getName() {

           return name;

        }

        public void setName(String name) {

           this.name = name;

        }

        public int getAge() {

           return age;

        }

        public void setAge(int age) {

           this.age = age;

        }

        @Override//自动生成

        public int hashCode() {

           final int prime = 31;

           int result = 1;

           result = prime * result + age;

           result = prime * result + ((name == null) ? 0 : name.hashCode());

           return result;

        }

        @Override//自动生成

        public boolean equals(Object obj) {

           if (this == obj)

               return true;

           if (obj == null)

               return false;

           if (getClass() != obj.getClass())

               return false;

           Student other = (Student) obj;

           if (age != other.age)

               return false;

           if (name == null) {

               if (other.name != null)

                  return false;

           } else if (!name.equals(other.name))

               return false;

           return true;

        }

    }

     

     

    测试类

    import java.util.HashSet;

    public class HashSetDemo2 {

        public static void main(String[] args) {

           // 创建集合对象

           HashSet<Student> hs = new HashSet<Student>();

           // 创建学生对象

           Student s1 = new Student("tom", 27);

           Student s2 = new Student("张三", 22);

           Student s3 = new Student("张四", 30);

           Student s4 = new Student("tom", 27);

           Student s5 = new Student("tom", 20);

           Student s6 = new Student("李四", 22);

     

           // 添加元素

           hs.add(s1);

           hs.add(s2);

           hs.add(s3);

           hs.add(s4);

           hs.add(s5);

           hs.add(s6);

           // 遍历集合

           for (Student s : hs) {

               System.out.println(s.getName() + "---" + s.getAge());

           }

        }

    }

     

    HashSet集合存储自定义对象并遍历

    重点看自定义类存在多个成员变量时,使用IDE的优势

    public class Dog {

        private String name;

        private int age;

        private String color;

        private char sex;

        public Dog() {}

        public Dog(String name, int age, String color, char sex) {

           this.name = name;

           this.age = age;

           this.color = color;

           this.sex = sex;

        }

        public String getName() {

           return name;

        }

        public void setName(String name) {

           this.name = name;

        }

        public int getAge() {

           return age;

        }

        public void setAge(int age) {

           this.age = age;

        }

        public String getColor() {

           return color;

        }

        public void setColor(String color) {

           this.color = color;

        }

        public char getSex() {

           return sex;

        }

        public void setSex(char sex) {

           this.sex = sex;

        }

    //自动生成的hashCode方法和equals方法

        @Override

        public int hashCode() {

           final int prime = 31;

           int result = 1;

           result = prime * result + age;

           result = prime * result + ((color == null) ? 0 : color.hashCode());

           result = prime * result + ((name == null) ? 0 : name.hashCode());

           result = prime * result + sex;

           return result;

        }

        @Override

        public boolean equals(Object obj) {

           if (this == obj)

               return true;

           if (obj == null)

               return false;

           if (getClass() != obj.getClass())

               return false;

           Dog other = (Dog) obj;

           if (age != other.age)

               return false;

           if (color == null) {

               if (other.color != null)

                  return false;

           } else if (!color.equals(other.color))

               return false;

           if (name == null) {

               if (other.name != null)

                  return false;

           } else if (!name.equals(other.name))

               return false;

           if (sex != other.sex)

               return false;

           return true;

        }

    }

    测试类

    import java.util.HashSet;

    public class DogDemo {

        public static void main(String[] args) {

           // 创建集合对象

           HashSet<Dog> hs = new HashSet<Dog>();

     

           // 创建狗对象

           Dog d1 = new Dog("AA", 25, "红", '男');

           Dog d2 = new Dog("BB", 22, "黑", '女');

           Dog d3 = new Dog("AA", 25, "红", '男');//

           Dog d4 = new Dog("AA", 20, "红", '女');

           Dog d5 = new Dog("CC", 28, "白", '男');

           Dog d6 = new Dog("DD", 23, "黄", '女');

           Dog d7 = new Dog("DD", 23, "黄", '女');//

           Dog d8 = new Dog("DD", 23, "黄", '男');

     

           // 添加元素

           hs.add(d1);

           hs.add(d2);

           hs.add(d3);

           hs.add(d4);

           hs.add(d5);

           hs.add(d6);

           hs.add(d7);

           hs.add(d8);

           // 遍历

           for (Dog d : hs) {

               System.out.println(d.getName() + "---" + d.getAge() + "---"

                      + d.getColor() + "---" + d.getSex());

           }

        }

    }

     

     

    获取10个1至20的随机数,要求随机数不能重复(使用HashSet实现)

    有范围的随机数:Random类的nextInt(int bound)方法

    HashSet本身能保证元素不重复,但是往集合中尝试添加的次数不确定

    import java.util.HashSet;

    import java.util.Random;

    public class HashSetDemo {

        public static void main(String[] args) {

           // 创建随机数对象

           Random r = new Random();

           // 创建一个Set集合

           HashSet<Integer> ts = new HashSet<Integer>();

           // 判断集合的长度是不是小于10

           while (ts.size() < 10) {

               int num = r.nextInt(20) + 1;

               ts.add(num);

           }

           // 遍历Set集合

           for (Integer i : ts) {

               System.out.println(i);

           }

        }

    }

     

     

    LinkedHashSet类概述

    HashSet有个子类:LinkedHashSet类,元素也是不允许重复,它的特点是使用链表维护其元素的顺序,这样使得元素是看起来按照插入的顺序保存的,也就是访问元素的顺序和存储元素的顺序一致

    LinkedHashSet特点:

    • 由链表保证元素访问顺序,因此性能略低于HashSet
    • 由哈希表保证元素唯一

    import java.util.LinkedHashSet;

    public class LinkedHashSetDemo {

        public static void main(String[] args) {

           // 创建集合对象

           LinkedHashSet<String> hs = new LinkedHashSet<String>();

           // 创建并添加元素

           hs.add("hello");

           hs.add("world");

           hs.add("java");

           hs.add("world");

           hs.add("java");

           // 遍历

           for (String s : hs) {

               System.out.println(s);

           }

        }

    }

    TreeSet类概述

    从继承关系上看,TreeSet实现了SortedSet接口,其元素可以进行比较,从而可以进行排序

    TreeSet集合对元素进行排序有两种实现方式:

    1.让元素具有比较性:使用元素的自然顺序对元素进行排序

    2.让集合本身具有比较性:根据创建 set 时提供的 Comparator 进行排序

    具体取决于使用的构造方法

    存储整型值,自动排序的样例:

    import java.util.TreeSet;

     

    public class TreeSetDemo {

        public static void main(String[] args) {

           TreeSet<Integer> ts = new TreeSet<Integer>();

           // 创建元素并添加

           ts.add(20);

           ts.add(18);

           ts.add(23);

           ts.add(22);

           // 遍历

           for (Integer i : ts) {

               System.out.println(i);

           }

        }

    }

    字符串一样可以实现排序

    自定义类型的使用

    自定义类实现排序的第一种方式:自然排序,让元素具有比较性

    如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口Comparable--可比较的,实现接口的时候指定了泛型,所以在实现compareTo方法的时候,就可以直接指定形参的类型,省去了类型转换的麻烦

     

    public class Student implements Comparable<Student> {//实现Comparable接口

        private String name;

        private int age;

        public Student() {

        }

        public Student(String name, int age) {

           this.name = name;

           this.age = age;

        }

        public String getName() {

           return name;

        }

        public void setName(String name) {

           this.name = name;

        }

        public int getAge() {

           return age;

        }

        public void setAge(int age) {

           this.age = age;

        }

        @Override//由于指定了泛型,所以在重写方法的时候,直接写类型即可

        public int compareTo(Student s) {

           // return 0;

           // return 1;

           // return -1;

           // 这里返回什么,其实应该根据我的排序规则来做

           // 按照年龄排序,主要条件

           int num = this.age - s.age;

           // 次要条件

           // 年龄相同的时候,还得去看姓名是否也相同

           // 如果年龄和姓名都相同,才是同一个元素

           int num2 = num == 0 ? this.name.compareTo(s.name) : num;

           return num2;

           //若想倒序,直接将两个变量的顺序颠倒即可

           //int num = s.age - this.age;

           //int num2 = num == 0?s.name.compareTo(this.name):num;

           //return num2;

           /*另一种写法

           if(this.age > o.age){

               return -1;

           }

           if(this.age == o.age){

               return o.name.compareTo(this.name);

           }

           return 1;*/

        }

    }

    测试类TreeSetDemo2

    import java.util.TreeSet;

    public class TreeSetDemo2 {

        public static void main(String[] args) {

           TreeSet<Student> ts = new TreeSet<Student>();

           // 创建元素

           Student s1 = new Student("zhanga", 27);

           Student s2 = new Student("zhangb", 27);

           Student s3 = new Student("tom", 23);

           Student s4 = new Student("tom", 27);

     

           // 添加元素

           ts.add(s1);

           ts.add(s2);

           ts.add(s3);

           ts.add(s4);

     

           // 遍历

           for (Student s : ts) {

               System.out.println(s.getName() + "---" + s.getAge());

           }

        }

    }

    条件不一样比较的方式也不一样

    先比较名字长度,再比较名字内容,最后是年龄,如果都相同,是同一元素,不能添加

    public class Student implements Comparable<Student> {

        private String name;

        private int age;

        public Student() {

        }

        public Student(String name, int age) {

           this.name = name;

           this.age = age;

        }

        public String getName() {

           return name;

        }

        public void setName(String name) {

           this.name = name;

        }

        public int getAge() {

           return age;

        }

        public void setAge(int age) {

           this.age = age;

        }

        @Override//直接指定形参的类型是Student,因为在方法声明的时候使用了泛型

        public int compareTo(Student s) {

           // 主要条件 姓名的长度

           int num = this.name.length() - s.name.length();

           // 姓名的长度相同,不代表姓名的内容相同

           int num2 = num == 0 ? this.name.compareTo(s.name) : num;

           // 姓名的长度和内容相同,不代表年龄相同,所以还得继续判断年龄

           int num3 = num2 == 0 ? this.age - s.age : num2;

           return num3;//如果三个属性值都相同,那就返回0

        }

    }

    //测试类TreeSetDemo

    import java.util.TreeSet;

    /*

     * 需求:请按照姓名的长度排序

     */

    public class TreeSetDemo {

        public static void main(String[] args) {

           // 创建集合对象

           TreeSet<Student> ts = new TreeSet<Student>();

           // 创建元素

           Student s1 = new Student("linqingxia", 27);

           Student s2 = new Student("zhangguorong", 29);

           Student s3 = new Student("wanglihong", 23);

           Student s4 = new Student("linqingxia", 27);

           Student s5 = new Student("liushishi", 22);

           Student s6 = new Student("wuqilong", 40);

           Student s7 = new Student("fengqingy", 22);

           Student s8 = new Student("linqingxia", 29);

     

           // 添加元素

           ts.add(s1);

           ts.add(s2);

           ts.add(s3);

           ts.add(s4);

           ts.add(s5);

           ts.add(s6);

           ts.add(s7);

           ts.add(s8);

     

           // 遍历

           for (Student s : ts) {

               System.out.println(s.getName() + "---" + s.getAge());

           }

        }

    }

    比较器接口Comparator

    自定义类实现排序的第二种方式:让集合具有比较性

     

    使用上图中的构造方法,在创建集合的时候,传递一个比较器对象,这样的集合就是具有比较性的集合了,首先要有一个比较器才行,实现Comparator接口

    import java.util.Comparator;

    //自定义比较器,实现Comarator接口,实现compare方法

    public class MyComparator implements Comparator<Student> {

        @Override

        public int compare(Student s1, Student s2) {

           // 姓名长度

           int num = s1.getName().length() - s2.getName().length();

           // 姓名内容

           int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;

           // 年龄

           int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;

           return num3;

        }

    }

    //Student类

    public class Student {

        private String name;

        private int age;

        public Student() {

           super();

        }

        public Student(String name, int age) {

           this.name = name;

           this.age = age;

        }

        public String getName() {

           return name;

        }

        public void setName(String name) {

           this.name = name;

        }

        public int getAge() {

           return age;

        }

        public void setAge(int age) {

           this.age = age;

        }

    }

    //测试类

    import java.util.Comparator;

    import java.util.TreeSet;

    /*

    * 排序:

     *     A:自然排序(元素具备比较性)

     *         让元素所属的类实现自然排序接口 Comparable

     *     B:比较器排序(集合具备比较性)

     *         让集合的构造方法接收一个比较器接口的子类对象 Comparator

     */

    public class TreeSetDemo {

        public static void main(String[] args) {

           // TreeSet<Student> ts = new TreeSet<Student>(); //自然排序

           // public TreeSet(Comparator comparator) //比较器排序的构造

           // TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());

        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {

               @Override

               public int compare(Student s1, Student s2) {

                  // 姓名长度

                  int num = s1.getName().length() - s2.getName().length();

                  // 姓名内容

                  int num2 = num == 0 ? s1.getName().compareTo(s2.getName())

                         : num;

                  // 年龄

                  int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;

                  return num3;

               }

           });

     

           // 创建元素

           Student s1 = new Student("linqingxia", 27);

           Student s2 = new Student("zhangguorong", 29);

           Student s3 = new Student("wanglihong", 23);

           Student s4 = new Student("linqingxia", 27);

           Student s5 = new Student("liushishi", 22);

           Student s6 = new Student("wuqilong", 40);

           Student s7 = new Student("fengqingy", 22);

           Student s8 = new Student("linqingxia", 29);

     

           // 添加元素

           ts.add(s1);

           ts.add(s2);

           ts.add(s3);

           ts.add(s4);

           ts.add(s5);

           ts.add(s6);

           ts.add(s7);

           ts.add(s8);

     

           // 遍历

           for (Student s : ts) {

               System.out.println(s.getName() + "---" + s.getAge());

           }

        }

    }

     

     

    键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩)

    按照总分从高到低输出到控制台

    总分相同的,按语文从高到低排序

    前两者都相同的,按数学从高到低排序

    前三者都相同的,按英语从高到底排序

    如果上面所有值都相同,说明是同一个元素,不能添加

    使用集合是可排序的方式完成

    public class Student {

        // 姓名

        private String name;

        // 语文成绩

        private int chinese;

        // 数学成绩

        private int math;

        // 英语成绩

        private int english;

        public Student(String name, int chinese, int math, int english) {

           this.name = name;

           this.chinese = chinese;

           this.math = math;

           this.english = english;

        }

        public Student() {

        }

        public String getName() {

           return name;

        }

        public void setName(String name) {

           this.name = name;

        }

        public int getChinese() {

           return chinese;

        }

        public void setChinese(int chinese) {

           this.chinese = chinese;

        }

        public int getMath() {

           return math;

        }

        public void setMath(int math) {

           this.math = math;

        }

        public int getEnglish() {

           return english;

        }

        public void setEnglish(int english) {

           this.english = english;

        }

        public int getSum() {

           return this.chinese + this.math + this.english;

        }

    }

     

    //测试类

    public class TreeSetDemo {

        public static void main(String[] args) {

           // 创建一个TreeSet集合

           TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {

               @Override

               public int compare(Student s1, Student s2) {

                  // 总分从高到低

                  int num = s2.getSum() - s1.getSum();

                  // 总分相同的不一定语文相同

                  int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;

                  // 总分相同的不一定数学相同

                  int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;

                  // 总分相同的不一定英语相同

                  int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3;

                  // 姓名还不一定相同呢

                  int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName())

                         : num4;

                  return num5;

               }

           });

     

           System.out.println("学生信息录入开始");

           // 键盘录入5个学生信息

           for (int x = 1; x <= 5; x++) {

               Scanner sc = new Scanner(System.in);

               System.out.println("请输入第" + x + "个学生的姓名:");

               String name = sc.nextLine();

               System.out.println("请输入第" + x + "个学生的语文成绩:");

               String chineseString = sc.nextLine();

               System.out.println("请输入第" + x + "个学生的数学成绩:");

               String mathString = sc.nextLine();

               System.out.println("请输入第" + x + "个学生的英语成绩:");

               String englishString = sc.nextLine();

     

               // 把数据封装到学生对象中

               Student s = new Student();

               s.setName(name);

               s.setChinese(Integer.parseInt(chineseString));

               s.setMath(Integer.parseInt(mathString));

               s.setEnglish(Integer.parseInt(englishString));

     

               // 把学生对象添加到集合

               ts.add(s);

           }

           System.out.println("学生信息录入完毕");

     

           System.out.println("学习信息从高到低排序如下:");

           System.out.println("姓名 语文成绩 数学成绩 英语成绩");

           // 遍历集合

           for (Student s : ts) {

               System.out.println(s.getName() + " " + s.getChinese() + " "

                      + s.getMath() + " " + s.getEnglish());

           }

        }

    }

    Map接口概述

    Map接口概述

    将键映射到值的对象

    一个映射不能包含重复的键

    每个键最多只能映射到一个值

    Map接口和Collection接口的不同

    Map是双列的,Collection是单列的

    Map的键唯一,Collection的子体系Set是唯一的

    Map集合的数据结构只针对key有效,跟value无关

    Collection集合的数据结构是针对元素有效

    Map集合的功能概述:

    1:添加功能

        V put(K key,V value):添加元素

           如果键是第一次存储,就直接存储元素,返回null

           如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值

    2:删除功能

           void clear():移除所有的键值对元素

           V remove(Object key):根据键删除键值对元素,并把值返回

    3:判断功能

           boolean containsKey(Object key):判断集合是否包含指定的键

           boolean containsValue(Object value):判断集合是否包含指定的值

           boolean isEmpty():判断集合是否为空

    4:获取功能

           Set<Map.Entry<K,V>> entrySet()

           V get(Object key):根据键获取值

           Set<K> keySet():获取集合中所有键的集合

           Collection<V> values():获取集合中所有值的集合

    5:长度功能

           int size():返回集合中的键值对的对数

    Map集合常见操作演示

    import java.util.HashMap;

    import java.util.Map;

    /*

     * 作为学生来说,是根据学号来区分不同的学生的,那么假设我现在已经知道了学生的学号,我要根据学号去获取学生姓名,请问怎么做呢?

     * 如果采用前面讲解过的集合,我们只能把学号和学生姓名作为一个对象的成员,然后存储整个对象,将来遍历的时候,判断,获取对应的名称。

     * 但是呢,如果我都能把学生姓名拿出来了,我还需要根据编号去找吗?

     * 针对我们目前的这种需求:仅仅知道学号,就想知道学生姓名的情况,Java就提供了一种新的集合 Map。

     * 通过查看API,我们知道Map集合的一个最大的特点,就是它可以存储键值对的元素。这个时候存储我们上面的需求,就可以这样做

     *     学号1      姓名1

     *     学号2 姓名2

     *     学号3      姓名3

     *     学号2(不行)姓名4

     *     学号4       姓名4

     * Map集合的特点:

     *     将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

     *

     * Map集合和Collection集合的区别?

     *     Map集合存储元素是成对出现的,Map集合的键是唯一的,值是可重复的

     *     Collection集合存储元素是单独出现的,Collection的子接口Set是唯一的,List是可重复的。

     * 注意:

     *     Map集合的数据结构只针对键有效,跟值无关

    *      Collection集合的数据结构是针对元素有效*/

    public class MapDemo {

        public static void main(String[] args) {

           // 创建集合对象,带有泛型

           Map<String, String> map = new HashMap<String, String>();

           // 添加元素

           // V put(K key,V value):添加元素。其返回值有时也有用

           // System.out.println("put:" + map.put("文章", "马伊俐"));

           //第一次添加没有返回值

           // System.out.println("put:" + map.put("文章", "姚笛"));

     

           map.put("邓超", "孙俪");

           map.put("黄晓明", "杨颖");

           map.put("周杰伦", "蔡依林");

           map.put("刘恺威", "杨幂");

     

           // void clear():移除所有的键值对元素

           // map.clear();

     

           // V remove(Object key):根据键删除键值对元素,并把值返回

           // System.out.println("remove:" + map.remove("黄晓明"));

           // System.out.println("remove:" + map.remove("黄晓波"));

     

           // boolean containsKey(Object key):判断集合是否包含指定的键

           // System.out.println("containsKey:" + map.containsKey("黄晓明"));

           // System.out.println("containsKey:" + map.containsKey("黄晓波"));

     

           // boolean isEmpty():判断集合是否为空

           // System.out.println("isEmpty:"+map.isEmpty());

          

           //int size():返回集合中的键值对的对数

           System.out.println("size:"+map.size());

           // 输出集合名称

           System.out.println("map:" + map);

        }

    }

    Map常用获取方法

    获取功能:

    • V get(Object key):根据键获取值
    • Set<K> keySet():获取集合中所有键的集合,不可重复
    • Collection<V> values():获取集合中所有值的集合,可重复
    • Set<Map.Entry<K,V>> entrySet()

    import java.util.Collection;

    import java.util.HashMap;

    import java.util.Map;

    import java.util.Set;

    public class MapDemo2 {

        public static void main(String[] args) {

           // 创建集合对象

           Map<String, String> map = new HashMap<String, String>();

           // 创建元素并添加元素

           map.put("邓超", "孙俪");

           map.put("黄晓明", "杨颖");

           map.put("周杰伦", "蔡依林");

           map.put("刘恺威", "杨幂");

     

           // V get(Object key):根据键获取值

           System.out.println("get:" + map.get("周杰伦"));

           System.out.println("get:" + map.get("周杰")); // 返回null

           System.out.println("----------------------");

           // Set<K> keySet():获取集合中所有键的集合

           Set<String> set = map.keySet();

           for (String key : set) {

               System.out.println(key);

           }

           System.out.println("----------------------");

           // Collection<V> values():获取集合中所有值的集合

           Collection<String> con = map.values();

           for (String value : con) {

               System.out.println(value);

           }

        }

    }

    Map集合遍历的两种方式

    Map集合遍历方式一

    • 方式1:根据key找value

        获取所有key的集合

        遍历key的集合,通过key获取到每一个value

       

    • 方式2:根据键值对对象找key和value

        获取所有键值对对象的集合

        遍历键值对对象的集合,获取到每一个键值对对象

        根据键值对对象找key和value

    import java.util.HashMap;

    import java.util.Map;

    import java.util.Set;

    public class MapDemo3 {

        public static void main(String[] args) {

           // 创建集合对象

           Map<String, String> map = new HashMap<String, String>();

           // 创建元素并添加到集合

           map.put("杨过", "小龙女");

           map.put("郭靖", "黄蓉");

           map.put("杨康", "穆念慈");

           map.put("陈玄风", "梅超风");

           // 遍历

           // 获取所有的键

           Set<String> set = map.keySet();

           // 遍历键的集合,获取得到每一个键

           for (String key : set) {

               // 根据键去找值

               String value = map.get(key);

               System.out.println(key + "---" + value);

           }

        }

    }

    Map集合遍历方式二

    import java.util.HashMap;

    import java.util.Map;

    import java.util.Set;

    public class MapDemo4 {

        public static void main(String[] args) {

           // 创建集合对象

           Map<String, String> map = new HashMap<String, String>();

           // 创建元素并添加到集合

           map.put("杨过", "小龙女");

           map.put("郭靖", "黄蓉");

           map.put("杨康", "穆念慈");

           map.put("陈玄风", "梅超风");

     

           // 获取所有键值对对象的集合

           Set<Map.Entry<String, String>> set = map.entrySet();

           // 遍历键值对对象的集合,得到每一个键值对对象

           for (Map.Entry<String, String> me : set) {

               // 根据键值对对象获取键和值

               String key = me.getKey();

               String value = me.getValue();

               System.out.println(key + "---" + value);

           }

        }

    }

     

    Map接口实现类:HashMap

    HashMap类概述

      key是哈希表结构,可以保证key的唯一性

    HashMap常见用法

    • HashMap<String,String>
    • HashMap<Integer,String>
    • HashMap<String,Student>
    • HashMap<Student,String>

    HashMap演示案例一

    import java.util.HashMap;

    import java.util.Set;

    /*

     * HashMap:是基于哈希表的Map接口实现。

     * 哈希表的作用是用来保证键的唯一性的。

    * HashMap<String,String>

     * 键:String

     * 值:String

     */

    public class HashMapDemo {

        public static void main(String[] args) {

           // 创建集合对象

           HashMap<String, String> hm = new HashMap<String, String>();

           //添加元素

           hm.put("it001", "马云");

           hm.put("it003", "马化腾");

           hm.put("it004", "乔布斯");

           hm.put("it005", "张朝阳");

           hm.put("it001", "比尔盖茨");

     

           // 遍历,通过key集合去找value

           Set<String> set = hm.keySet();

           for (String key : set) {

               String value = hm.get(key);

               System.out.println(key + "---" + value);

           }

        }

    }

    HashMap演示案例二

    import java.util.HashMap;

    import java.util.Set;

    /*

     * HashMap<Integer,String>

     * 键:Integer

     * 值:String

     */

    public class HashMapDemo2 {

        public static void main(String[] args) {

           // 创建集合对象

           HashMap<Integer, String> hm = new HashMap<Integer, String>();

           //添加元素

           hm.put(27, "林青霞");

           hm.put(30, "风清扬");

           hm.put(28, "张三");

           hm.put(29, "林青霞");

     

           // 下面的写法是八进制,但是不能出现8以上的单个数据

           // hm.put(003, "hello");

           // hm.put(006, "hello");

           // hm.put(007, "hello");

           // hm.put(008, "hello");//error

           // 遍历

           Set<Integer> set = hm.keySet();

           for (Integer key : set) {

               String value = hm.get(key);

               System.out.println(key + "---" + value);

           }

     

           // 下面这种方式仅仅是集合的元素的字符串表示

           // System.out.println("hm:" + hm);

        }

    }

     

     

    演示案例:存放学生对象

    由于使用的是HashMap所以自定义的类中一定要重写hashCode和equals方法,这样才能保证key能准确存储到集合中

     

    public class Student {

        private String name;

        private int age;

        public Student() {   }

        public Student(String name, int age) {

           this.name = name;

           this.age = age;

        }

        public String getName() {

           return name;

        }

        public void setName(String name) {

           this.name = name;

        }

        public int getAge() {

           return age;

        }

        public void setAge(int age) {

           this.age = age;

        }

        @Override

        public int hashCode() {

           final int prime = 31;

           int result = 1;

           result = prime * result + age;

           result = prime * result + ((name == null) ? 0 : name.hashCode());

           return result;

        }

        @Override

        public boolean equals(Object obj) {

           if (this == obj)

               return true;

           if (obj == null)

               return false;

           if (getClass() != obj.getClass())

               return false;

           Student other = (Student) obj;

           if (age != other.age)

               return false;

           if (name == null) {

               if (other.name != null)

                  return false;

           } else if (!name.equals(other.name))

               return false;

           return true;

        }

    }

     

     

    //测试类

    import java.util.HashMap;

    import java.util.Set;

    /*

     * HashMap<String,Student>

     * 键:String  学号

     * 值:Student 学生对象

     */

    public class HashMapDemo3 {

        public static void main(String[] args) {

           // 创建集合对象

           HashMap<String, Student> hm = new HashMap<String, Student>();

           // 创建学生对象

           Student s1 = new Student("周星驰", 58);

           Student s2 = new Student("刘德华", 55);

           Student s3 = new Student("梁朝伟", 54);

           Student s4 = new Student("刘嘉玲", 50);

     

           // 添加元素

           hm.put("9527", s1);

           hm.put("9522", s2);

           hm.put("9524", s3);

           hm.put("9529", s4);

     

           // 遍历

           Set<String> set = hm.keySet();

           for (String key : set) {

               // 注意了:这次值不是字符串了

               Student value = hm.get(key);

               System.out.println(key + "---" + value.getName() + "---"

                      + value.getAge());

           }

        }

    }

    第二种方法

    import java.util.HashMap;

    import java.util.Set;

     

    /*

     * HashMap<Student,String>

     * 键:Student

     *     要求:如果两个对象的成员变量值都相同,则为同一个对象。

     * 值:String

     */

    public class HashMapDemo4 {

        public static void main(String[] args) {

           // 创建集合对象

           HashMap<Student, String> hm = new HashMap<Student, String>();

     

           // 创建学生对象

           Student s1 = new Student("貂蝉", 27);

           Student s2 = new Student("王昭君", 30);

           Student s3 = new Student("西施", 33);

           Student s4 = new Student("杨玉环", 35);

           Student s5 = new Student("貂蝉", 27);

     

           // 添加元素

           hm.put(s1, "8888");

           hm.put(s2, "6666");

           hm.put(s3, "5555");

           hm.put(s4, "7777");

           hm.put(s5, "9999");//s5于s1属于重复对象,所以不能添加

     

           // 遍历

           Set<Student> set = hm.keySet();

           for (Student key : set) {

               String value = hm.get(key);

               System.out.println(key.getName() + "---" + key.getAge() + "---"

                      + value);

           }

        }

    }

  • 相关阅读:
    ES 2016+
    git-svn for mac
    Linux系统下安装rz/sz命令及使用说明
    Nginx location指令匹配顺序规则
    nginx修改配置后不生效的问题
    ssh and scp从远程服务器下载文件
    安装yii2 框架遇到的问题
    php添加openssl扩展
    GitHub Token for composer
    centos7+nginx+php+mysql环境搭建
  • 原文地址:https://www.cnblogs.com/zhaoyongcx/p/6675937.html
Copyright © 2011-2022 走看看