集合(上)

集合(上)

集合类的特点:提供一种存储空间可变的存储模型,存储的数据容量可以随时发生改变。

集合类体系结构:

在这里插入图片描述

注意:在学习的时候,首先会学习接口,而在使用的时候是使用实现类。为什么要先学习接口?假如说,我们先学习了Collection接口,那么以后在学习List或Set接口的时候,我们只需学习它的特有功能就可以了,同理,之后学习ArrayList、LinkedList的时候,也只需学习它的特有功能就可以了。而在使用的时候,要使用具体的实现类,原因很简单,因为接口是不能直接创建对象并实例化的,它必须通过具体的实现类来创建对象并实例化


一、Collection集合

  • 它是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素。

  • JDK不提供此接口的任何直接实现,但它提供更具体的子接口(如Set和List)实现

创建Collection集合的对象

  • 多态的方式
  • 具体的实现类ArrayList
public static void main(String[] args) {

    //创建Collection 集合的对象
    Collection<String> c = new ArrayList<>();

    //添加元素:boolean add(E e) E为<>中的类型
    c.add("Hello");
    c.add("World");

    //输出集合对象
    System.out.println(c);

}

/*
        [Hello, World]
        可以看出,集合中重写了toString方法(没有重写的话是输出包名,类名xxx@xxx)
 */

Collection集合常用方法

方法名作用
boolean add(E e)添加元素
boolean remove(Object o)从集合中移除指定的元素
void clear()清空集合中的元素
boolean contains(Object o)判断集合中是否存在指定的元素
boolean isEmpty()判断集合是否为空
int size()集合的长度,也就是集合中元素的个数
public static void main(String[] args) {

    //创建集合对象
    Collection<String> c = new ArrayList<>();

    //boolean add(E e):添加元素
    c.add("hello");
    c.add("world");
    c.add("JAVA");
    c.add("Here");
    System.out.println(c);      // [hello, world, JAVA, Here]

    //boolean remove(Object o):从集合中移除指定的元素
    System.out.println(c.remove("world"));    //  true
    System.out.println(c.remove("Javaee"));  //  false
    System.out.println(c);      // [hello, JAVA, Here]

    //void clear():清空集合中的元素
//        c.clear();
//        System.out.println(c);

    //boolean contains(Object o):判断集合中是否存在指定的元素
    System.out.println(c.contains("hello"));    // true
    System.out.println(c.contains("Javaee"));   // false

    //boolean isEmpty():判断集合是否为空
    System.out.println(c.isEmpty());        // false

    //int size():集合的长度,也就是集合中元素的个数
    System.out.println(c.size());       // 3
}

Collection集合的遍历

Iterator中的常用方法

方法名作用
E nex()返回迭代中的下一个元素
boolean hasNext()如果迭代具有更多元素,则返回true(判断迭代器中是否有元素)
public static void main(String[] args) {
    //创建对象
    Collection<String> c = new ArrayList<>();

    //添加元素
    c.add("hello");
    c.add("world");
    c.add("JAVA");

    //Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
    Iterator<String> it = c.iterator();
/*
	//E nex():返回迭代中的下一个元素
    System.out.println(it.next());
    System.out.println(it.next());
    System.out.println(it.next());
    System.out.println(it.next());  //NoSuchElementException  表示被请求的元素不存在。 怎么解决?看下面
*/

/*
	//boolean hasNext():如果迭代具有更多元素,则返回true(判断迭代器中是否有元素)
    if (it.hasNext()){
    	System.out.println(it.next());
     }
     if (it.hasNext()){
     	System.out.println(it.next());
     }
     if (it.hasNext()){
     	System.out.println(it.next());
      }
      if (it.hasNext()){
      	System.out.println(it.next());
       }
       //这样就能解决 NoSuchElementException 异常了,那么可不可以在优化一下这四个if语句呢?用while循环试试
*/
    while (it.hasNext()){
        String s = it.next();
        System.out.println(s);
    }
/*
            hello
            world
            JAVA
*/
}

集合的使用步骤

public static void main(String[] args) {

    Collection<String> c = new ArrayList<>();       //步骤1、创建集合对象
    c.add("hello");                                 //步骤2、添加元素到集合
    c.add("world");
    //步骤3、遍历集合
    Iterator<String> it = c.iterator();             //    3.1、通过集合对象获取迭代器对象
    while (it.hasNext()){                           //    3.2、通过迭代器对象的hasNext()方法判断是否还有元素
        String s = it.next();                       //    3.3、通过迭代器对象的next()方法获取下一个元素
        System.out.println(s);
    }
}

案例:用Collection集合存储学生对象并遍历

需求:创建一个存储学生对象的集合,存储三个学生对小,使用程序实现在控制台遍历集合

思路:
1、定义学生类
2、创建Collection集合对象
3、创建学生对象
4、把学生添加到集合中
5、遍历集合(迭代器方式)

/*
    1、定义学生类
    	定义私有属性:name,age,address,以及它们各自的get/set方法
    	定义有参、无参构造方法
    	重写toString方法
 */
public class Student {

    private String name;
    private int age;
    private String  address;

    public Student() {
    }

    public Student(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    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 getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}
public class CollectionDM {
    public static void main(String[] args) {

        //2、创建集合对象
        Collection<Student> c = new ArrayList<>();
        
        //3、创建学生对象
        Student s1 = new Student("张三",23,"北京");
        Student s2 = new Student("李四",24,"上海");
        Student s3 = new Student("王五",25,"广州");

        //4、把学生添加到集合
        c.add(s1);
        c.add(s2);
        c.add(s3);

        //5、遍历集合(迭代器)
        Iterator<Student> it = c.iterator();
        while (it.hasNext()){
            Student s = it.next();
            System.out.println(s);
        }
    }
}
/*
	结果输出:
        Student{name='张三', age=23, address='北京'}
        Student{name='李四', age=24, address='上海'}
        Student{name='王五', age=25, address='广州'}
*/

二、List集合

List集合概述和特点

List集合概述

​ 1、有序集合(也称为序列 )。 该界面的用户可以精确控制列表中每个元素的插入位置。
​ 用户可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素。

​ 2、与Set集合不同,列表通常允许重复的元素

List集合特点:

​ 有序:存储和取出的元素顺序一致

​ 可重复:存储的元素可以重复

public static void main(String[] args) {

    //创建对象
    List<String> list = new ArrayList<>();

    //添加元素(List集合可以重复添加元素)
    list.add("hello");
    list.add("world");
    list.add("hello");
    list.add("world");

    System.out.println(list);   //[hello, world, hello, world]

    //遍历集合(使用构造器)
    Iterator<String> it = list.iterator();
    while (it.hasNext()){
        String s = it.next();
        System.out.println(s);
    }
   		 /*
           hello
           world
           hello
           world
         */
}

List集合特有方法

方法名作用
void add(int index,E element)将指定的元素插入此列表中的指定位置。
E remove(int index)删除该列表中指定位置的元素。
E set(int index, E element)修改指定索引处的元素,返回被修改的元素。
E get(int index)返回指定索引处的元素。
public static void main(String[] args) {

    //创建集合对象
    List<String> list = new ArrayList<>();

    //添加元素
    list.add("hello");
    list.add("nihao");
    list.add("world");

    //void add(int index,E element);将指定的元素插入此列表中的指定位置。
//        list.add(4,"javaee");   // IndexOutOfBoundsException
    list.add(1,"world");
    System.out.println(list);   // [hello, world, nihao, world]

    //E remove(int index);删除该列表中指定位置的元素。
//        list.remove(4);     // IndexOutOfBoundsException
    list.remove(1);
    System.out.println(list);   // [hello, nihao, world]

    //E set(int index, E element);修改指定索引处的元素,返回被修改的元素。
//        list.set(4,"Javaee");     // IndexOutOfBoundsException
    list.set(2,"Java");
    System.out.println(list);   // [hello, nihao, Java]

    // E get(int index);返回指定索引处的元素。
    String s =list.get(1);
    System.out.println(s);  // nihao
}

案例:用List集合存储学生对象并遍历

需求:创建一个存储学生对象的集合,存储三个学生对小,使用程序实现在控制台遍历集合

思路:
1、定义学生类
2、创建List集合对象
3、创建学生对象
4、把学生添加到集合中
5、遍历集合(迭代器方式、for循环方式)

/*
    1、定义学生类
    	定义私有属性:name,age,address,以及它们各自的get/set方法
    	定义有参、无参构造方法
    	重写toString方法
 */
(具体代码与上一节中的案例相同)
public static void main(String[] args) {

    //创建List集合对象
    List<Student> c = new ArrayList<>();

    //创建学生对象
    Student s1 = new Student("张三",23,"北京");
    Student s2 = new Student("李四",24,"上海");
    Student s3 = new Student("王五",25,"广州");

    //把学生添加到集合中
    c.add(s1);
    c.add(s2);
    c.add(s3);

    //遍历集合:迭代器方式
    Iterator<Student> it = c.iterator();
    while (it.hasNext()) {
        Student s = it.next();
        System.out.println(s);
    }

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

    //遍历集合:for循环方式
    for (int i = 0; i < c.size(); i++) {
        Student ss = c.get(i);
        System.out.println(ss);
    }
}
/*
	输出结果:
        Student{name='张三', age=23, address='北京'}
        Student{name='李四', age=24, address='上海'}
        Student{name='王五', age=25, address='广州'}
        ===========
        Student{name='张三', age=23, address='北京'}
        Student{name='李四', age=24, address='上海'}
        Student{name='王五', age=25, address='广州'}
*/

该main()方法与Collection案例中的main()方法的区别:

​ 创建集合对象的不同,一个创建Collection 集合的对象,一个创建List集合对象,但他们都是在ArrayList的基础上创建的(这里用到了多态的知识)。其次另一个不同点是List案例用了普通for循环来遍历集合

并发修改异常

有一个集合:List list = new ArrayList<>();
里面有三个元素:
list.add(“hello”);
list.add(“world”);
list.add(“java”);
需求:遍历集合,得到每一个元素,看有没“world”这个元素,如果有,就添加个“javaee”元素。

public static void main(String[] args) {

    //创建集合对象
    List<String> list = new ArrayList<>();

    //添加元素
    list.add("hello");
    list.add("world");
    list.add("java");

    //遍历集合:得到每一个元素,看有没“world”这个元素,如果有,就添加哟个“javaee”元素。

/*
    Iterator<String> it = list.iterator();
    while (it.hasNext()){
        String s = it.next();
        if (s.equals("world")){
            list.add("javaee");     //通过集合来添加元素,不能用Iterator来添加元素,因为里面没有添加方法
        }
    }
    //  ConcurrentModificationException:当不允许这样的修改时,可以通过检测到对象的并发修改的方法来抛出此异常。
*/
    for (int i = 0; i < list.size(); i++) {
        String s = list.get(i);
        if (s.equals("world")){
            list.add("javaee");
        }
    }
}

小总结:

并发修改异常
    ConcurrentModificationException

产生原因:
    迭代器遍历的过程中,通过集合对象修改了几何元素中的长度,造成了迭代器获取元素中判断预期修改值和实际值不一致

解决方案:
    用for循环遍历,然后用集合对象做对应的操作

ListIterator

ListIterator:列表迭代器

​ 通过List集合的listIterator()方法得到,所以说他是List集合特有的迭代器

​ 用于允许程序猿沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置

ListIterator中的常用方法:

方法名作用
E next()返回列表中的下一个元素,并且前进光标位置。
boolean hasNext()如果列表迭代器在向前方向遍历列表时有多个元素,则返回true。
E previous()返回列表中的上一个元素,并向后移动光标位置。
boolean hasPrevious()如果列表迭代器在相反方向遍历列表时有多个元素,则返回true。
void add(E e)将指定的元素插入列表。
public static void main(String[] args) {

    //创建集合对象
    List<String> list = new ArrayList<>();

    //添加集合元素
    list.add("hello");
    list.add("world");
    list.add("java");

/*
    //通过List集合的listIterator()方法得到,所以说他是List集合特有的迭代器
    ListIterator<String> lit = list.listIterator();

    //  正向遍历:
    //  E next();返回列表中的下一个元素,并且前进光标位置。
    //  boolean hasNext();如果列表迭代器在向前方向遍历列表时有多个元素,则返回true。
    while (lit.hasNext()){
        String s = lit.next();
        System.out.println(s);
    }

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

    //  反向遍历:
    //  E previous();返回列表中的上一个元素,并向后移动光标位置。
    //  boolean hasPrevious();如果列表迭代器在相反方向遍历列表时有多个元素,则返回true。
    while (lit.hasPrevious()){
        String ss = lit.previous();
        System.out.println(ss);
    }
    	这个遍历方法了解即可,一般都使用Iterator迭代器进行正向遍历.
        下面重点学习 void add(E e);   再与上一节学习的并发修改异常作比较.
*/

        ListIterator<String> lit = list.listIterator();
    	while (lit.hasNext()){
            String s = lit.next();
            if (s.equals("world")){
                lit.add("javaee");      // 可以用ListIterator迭代器添加元素(该迭代器中有add方法),不能用Iterator来添加元素,
            							// 因为里面没有添加方法,因此在上一节用集合来添加元素
        }
    }
    System.out.println(list);   //[hello, world, javaee, java]
}

此案例中的代码与上一节并发修改异常中的代码大同小异,但此案例却可以通过迭代器实现集合的遍历,这是为啥?

原因在于ListIterator迭代器中有add方法,因此可以直接添加元素。而出现并发修改异常的代码中是借助ArrayList集合中add方法来添加。

//并发修改异常
Iterator<String> it = list.iterator();
    while (it.hasNext()){
        String s = it.next();
        if (s.equals("world")){
            list.add("javaee");     
        }
    }
//ListIterator迭代器
ListIterator<String> lit = list.listIterator();
    	while (lit.hasNext()){
            String s = lit.next();
            if (s.equals("world")){
                lit.add("javaee");      
        }
    }

增强for循环

增强For:简化数组和Collection集合的遍历

​ 实现Iterator接口的类允许其对象成为增强for语句的目标

​ 它是JDK5之后出现的,其内部原理是一个Iterator迭代器

增强for的格式

​ for(元素数据类型 变量名 :该数组或Collection集合){

​ //在此处使用变量即可,该变量就是元素

​ }

public static void main(String[] args) {

    //遍历 int 数组
    int[] arr = {1,2,3,4,5};
    for(int i: arr){
        System.out.println(i);
    }

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

    //遍历 String 数组
    String[] s = {"hello","wolrd","java"};
    for (String a :s){
        System.out.println(a);
    }

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

    //遍历集合
    List<String> l = new ArrayList<>();
    l.add("hello");
    l.add("world");
    l.add("java");
    for (String aa : l){
        System.out.println(aa);
    }
}
/*
	输出结果:
		1
        2
        3
        4
        5
        =============
        hello
        wolrd
        java
        =============
        hello
        world
        java
*/

如何验证加强for内部是一个Iterator迭代器?
进行以下操作,如果返回的是一个ConcurrentModificationException,则其内部是一个Iterator迭代器?

for (String ss : l){
    if (ss.equals("world")){
        l.add("javaee");    //ConcurrentModificationException
    }
}

案例:用List集合存储学生对象并遍历。(与上一个案例大同小异)

(略)

数据结构

在这里插入图片描述

**队列 **:

在这里插入图片描述

数组

在这里插入图片描述

查询数据通过索引定位,查询任意数据耗时相同,**查询效率高 **。(数组是一种查询快的模型)

删除数据时,要将原始数据删除,同时后面每个数据前移,删除效率低。(数组是一种增删慢的模型)

添加数据时,添加位置后的每个数据后移,再添加元素,添加效率极低

链表

在这里插入图片描述

链表是一种增删快的模型(对比数组)

链表是一种查询慢的模型(对比数组)

List集合子类特点

List集合常用子类: ArrayList、LinkedList

​ ArrayList:底层数据结构是数组,查询快、增删慢。

​ LinkedList:底层数据结构是链表,查询慢、增删快。

练习:

​ 分别使用ArrayList和LinkedList完成存储字符串并遍历

public static void main(String[] args) {

        //创建ArrayList集合对象
        ArrayList<String> a = new ArrayList<>();

        //添加集合元素
        a.add("hello");
        a.add("world");
        a.add("java");

        //遍历集合元素:增强for遍历
        for (String s : a ){
            System.out.println(s);
        }
        System.out.println("---------------");

        //遍历集合元素:普通for遍历
        for (int i = 0; i < a.size(); i++) {
            String s1 = a.get(i);
            System.out.println(s1);
        }
        System.out.println("---------------");

        //遍历集合元素:迭代器遍历
        Iterator<String> s2 = a.iterator();
        while (s2.hasNext()){
            System.out.println(s2.next());
        }

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

        //创建LinkedList集合对象
        LinkedList<String> l = new LinkedList<>();

        //添加集合元素
        l.add("hello");
        l.add("world");
        l.add("java");

        //遍历集合元素:增强for遍历
        for (String ss : l){
            System.out.println(ss);
        }
        System.out.println("---------------");

        //遍历集合元素:普通for遍历
        for (int i = 0; i < l.size(); i++) {
            String ss1 = l.get(i);
            System.out.println(ss1);
        }
        System.out.println("---------------");

        //遍历集合元素:迭代器遍历
        Iterator<String> ss2 = l.iterator();
        while (ss2.hasNext()){
            System.out.println(ss2.next());
        }
    }
/*
	输出结果:
        hello
        world
        java
        ---------------
        hello
        world
        java
        ---------------
        hello
        world
        java
        =============
        hello
        world
        java
        ---------------
        hello
        world
        java
        ---------------
        hello
        world
        java
*/

ArrayList集合(前面基本穿插学完)

LinkedList集合

LinkedList集合的常用方法:

方法名作用
public void addFirst(E e)在该列表开头插入指定的元素。
public void addLast(E e)将指定的元素追加到此列表的末尾。
public E getFirst()返回此列表中的第一个元素。
public E getLast()返回此列表中的最后一个元素。
public E removeFirst()从此列表中删除并返回第一个元素。
public E removeLast()从此列表中删除并返回最后一个元素。
public static void main(String[] args) {

    LinkedList<String> l = new LinkedList<>();

    l.add("hello");
    l.add("world");
    l.add("java");

    //  public void addFirst(E e);在该列表开头插入指定的元素。
    //  public void addLast(E e);将指定的元素追加到此列表的末尾。
    l.addFirst("qqq");
    l.addLast("www");
    System.out.println(l);
    System.out.println("===============");  

    //  public E getFirst();返回此列表中的第一个元素。
    //  public E getLast()返回此列表中的最后一个元素。
    System.out.println(l.getFirst());
    System.out.println(l.getLast());
    System.out.println("===============");

    //  public E removeFirst()从此列表中删除并返回第一个元素。
    //  public E removeLast()从此列表中删除并返回最后一个元素。
    System.out.println(l.removeFirst());
    System.out.println(l.removeLast());
    System.out.println(l);
}
/*
	输出结果:
        [qqq, hello, world, java, www]
        ===============
        qqq
        www
        ===============
        qqq
        www
        [hello, world, java]
*/

三、Set集合

Set集合概述和特点

Set集合特点

​ 不包含重复元素的集合

​ 没有带索引的方法,所以不能使用普通for循环遍历

HashSet:

​ 对集合的迭代次序不作任何保证。(即元素可能会乱序)

/*
	Set集合练习:
        存储字符串并遍历
 */
 public static void main(String[] args) {

     //创建集合对象
     Set<String> s = new HashSet<>();

     //添加元素
     s.add("hello");
     s.add("world");
     s.add("java");
     //不包含重复元素的集合
     s.add("java");

     //遍历
     for (String ss : s){
         System.out.println(ss);
     }
 }

哈希值

哈希值:

​ 是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值

Object类中有一个方法可以获取对象的哈希值:

​ public int hashCode();返回对象的哈希码值

对象的哈希值特点

​ 同一个对象多次调用hashCode()方法返回的哈希值是相同的

​ 默认情况下,不同对象的哈希值是不同的,而重写hashCode()方法,可以实现让不同对象的哈希值相同

/*
    定义学生类:
    	定义私有属性:name,age,address,以及它们各自的get/set方法
    	定义有参、无参构造方法
    	重写toString方法
*/
(具体代码与上一节中的案例相同)
 public static void main(String[] args) {

     //创建学生对象
     Student s1 = new Student("张三",23,"北京");

     //同一个对象多次调用hashCode()方法返回的哈希值是相同的
     System.out.println(s1.hashCode());  //460141958
     System.out.println(s1.hashCode());  //460141958
     System.out.println("===========");

     Student s2 = new Student("李四",25,"上海");

     //默认情况下,不同对象的哈希值是不同的,而重写hashCode()方法,可以实现让不同对象的哈希值相同
     System.out.println(s2.hashCode()); //1163157884
     System.out.println("===========");

     System.out.println("hello".hashCode()); //99162322
     System.out.println("world".hashCode()); //113318802
     System.out.println("java".hashCode()); //3254818
 }

HashSet集合概述和特点

HashSet集合特点:

​ 底层数据结构是哈希表

​ 对集合的迭代顺序不做任何保证,即不保证存储和取出的顺序一致

​ 没有带索引的方法,所以不能使用普通for循环遍历

​ 由于是Set集合,所以是不包含重复元素的集合

public static void main(String[] args) {

    //创建集合对象
    HashSet<String> hs = new HashSet<>();

    //添加集合元素
    hs.add("hello");
    hs.add("world");
    hs.add("java");

    //遍历集合
    for(String s : hs){
        System.out.println(s);
    }
}
/*
	world
	java
	hello
	//输出顺序与存储顺序不同,它是不保证存储和取出的顺序一致
*/

常见数据结构之哈希表

哈希表

​ JDK8之前,底层采用数组+链表实现,可以说是一个元素为链表的数组。

​ JDK8以后,在长度较长的是否,底层实现了优化

哈希表在存储时是如何保证元素唯一性的?
通过下图说明:

在这里插入图片描述

案例:HashSet集合存储学生对象并遍历

需求:创建一个学生对象的集合,存储多个学生对象,实用程序实现在控制台遍历该集合
要求:学生对象成员变量值相同时,我们就认为是同一个对象
思路:
1、定义学生类
2、创建HashSet集合对象
3、创建学生对象
4、把学生添加到集合
5、遍历集合(增强for循环)

/*
	定义学生类
		定义属性:name,age,及其各自的get/set方法
		定义有参、无参构造方法
		重写toString、equals和hashCode方法
*/
public static void main(String[] args) {

    //创建学生集合对象
    HashSet<Student> hs = new HashSet<>();

    //创建并添加学生对象
    Student s1 = new Student("张三",23);
    Student s2 = new Student("李四",26);

    //验证是否会输出相同的值
    Student s3 = new Student("李四",26);	//保证输出元素不重复,需要重写equals和hashCode方法

    //把学生对象添加到集合
    hs.add(s1);
    hs.add(s2);
    hs.add(s3);

    for (Student s : hs){
        System.out.println(s);
    }
}
/*
Student{name='张三', age=23}
Student{name='李四', age=26}
*/

LinkedHashSet集合概述和特点

LinkedHashSet集合特点:

​ 哈希表和链表实现的Set接口,具有可预测的迭代次序

​ 由链表保证元素有序,即元素的存储和取出顺序是一致的

​ 由哈希表保证元素唯一,即没有重复的元素

/*
	LinkedHashSet集合练习:存储字符串并遍历
*/
public static void main(String[] args) {

    //创建集合对象
    LinkedHashSet<String> lhs = new LinkedHashSet<>();

    //添加元素
    lhs.add("hello");
    lhs.add("world");
    lhs.add("java");

    //验证是否会添加重复元素
    lhs.add("java");

    //遍历集合
    for (String s : lhs){
        System.out.println(s);
    }

}
/*
	hello
	world
	java
*/

TreeSet集合概述和特点

TreeSet集合特点

​ 元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方法取决于构造方法

​ TreeSet():根据其元素的自然排序进行排序

​ TreeSet(Comparator comparator):根据指定的比较器进行排序

​ 没有带索引的方法,所以不能使用普通for循环遍历

​ 由于是Set集合,所以不包含重复元素的集合

/*
	TreeSet集合练习:存储字符串并遍历
*/
public static void main(String[] args) {

    //创建集合对象
    TreeSet<Integer> ts = new TreeSet<>();

    //添加集合元素
    ts.add(10);
    ts.add(20);
    ts.add(30);
    ts.add(30);
    ts.add(40);

    //遍历集合元素
    for (int s : ts){
        System.out.println(s);
    }
}
/*
	10
    20
    30
    40
*/

自然排序Comparable的使用

存储学生对象并遍历,创建TreeSet集合使用无参构造方法
要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

/*
    定义学生类
		定义属性:name,age,及其各自的get/set方法
		定义有参、无参构造方法
		实现自然排序(先实现Comparable<E>,然后重写compareTo(E e)方法)
 */
public class Student implements Comparable<Student>{

    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Student() {
    }

    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 String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student s) {
//        return 0;   //返回值是0,系统会默认元素是重复的,就不会存储要添加的元素。
//        return 1;      //按照升序来存储
//        return -1;      //按照降序来存储

        int num = this.age - s.age;     //按照年龄升序存储
//        int num = s.age - this.age;     //按照年龄降序存储(相同的不存储)
        int num2  = num == 0? this.name.compareTo(s.name):num;  //判断年龄是否等于零,若等于零,则判断名字是否相同
        return num2;			//注:this.name.compareTo(s.name) 得出的是0/1/-1,因此可以用int来接收
    }
}

public static void main(String[] args) {

    //创建集合对象
    TreeSet<Student> ts = new TreeSet<>();

/*
    //创建学生对象并添加
    Student s1 = new Student("张三",23);
    Student s2 = new Student("王宝强",29);
    Student s3 = new Student("成龙",39);
    Student s4 = new Student("周润发",39);
*/

    //创建学生对象并添加
    Student s1 = new Student("zhangsan",23);
    Student s2 = new Student("wangbaoqiang",29);
    Student s3 = new Student("chenglong",39);
    Student s4 = new Student("zhourunfa",39);
    Student s5 = new Student("zhourunfa",39);       //观察重复元素是否会输出

    //把学生添加到集合
    ts.add(s1);
    ts.add(s2);
    ts.add(s3);
    ts.add(s4);
    ts.add(s5);

    //遍历集合
    for (Student s : ts){
        System.out.println(s);
    }
}

/*
Student{name='张三', age=23}
Student{name='王宝强', age=29}
Student{name='周润发', age=39}
Student{name='成龙', age=39}
 */

/*
Student{name='zhangsan', age=23}
Student{name='wangbaoqiang', age=29}
Student{name='chenglong', age=39}
Student{name='zhourunfa', age=39}
 */

小结:

​ 1、用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的

​ 2、自然排序,就是让元素所属的类实现Comparable接口,重写compareTo方法

​ 3、重写方法时,一定要注意排序规则必须按照要求的主要任务和次要任务来写

比较器排序Comparator的使用

存储学生对象并遍历,创建TreeSet集合使用有参构造方法
要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

/*
    定义学生类
		定义属性:name,age,及其各自的get/set方法
		定义有参、无参构造方法
		实现自然排序(先实现Comparable<E>,然后重写compareTo(E e)方法)
 */
public static void main(String[] args) {

    //使用有参构造创建集合对象(匿名内部类创建比较器进行排序)
    TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
        @Override
        public int compare(Student s1, Student s2) {
            // this --- s1  ;  s --- s2
            int num1 = s1.getAge() - s2.getAge();
            int num2 =  num1 == 0? s1.getName().compareTo(s2.getName()) : num1;
            return num2;
        }
    });

    //创建学生对象并添加
    Student s1 = new Student("zhangsan",23);
    Student s2 = new Student("wangbaoqiang",29);
    Student s3 = new Student("chenglong",39);
    Student s4 = new Student("zhourunfa",39);
    Student s5 = new Student("zhourunfa",39);       //观察重复元素是否会输出

    //把学生添加到集合
    ts.add(s1);
    ts.add(s2);
    ts.add(s3);
    ts.add(s4);
    ts.add(s5);

    //遍历集合
    for (Student s : ts){
        System.out.println(s);
    }

}

/*
Student{name='zhangsan', age=23}
Student{name='wangbaoqiang', age=29}
Student{name='chenglong', age=39}
Student{name='zhourunfa', age=39}
 */

小结:

​ 1、 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序

​ 2、 比较器排序:是让集合构造方法接收Comparator的实现类对象,重写Comparae(T o1,T o2)方法

​ 3、 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

案例:成绩排序

需求: 用TreeSet集合存储多个学生信息(姓名,语文成绩,数学成绩),并遍历集合

​ 要求:总分从高到低

​ 思路:

​ 1、定义学生类
​ 2、创建TreeSet集合对象,通过比较器排序进行排序(自己试试通过自然排序实现)
​ 3、创建学生对象
​ 4、把学生对象添加到集合
​ 5、遍历集合

方法一:通过比较器排序进行排序

/*
	定义学生类:
		定义属性:name,ChinaScore,MathScore,及其各自的get/set方法
		定义有参、无参构造方法
		重写toString方法
*/
public static void main(String[] args) {

    //创建TreeSet集合对象,通过比较器进行排序
    TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
        @Override
        public int compare(Student s1, Student s2) {
            //                int num = (s2.getChinaScore() + s2.getMathScore()) - (s1.getChinaScore() + s1.getMathScore());
            //主要条件
            int num = s2.getSum() - s1.getSum();    //判断总分是否相同
            //次要条件
            int num2 = num == 0? s2.getChinaScore()-s1.getChinaScore(): num; //若总分相同,看语文成绩是否相同(若相同则数学成绩也相同)
            int num3 = num2 == 0? s2.getName().compareTo(s1.getName()): num2;  //若总分相同,判断名字是否相同

            return num3;
        }
    });

    //添加学生信息
    Student s1 = new Student("张三", 80,96);
    Student s2 = new Student("李四", 85,99);
    Student s3 = new Student("王五", 88,86);
    Student s4 = new Student("老六", 78,66);
    Student s5 = new Student("桃七", 88,86);  //不同学生,语文数学成绩都相同时,是否会输出

    //将学生添加到集合
    ts.add(s1);
    ts.add(s2);
    ts.add(s3);
    ts.add(s4);
    ts.add(s5);

    //遍历集合
    for (Student s :ts){
        System.out.println(s + "," + s.getSum());
    }
}

/*
Student{name='李四', ChinaScore=85, MathScore=99},184
Student{name='张三', ChinaScore=80, MathScore=96},176
Student{name='王五', ChinaScore=88, MathScore=86},174
Student{name='桃七', ChinaScore=88, MathScore=86},174
Student{name='老六', ChinaScore=78, MathScore=66},144
 */

方法二:通过自然排序实现

/*
    定义学生类
		定义属性:name,age,及其各自的get/set方法
		定义有参、无参构造方法
		实现自然排序(先实现Comparable<E>接口,然后重写compareTo(E e)方法)
 */
public class Student implements Comparable<Student> {	实现Comparable<E>接口
	...
    //重写compareTo(E e)方法
    @Override
    public int compareTo(Student s) {

        int num1 = s.getSum() - this.getSum();
        int num2 = num1 == 0? s.getChinaScore() - this.getChinaScore() : num1;
        int num3 = num2 == 0? s.getName().compareTo(this.getName()) : num2;

        return num3;
    }
}
public static void main(String[] args) {

    //创建集合对象
    TreeSet<Student> ts = new TreeSet<>();

    //添加学生信息
    Student s1 = new Student("张三", 80,96);
    Student s2 = new Student("李四", 85,99);
    Student s3 = new Student("王五", 88,86);
    Student s4 = new Student("老六", 78,66);
    Student s5 = new Student("桃七", 88,86);   //不同学生,语文数学成绩都相同时

    //将学生添加到集合
    ts.add(s1);
    ts.add(s2);
    ts.add(s3);
    ts.add(s4);
    ts.add(s5);

    //遍历集合
    for (Student s :ts){
        System.out.println(s + "," + s.getSum());
    }
}

/*
Student{name='李四', ChinaScore=85, MathScore=99},184
Student{name='张三', ChinaScore=80, MathScore=96},176
Student{name='王五', ChinaScore=88, MathScore=86},174
Student{name='桃七', ChinaScore=88, MathScore=86},174
Student{name='老六', ChinaScore=78, MathScore=66},144
 */

案例:不重复的随机数

需求:编写一个程序,获取10个1-20之间的随机数,要求随机数不能重复,并在控制台输出

思路:
1、创建Set集合对象
2、创建随机数对象
3、判断集合的长度是否小于10
是:产生一个随机数添加到集合
回到3继续
4、遍历集合

public static void main(String[] args) {

    //创建集合对象
    Set<Integer> s = new HashSet<>();

    //创建随机数对象
    Random r = new Random();

    //判断集合长度是否小于10
    while (s.size()<10){
        //产生一个随机数
        int num = r.nextInt(20)+1;
        s.add(num);
    }

    //遍历集合
    for (int i : s){
        System.out.println(i);
    }
}

/*
16
1
2
4
5
6
7
10
14
15
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值