深入理解Collection集合

目录

什么是集合?

集合的特点

Collection 常用的API(它下面的子类都能用)

 List接口

 Set 接口

Collection集合的遍历方式(常用)

1.迭代器

2.foreach(增强for循环)

3.jdk1.8以后 lambda

深入理解List集合

        ArrayList

        LinkedList

深入理解Set集合

        LinkedHashSet

        TreeSet(排序不重复集合)


什么是集合?

 集合是一个大小可变的容器(与数组的区别)

 容器中的每个数据称为一个元素。数据==元素。

集合的特点

 类型不特定,长度不固定,集合有很多种,可以用于不同的场景。

 Collection是最基本的集合接口,注意它是有泛型的,Collection

 Collection接口有个超级接口 Iterable

 Collection又根据有序无序,是否重复,有无索引 分为了List和Set接口

 集合重写了tostring()方法,默认打印出内容

Collection 常用的API(它下面的子类都能用)


          A:添加功能

                          boolean add(Object obj):向集合中添加一个元素

                          boolean addAll(Collection c):向集合中添加一个集合的元素。

          B:删除功能

                          void clear():删除集合中的所有元素。

                          boolean remove(Object obj):从集合中删除指定的元素

                          boolean removeAll(Collection c):从集合中删除一个指定的集合元素。

          C:判断功能

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

                      boolean contains(Object obj):判断集合中是否存在指定的元素。

                      boolean containsAll(Collection c):判断集合中是否存在指定的一个集合中的元素。

          D:遍历功能

                          Iterator iterator():就是用来获取集合中每一个元素。

          E:长度功能

                          int size():获取集合中的元素个数

          F:交集功能

                          boolean retainAll(Collection c):判断两个集合中是否有相同的元素。???

          G:把集合转换成数组

                          Object[] toArray():把集合变成数组

 List接口


            List接口下的集合元素存储有序,可以重复。

            List的特有功能
              A:添加功能

                  void add(int index, Object obj):在指定位置添加元素

              B:删除功能

                  Object remove(int index):根据指定索引删除元素,并把删除的元素返回。

              C:修改功能

                  Object set(int index, Object obj):把指定索引位置的元素修改为指定的值,返回修改前的值。

              D:获取功能

                  int indexOf(Object o):返回指定元素在集合中第一次出现的索引

                  Object get(int index):获取指定位置的元素

                  ListIterator listIterator():列表迭代器

              E:截取功能

                  List subList(int fromIndex, int toIndex):截取集合。

 Set 接口


               Set接口下的元素无序,不可以重复。其下面分为HashSet和TreeSet。

              HashSet
               底层数据结构是哈希表,线程不安全,效率高。

               保证唯一性依赖两个方法:hashCode()和equals()。

               顺序:

                       判断hashCode()值是否相同。

                       相同:继续走equals(),看返回值

                                   如果true:就不添加到集合。

                                   如果false:就添加到集合。

                       不同:就添加到集合。

              TreeSet
                底层数据结构是二叉树,线程不安全,效率高。

                保证元素唯一性的方法时根据返回值是否是0。

                保证排序的两种方式:

                        自然排序(元素具备比较性):实现Comparable接口

                        比较器排序(集合具备比较性):实现Comparator接口

Collection集合的遍历方式(常用)

        什么是遍历?

 遍历就是把容器中的元素一个个访问过去,简单来说就是遍历可以拿到每一个元素,而直接打印Sout(list)是取到它那个对象,能直接打印是因为集合重写了tostring方法,不然打印的就是地址了

(而且集合直接打印其实都是找下标对应值调用stringbuilder拼接的方式的,你要是用了linkedlist还得先get(index) 更难去找了,效率还差)

开发中经常要找最值,统计元素的个数,总和,可以count++呀之类的,都要用到遍历

1.迭代器

public class test{
/* 迭代器方法:
      public Iterator iterator(): 获取集合的迭代器
      E next():获取下一个值
      boolean hasNext():判断是否有下一个值  */

 public static void main(String[] args){

    Collection col=new ArrayList<>();

      col.add("小王");
      col.add("小李");

  //1.得到集合的迭代器对象
  Iterator it=col.iterator();     //迭代器也有泛型变量,和集合泛型变量一致

  //2.使用while循环遍历
   while(it.hasNext()){
       String els=it.next();
      System.out.println(else);
  }
} }

2.foreach(增强for循环)

    foreach是一种遍历形式,可以遍历集合和数组。(注意数组没有迭代器)

    foreach遍历集合实际上是迭代器的简化写法。

    foreach遍历的关键是记住格式。

public class test{
 
 public static void main(String[] args){
    Collection col=new ArrayList<>();
      col.add("小王");
      col.add("小李");
 
  for(String else: col){
       syetem.out.println(else);            //快捷键col.for自动生成
  }
}
}

  foreach遍历没有索引,不知道遍历到了哪个元素

3.jdk1.8以后 lambda

public class test{
 
 public static void main(String[] args){
    Collection col=new ArrayList<>();
      col.add("小王");
      col.add("小李");
 
 col.forEach(s->{
            System.out.println(s);        
        });
}
}

深入理解List集合

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

        ——ArrayList:添加的元素是有序的,可重复的,有索引的

       ——LinkedList:添加的元素是有序的,可重复的,有索引的

       ——Vector:是线程安全的,速度慢,工作中很少用

   List集合继承了Collection集合的所有功能,List系列集合有索引

                  

        ArrayList

                 ArrayList底层是数组,查询快,增删慢!

ArrayList  api方法

import java.util.List;
public class ArrayListDemo {
    public static void main(String[] args) {
        List lists = new ArrayList<>();
        lists.add("花花");
        lists.add("小明");
        lists.add("小赵");
        //增
        lists.add(1, "小李"); //在索引位置增加数据
        System.out.println("增后的数据:"+lists);
        //删
        System.out.println("删除了"+lists.remove(0)); //删除索引值对应的数据,返回被删数据
        System.out.println("删后的数据:"+lists);
        //改
        lists.set(2,"小强"); //修改索引值处的位置
        System.out.println("改后的数据:"+lists);
    }
}

打印输出:

增后的数据:[花花, 小李, 小明, 小赵]
花花
删后的数据:[小李, 小明, 小赵]
改后的数据:[小李, 小明, 小强]

Process finished with exit code 0   

因为List有索引,所以List还可以用普通for循环遍历,一共有四种遍历方式。

        //(1) for循环
        for(int i=0;i it=lists.iterator();
        while(it.hasNext()){
            System.out.print(it.next()); }
        


        //(3)  foreach
        for(String list22:lists)
            System.out.print(list22);
       


        //(4) lambda
         lists.forEach(s -> System.out.print(s));

        LinkedList

                 LinkedList底层是链表,查询慢,增删快!

                 LinkedList支持双链表,定位首尾的元素很快,增删首尾元素也很快!

                 所以LinkedList除了拥有List的功能,还拥有很多操作首尾元素的特殊功能。

LinkedList  api方法

package List;
import java.util.LinkedList;
public class LinkedListDemo {
    //未用到但是也是它特殊方法
    public static void main(String[] args) {
        //用LinkedList来模拟一个队列,先进先出
        LinkedList queue = new LinkedList<>();  //为什么不用多态?因为多态不能用子类特有功能
        //入队(排队)
        queue.addLast("1号");
        queue.addLast("2号");
        queue.addLast("3号");
        queue.addLast("4号");
        System.out.println(queue);
        //出队
        for (int i = 0; i < queue.size(); i++) {
            System.out.println(queue.removeFirst());    //输出为1号,2号,因为执行removeFirst的时候栈的大小也在减小 正常遍历还是用迭代器吧
        }                                               //当然也有getFirst(),也是不删除的方法
        //用LinkedList来模拟一个栈,先进后出
        LinkedList stack = new LinkedList<>();
        //压栈
        stack.push("子弹1"); //注意:push和addFirst方法一毛一样,它存在的意义emm就是为了应和”压“吧
        stack.push("子弹2");
        stack.push("子弹3");
        stack.push("子弹4");
        //出栈
        System.out.println(stack.pop());        //pop就是removeFirst
    }
}

深入理解Set集合

 Sett集合:添加的元素是无序的,不重复的,无索引的

        ——HashSet:添加的元素是无序的,不重复的,无索引的   //基本完全继承Set(可以用多态)

       ——LinkedHashSet:添加的元素是有序的,不重复的,有索引的  //HashSet的子类

       ——TreeSet:不重复,无索引,按照大小默认升序排序!(可排序集合)

研究两个问题:

      1)Set集合添加的元素是不重复的,怎么去重复

答:先比较hashCode(哈希值相当于内存地址,暂时这么理解,那hashcode和==有什么区别呢),hashCode不同则不重复;若hashCode相同,则继续判断equals,equals为true则重复,equals为false则不重复。

需要重写equals()和hashCode()方法。重写hashCode()后,就是 两个对象的内容一样返回的哈希值也一样, 能够保证hashCode相同再继续去判断equals,就能返回true

      2)Set集合元素无序的原因是什么?

答:其根本原因是底层采用了哈希表存储数据。

JDK1.8之前:哈希表=数组+链表+(哈希算法)

JDK1.8之后(包括):哈希表=数组+链表+红黑树+(哈希算法)

       当链表长度超过阈值(8)时,将链表转换为红黑树,这样会大大减小查找时间

–>哈希表由数组和链表组成
–>当集合添加元素的时候会生成一个哈希值,哈希值是根据地址或字符串或数字算出来的int类型数值
–>根据元素的哈希值跟数组的长度<16>求余算出应存入位置
–>判断数组中当前位置是否为NULL,(1)如果为null直接存入 (2) 如果不为null,表示有元素,采用equals比较属性值①一样则不存 ②不一样,则存入数组,老元素挂在新元素下面形成链表
–>如果数组存满到16*0.75=12时,数组就会自动扩容为原来的两倍
 

        LinkedHashSet

底层仍然是哈希表来存储元素,

但是每个元素都额外带一个列来维护添加数据!

但也因为多了一个存储顺序的链会占内存空间。

        TreeSet(排序不重复集合)

package Set;
import test.Student;

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

//    TreeSet排序方式:
//   1.有值特性的元素可以升序排序。(float,double,int)
//   2.字符串类型的元素会按照首字符的编号排序。(String)
//   3.对于自定义的引用数据类型,Treeset默认无法排序,执行会报错

//  自定义的引用数据类型的排序实现:
//          Treeset默认无法排序,所以我们需要定制排序的大小规则,程序员定义大小规则的方案有2种:
//   a.直接为对象的类实现比较器规则接口Comparable,重写比较方法(拓展方式)
//比较规则:
//如果程序员认为比较者大于被比较者,返回正数
//如果程序员认为比较者小于被比较者,返回负数
//如果程序员认为比较者等于被比较者,返回0
//   b.直接为集合设置比较器Comparator对象,重写比较方法
//比较规则:
//如果程序员认为比较者大于被比较者,返回正数
//如果程序员认为比较者小于被比较者,返回负数
//如果程序员认为比较者等于被比较者,返回0

//如果集合和对象都存在大小规则,优先使用集合的比较器

public class TreeSetADemo {
    public static void main(String[] args) {
        Set set = new TreeSet<>();
        set.add(99.2);
        set.add(929.4);
        set.add(299.6);
        set.add(993.8);
        System.out.println(set);       //打印:[99.2, 299.6, 929.4, 993.8]

        Set set2 = new TreeSet<>();
        set2.add(new Student(1, "小明"));
        set2.add(new Student(2, "小王"));
        set2.add(new Student(3, "小栗子"));
        System.out.println(set2);               //[Student{stunage=1, stuname='小明'}, Student{stunage=2, stuname='小王'}, Student{stunage=3, stuname='小栗子'}]

        Set set3 = new TreeSet<>(new Comparator() {
            @Override
            public int compare(Student o1, Student o2) {
                //o1比较者,o2被比较者
                return o1.getStunage()-o2.getStunage();
            }
        });
        set3.add(new Student(1, "小明"));
        set3.add(new Student(2, "小王"));
        set3.add(new Student(3, "小栗子"));
        System.out.println(set3);       //[Student{stunage=1, stuname='小明'}, Student{stunage=2, stuname='小王'}, Student{stunage=3, stuname='小栗子'}]


    }
}
package test;

public class Student implements  Comparable {
     private  int stunage;
     private  String stuname;

    public int getStunage() {
        return stunage;
    }

    public void setStunage(int stunage) {
        this.stunage = stunage;
    }

    public Student(int stunage, String stuname) {
        this.stunage = stunage;
        this.stuname = stuname;
    }

    @Override
    public String toString() {
        return "Student{" +
                "stunage=" + stunage +
                ", stuname='" + stuname + '\'' +
                '}';
    }

    //重写比较方法
     //比较者:this
     //被比较者:o
    @Override
    public int compareTo(Student o) {
        //比较规则:
        //如果程序员认为比较者大于被比较者,返回正数
        //如果程序员认为比较者小于被比较者,返回负数
        //如果程序员认为比较者等于被比较者,返回0
//        if(this.stunage>o.stunage){
//            return 1;}
//           else if(this.stunage

你可能感兴趣的:(java基础知识,集合,java)