大数据第十九天

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了大数据第十九天相关的知识,希望对你有一定的参考价值。

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返回值]

[email protected]

[email protected]

[email protected]      //由于只有一个C的对象,所以这里只有一个元素

[email protected]

[email protected]

说明:

  • 单纯的重写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("姓名\t语文成绩\t数学成绩\t英语成绩");

       // 遍历集合

       for (Student s : ts) {

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

                  + s.getMath() + "\t" + 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);

       }

    }

}

以上是关于大数据第十九天的主要内容,如果未能解决你的问题,请参考以下文章

大数据第九天内容

大数据Java基础第九天作业

大数据JAVA基础第九天

python学习第十九天:re,sys,suprocess模块

大数据入门第十九天——推荐系统与mahout入门与概述

PHP操作MYSQL数据库(10.11 第十九天)