单例集合(Collection)

Collection集合概述

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

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

1.1数组和集合的区别

- 相同点

  都是容器,可以存储多个数据

- 不同点

  - 数组的长度是不可变的,集合的长度是可变的

  - 数组可以存基本数据类型和引用数据类型

  - 集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类

1.2 单列集合体系结构

List系列集合:添加的元素是有序、可重复、有索引

Set系列集合:添加的元素是无序、不重复、无索引

1.3 常见的方法

注意点:
    Collection是一个接口,我们不能直接创建他的对象。
    所以,我们学习他的方法时,只能创建他的实现类对象
    实现类:ArraysList
目的:为了学习Collection接口里面的方法
格式:Collection coll = new ArrayList<>();

1.4 Collection集合的遍历

1.4.1 迭代器遍历

- 迭代器介绍

  - 迭代器,集合的专用遍历方式

  - Iterator<E> iterator(): 返回此集合中元素的迭代器,通过集合对象的iterator()方法得到

- Iterator中的常用方法

  ​ boolean hasNext(): 判断当前位置是否有元素可以被取出

    E next(): 获取当前位置的元素,将迭代器对象移向下一个索引位置

- 代码演示

public class IteratorDemo1 {
      public static void main(String[] args) {
          //创建集合对象
          Collection<String> c = new ArrayList<>();
  
          //添加元素
          c.add("hello");
          c.add("world");
          c.add("java");
          c.add("javaee");
  
          //Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
          Iterator<String> it = c.iterator();
  
          //用while循环改进元素的判断和获取
          while (it.hasNext()) {//判断当前位置上的元素是否为空
              String s = it.next();//获取当前元素并将指针移动到下一个元素的位置
              System.out.println(s);
          }
      }
  }

1.4.2 增强for

- 介绍

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

  - 实现Iterable接口的类才可以使用迭代器和增强for

  - 简化数组和Collection集合的遍历

- 格式

for(集合/数组中元素的数据类型 变量名 :  集合/数组名) {

                 // 已经将当前遍历到的元素封装到变量中了,直接使用变量即可

}

- 代码演示

public class MyCollectonDemo1 {
      public static void main(String[] args) {
          ArrayList<String> list =  new ArrayList<>();
          list.add("a");
          list.add("b");
          list.add("c");
          list.add("d");
          list.add("e");
          list.add("f");
  
          //1,数据类型一定是集合或者数组中元素的类型
          //2,str仅仅是一个变量名而已,在循环的过程中,依次表示集合或者数组中的每一个元素
          //3,list就是要遍历的集合或者数组
          for(String str : list){
              System.out.println(str);
          }
      }
  }

1.4.3 lambda表达式

利用forEach方法,再结合lambda表达式的方式进行遍历、

- 代码演示

public class A07_CollectionDemo7 {
    public static void main(String[] args) {
       /* 
        lambda表达式遍历:
                default void forEach(Consumer<? super T> action):
        */

        //1.创建集合并添加元素
        Collection<String> coll = new ArrayList<>();
        coll.add("zhangsan");
        coll.add("lisi");
        coll.add("wangwu");
        //2.利用匿名内部类的形式
        //底层原理:
        //其实也会自己遍历集合,依次得到每一个元素
        //把得到的每一个元素,传递给下面的accept方法
        //s依次表示集合中的每一个数据
       /* coll.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });*/

        //lambda表达式
        coll.forEach(s -> System.out.println(s));
    }
}

一、List集合

2.1  List集合的概述和特点【记忆】

- List集合的概述

          - 有序集合,这里的有序指的是存取顺序

          - 用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素

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

- List集合的特点

          - 存取有序:存和取的元素顺序一致

          - 可以重复:可以通过索引操作元素

          - 有索引:存储的元素可以重复

2.2  List集合的特有方法

        - List继承了Collection的所有方法

        - List集合因为有索引,所以多了很多索引操作的方法

- 示例代码

public class MyListDemo {
      public static void main(String[] args) {
          List<String> list = new ArrayList<>();
          list.add("aaa");
          list.add("bbb");
          list.add("ccc");
          //method1(list);
          //method2(list);
          //method3(list);
          //method4(list);
      }
  
      private static void method4(List<String> list) {
          //        E get(int index)		返回指定索引处的元素
          String s = list.get(0);
          System.out.println(s);
      }
  
      private static void method3(List<String> list) {
          //        E set(int index,E element)	修改指定索引处的元素,返回被修改的元素
          //被替换的那个元素,在集合中就不存在了.
          String result = list.set(0, "qqq");
          System.out.println(result);
          System.out.println(list);
      }
  
      private static void method2(List<String> list) {
          //        E remove(int index)		删除指定索引处的元素,返回被删除的元素
          //在List集合中有两个删除的方法
          //第一个 删除指定的元素,返回值表示当前元素是否删除成功
          //第二个 删除指定索引的元素,返回值表示实际删除的元素
          String s = list.remove(0);
          System.out.println(s);
          System.out.println(list);
      }
  
      private static void method1(List<String> list) {
          //        void add(int index,E element)	在此集合中的指定位置插入指定的元素
          //原来位置上的元素往后挪一个索引.
          list.add(0,"qqq");
          System.out.println(list);
      }
  }

2.3  List集合的五种遍历方式【应用】

1. 迭代器

2. 列表迭代器

3. 增强for

4. Lambda表达式

5. 普通for循环

其中迭代器、增强for、lambda表达式与Collection集合中所用得遍历方式一样,因为List集合是有序的且有索引的,因此List集合的遍历方式多了列表迭代器、普通for循环两种

- 代码示例

//创建集合并添加元素
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");

//1.迭代器
/*Iterator<String> it = list.iterator();
     while(it.hasNext()){
        String str = it.next();
        System.out.println(str);
}*/


//2.增强for
//下面的变量s,其实就是一个第三方的变量而已。
//在循环的过程中,依次表示集合中的每一个元素
/* for (String s : list) {
       System.out.println(s);
   }*/

//3.Lambda表达式
//forEach方法的底层其实就是一个循环遍历,依次得到集合中的每一个元素
//并把每一个元素传递给下面的accept方法
//accept方法的形参s,依次表示集合中的每一个元素
//list.forEach(s->System.out.println(s) );


//4.普通for循环
//size方法跟get方法还有循环结合的方式,利用索引获取到集合中的每一个元素
/*for (int i = 0; i < list.size(); i++) {
            //i:依次表示集合中的每一个索引
            String s = list.get(i);
            System.out.println(s);
        }*/

// 5.列表迭代器
//获取一个列表迭代器的对象,里面的指针默认也是指向0索引的

//额外添加了一个方法:在遍历的过程中,可以添加元素
ListIterator<String> it = list.listIterator();
while(it.hasNext()){
    String str = it.next();
    if("bbb".equals(str)){
        //qqq
        it.add("qqq");
    }
}
System.out.println(list);

1、List的实现类ArrayList源码分析:

核心步骤:

1. 创建ArrayList对象的时候,他在底层先创建了一个长度为0的数组。

   数组名字:elementDate,定义变量size。

   size这个变量有两层含义:

   ①:元素的个数,也就是集合的长度

   ②:下一个元素的存入位置

2. 添加元素,添加完毕后,size++

扩容时机一:

3. 当存满时候,会创建一个新的数组,新数组的长度,是原来的1.5倍,也就是长度为15.再把所有的元素,全拷贝到新数组中。如果继续添加数据,这个长度为15的数组也满了,那么下次还会继续扩容,还是1.5倍。

扩容时机二:

4. 一次性添加多个数据,扩容1.5倍不够,怎么办呀?

如果一次添加多个元素,1.5倍放不下,那么新创建数组的长度以实际为准。

举个例子:

在一开始,如果默认的长度为10的数组已经装满了,在装满的情况下,我一次性要添加100个数据很显然,10扩容1.5倍,变成15,还是不够,

怎么办?

此时新数组的长度,就以实际情况为准,就是110

添加一个元素时的扩容:

添加多个元素时的扩容:

2、LinkedList源码分析:

底层是双向链表结构

核心步骤如下:

1. 刚开始创建的时候,底层创建了两个变量:一个记录头结点first,一个记录尾结点last,默认为null

2. 添加第一个元素时,底层创建一个结点对象,first和last都记录这个结点的地址值

3. 添加第二个元素时,底层创建一个结点对象,第一个结点会记录第二个结点的地址值,last会记录新结点的地址值

二、Set集合

Set  集合概述和特点【应用】

        - 不可以存储重复元素

        - 没有索引,不能使用普通for循环遍历

2.2  Set集合的使用【应用】

存储字符串并遍历

代码示例:

public class MySet1 {
    public static void main(String[] args) {
      	//创建集合对象
        Set<String> set = new TreeSet<>();
      	//添加元素
        set.add("ccc");
        set.add("aaa");
        set.add("aaa");
        set.add("bbb");

//        for (int i = 0; i < set.size(); i++) {
//            //Set集合是没有索引的,所以不能使用通过索引获取元素的方法
//        }
      
      	//遍历集合
        Iterator<String> it = set.iterator();
        while (it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("-----------------------------------");
        for (String s : set) {
            System.out.println(s);
        }
    }
}

1、TreeSet集合

1.1 TreeSet集合概述和特点【应用】

        - 不可以存储重复元素

        - 没有索引

        - 可以将元素按照规则进行排序

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

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

1.2  TreeSet集合基本使用【应用】

存储Integer类型的整数并遍历

代码示例:

public class TreeSetDemo01 {
    public static void main(String[] args) {
        //创建集合对象
        TreeSet<Integer> ts = new TreeSet<Integer>();

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

        ts.add(30);

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

1.3  自然排序Comparable的使用【应用】

- 案例需求

  - 存储学生对象并遍历,创建TreeSet集合使用无参构造方法

  - 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

- 实现步骤

  1. 使用空参构造创建TreeSet集合

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

  2. 自定义的Student类实现Comparable接口

     + 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法

  3. 重写接口中的compareTo方法

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

- 代码实现

学生类

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

      @Override
      public int compareTo(Student o) {
          //按照对象的年龄进行排序
          //主要判断条件: 按照年龄从小到大排序
          int result = this.age - o.age;
          //次要判断条件: 年龄相同时,按照姓名的字母顺序排序
          result = result == 0 ? this.name.compareTo(o.getName()) : result;
          return result;
      }
  }

测试类

public class MyTreeSet2 {
      public static void main(String[] args) {
          //创建集合对象
          TreeSet<Student> ts = new TreeSet<>();
  	    //创建学生对象
          Student s1 = new Student("zhangsan",28);
          Student s2 = new Student("lisi",27);
          Student s3 = new Student("wangwu",29);
          Student s4 = new Student("zhaoliu",28);
          Student s5 = new Student("qianqi",30);
  		//把学生添加到集合
          ts.add(s1);
          ts.add(s2);
          ts.add(s3);
          ts.add(s4);
          ts.add(s5);
  		//遍历集合
          for (Student student : ts) {
              System.out.println(student);
          }
      }
  }

1.4 比较器排序Comparator的使用【应用】

- 案例需求

  - 存储老师对象并遍历,创建TreeSet集合使用带参构造方法

  - 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

- 实现步骤

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

  - 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法

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

- 代码实现

  老师类

public class Teacher {
      private String name;
      private int age;

      public Teacher() {
      }

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

测试类

public class MyTreeSet4 {
      public static void main(String[] args) {
        	//创建集合对象
          TreeSet<Teacher> ts = new TreeSet<>(new Comparator<Teacher>() {
              @Override
              public int compare(Teacher o1, Teacher o2) {
                  //o1表示现在要存入的那个元素
                  //o2表示已经存入到集合中的元素
                
                  //主要条件
                  int result = o1.getAge() - o2.getAge();
                  //次要条件
                  result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
                  return result;
              }
          });
  		//创建老师对象
          Teacher t1 = new Teacher("zhangsan",23);
          Teacher t2 = new Teacher("lisi",22);
          Teacher t3 = new Teacher("wangwu",24);
          Teacher t4 = new Teacher("zhaoliu",24);
  		//把老师添加到集合
          ts.add(t1);
          ts.add(t2);
          ts.add(t3);
          ts.add(t4);
  		//遍历集合
          for (Teacher teacher : ts) {
              System.out.println(teacher);
          }
      }
  }

1.5 总结TreeSet的原理和使用(Comparable和comparator)

  1. TreeSet中的元素不允许重复,但是有序
  2. TreeSet采用树结构存储数据,存入元素时需要和树中元素进行对比,需要指定比较策略。可以通过Comparable和Comparator来指定比较策略。
  3. 实现了Comparable的系统类可以顺利存入TreeSet。自定义类可以实现Comparable接口来指定比较策略。
  4. 可创建Comparator接口实现类来指定比较策略,并通过TreeSet构造方法参数传入。这种方式尤其对系统类非常适用。

2、HashSet集合

2.1HashSet集合概述和特点【应用】

- 底层数据结构是哈希表

- 存取无序

- 不可以存储重复元素

- 没有索引,不能使用普通for循环遍历

2.2HashSet集合的基本应用【应用】

存储字符串并遍历

代码示例:

public class HashSetDemo {
    public static void main(String[] args) {
        //创建集合对象
        HashSet<String> set = new HashSet<String>();

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

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

2.3 哈希值【理解】

- 哈希值简介

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

- 如何获取哈希值

  ​ Object类中的public int hashCode():返回对象的哈希码值

- 哈希值的特点

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

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

3、LinkedHashSet集合

LinkedHashSet集合的特点和原理
    特点:有序、不重复、无索引
    原理:底层基于哈希表,比起HashSet多了一个双链表记录添加顺序,所以它是有序的
如果数据去重,默认使用HashSet,如果要求去重且存取有序,才使用LinkedHashSet

代码示例

public class a04_LinkedHashSetDemo {
    public static void main(String[] args) {
        
        //1、创建学生对象
        Student s1 = new Student("zhangsan",21);
        Student s2 = new Student("lisi",22);
        Student s3 = new Student("wangwu",21);
        Student s4 = new Student("zhangsan",21);

        //2、创建集合并添加学生
        LinkedHashSet<Student> lhs = new LinkedHashSet<>();

        //添加元素
        System.out.println(lhs.add(s1));
        System.out.println(lhs.add(s2));
        System.out.println(lhs.add(s3));
        System.out.println(lhs.add(s4));

        //打印集合
        System.out.println(lhs);
    }
}

三、单例集合总结

1、如果想要集合中的元素可重复

        - 用ArrayList集合,基于数组的

2、如果想要集合中的元素可重复,而且当前的增删操作明显多于查询

        - 用LinkedList集合,基于链表的

3、如果想对集合中的元素去重

        - 用HashSet集合,基于哈希表的

4、如果对集合中的元素去重,而且保证存取顺序

        - 用LinkedHashSet集合,基于哈希表和双向链表的,效率低于HashSet

5、如果想对集合中的元素进行排序

        - 用TreeSet集合,基于红黑树,后续也可以用List集合实现排序

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值