Java集合详解

集合

Collection(单列集合)(接口)

Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的、
  • 一些常用的方法

方法名称

说明

返回值

public boolean add(E e)

把给定的对象添加到当前集合中

添加成功与否

public void clear()

清空集合中所有的元素

public boolean remove(E e)

把给定的对象在当前集合中删除

删除成功与否

public boolean contains(Object obj)

判断当前集合是否包含给定的对象

是否

public boolean isEmpty()

判断当前集合是否为空

是否

public int size()

返回集合中元素的个数

返回集合中元素的个数

  • remove 因为Collection里面定义的是共性方法,所以此时不能通过索引进行删除,只能通过元素的对象进行删除

  • contains 底层是依赖equals方法进行判断是否存在,如果集合存储的是自定义的对象,也想通过此方法判断是否包含,那么在javabean类中一定要重写equals方法

Collection的遍历方式

迭代器在java中的类是Iterator,迭代器是集合专用的遍历方式
Iterator<E> iterator()     //返回迭代器对象,默认指向当前集合的0索引

方法名称

说明

boolean hasNext()

判断当前位置是否有元素,有元素返回true,没有元素返回false

E next()

获取当前位置的元素,并将迭代器对象移向下一个位置

迭代器遍历
Iterator<String> it = list.iterator();           //创建指针
while(it.hasNext()){                             //判断是否有元素
    String s = it.next;                          //获取元素  移动指针
  	System.out.println(s);
}

迭代器源码分析

  • 注意

  • 迭代器遍历完毕,指针不会复位

  • 迭代器遍历时,不能用集合的方法进行增加或者删除

增强for的底层就是迭代器,为了简化迭代器的代码书写的
所有的单列集合和数组才能用增强for进行遍历
//格式
//s是一个第三方变量,修改了s的值不会改变集合中原本的数据
for(元素的数据类型 变量名(s) : 数组或者集合){
    
}
lambda表达式遍历
//使用匿名内部类
//底层它会自己遍历集合,依次得到每一个元素,把得到的每一个元素,传递给下面的accept方法
c.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
 //使用lambda表达式
c.forEach(s -> System.out.println(s));

List(接口)

List系列集合:添加的元素是有序、可重复、有索引
Collection的方法List都继承了
List因为有索引,所以多了很多索引操作的方法

方法名称

说明

void add(int index,E element)

在此集合中的指定位置插入指定的元素

E remove(int index)

删除指定索引处的元素,返回被删除的元素

E set(int index,E element)

修改指定索引处的元素,返回被修改的元素

E get(int index)

返回指定索引的元素

List遍历方法

除了刚刚通用的遍历方法外,List集合还可以用普通for遍历和listIterator进行遍历,listIterator继承了Iterator这个接口,其中的方法基本相同

ArrayList
ArrayList集合底层原理
  1. 利用空参创建的集合,在底层创建一个默认长度为0的数组

  1. 添加第一个元素时,底层会创建一个新的长度为10的数组

  1. 存满时,会扩容1.5倍

  1. 如果一次添加多个元素,1.5倍还放不下,则新创建的数组以实际·为准

LinkedList
底层数据结构是双链表,查询慢,增删快,但是如果操作的是首尾元素,速度也是极快的
LinkList本身多了很多直接操作首尾元素的特有API

特有方法

说明

public void addFirst(E e)

在该列表开头插入指定的元素

public void addLast(E e)

将指定的元素追加到此列表的末尾

public E getFirst()

返回此列表的第一个元素

public E getLast()

返回此列表的最后一个元素

public E removeFirst()

从此列表删除并返回第一个元素

public E removeLast()

从此列表删除并返回最后一个元素

Vector

知道存在即可,已经被淘汰

Set(接口)

Set系列集合:添加的元素是无序、不重复、无索引
Set接口中的方法基本上与Collection的API一致
HashSet
无序、不重复、无索引
HashSet集合底层采取哈希表存储结构
哈希表是一种对于增删改查数据性能都较好的结构

哈希值

  • 根据hashCode方法算出来的int类型的整数

  • 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算

  • 一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值

  • 对象的哈希值的特点、

  • 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的

  • 如果已经重写hashCode方法,不同的对象只要属性值相同,计算出的哈希值是相同的

  • 在小部分情况下,不同属性值的地址值计算出来的哈希值也有可能一样(哈希碰撞)

HashSet底层原理

  • 加载因子就是数组的扩容时机,当数组中存了16*0.75=12个元素时,数组就会扩容成原来的两倍

  • 存入的位置:int index = (数组长度 - 1 & 哈希值)

  • 当链表长度大于8而且数组长度大于等于64时当前链表自动转成红黑树

  • 如果集合中存储的是自定义对象,必须要重写hashCode和equals方法

LinkedHashSet
有序、不重复、无索引
这里的有序指的是保证存储和取出的元素顺序一致
原理:底层数据结构是依赖哈希表,只是每个元素有额外的多了一个双链表的机制记录存储的顺序

TreeSet
可排序、不重复、无索引
可排序:按照元素的默认规则(由小到大)排序
TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好

TreeSet的两种比较方式

  • 方式一:默认排序/自然排序:javabean类实现Comparable接口指定比较规则

//学生类
public class Student implements Comparable<Student>{
    ...
    ...
    ...
    @Override
    //this:表示当前要添加的元素
    //o:表示已经在红黑树存在的元素

    //返回值:
    //负数:表示当前要添加的元素是小的,存左边
    //正数:表示当前要添加的元素是大的,存右边
    //0 :表示当前要添加的元素已经存在,舍弃
    public int compareTo(Student o) {
        System.out.println("--------------");
        System.out.println("this:" + this);
        System.out.println("o:" + o);
        //指定排序的规则
        //只看年龄,我想要按照年龄的升序进行排列
        return this.getAge() - o.getAge();
    }
}
public static void main(String[] args) {
        /*
            需求:创建TreeSet集合,并添加3个学生对象
            学生对象属性:
                姓名,年龄。
                要求按照学生的年龄进行排序
                同年龄按照姓名字母排列(暂不考虑中文)
                同姓名,同年龄认为是同一个人

            方式一:
                默认的排序规则/自然排序
                Student实现Comparable接口,重写里面的抽象方法,再指定比较规则
        */


        //1.创建三个学生对象
        Student s1 = new Student("zhangsan",23);
        Student s2 = new Student("lisi",24);
        Student s3 = new Student("wangwu",25);
        Student s4 = new Student("zhaoliu",26);


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

        //3.添加元素
        ts.add(s3);
        ts.add(s2);
        ts.add(s1);
        ts.add(s4);

        //4.打印集合
        System.out.println(ts);

  • 方式二:比较器排序:创建TreeSet对象的时候,传递比较器Comparator指定规则

public static void main(String[] args) {
       /*
            需求:请自行选择比较器排序和自然排序两种方式;
            要求:存入四个字符串, “c”, “ab”, “df”, “qwer”
            按照长度排序,如果一样长则按照首字母排序

            采取第二种排序方式:比较器排序
        */

        //1.创建集合
        //o1:表示当前要添加的元素
        //o2:表示已经在红黑树存在的元素
        //返回值规则跟之前是一样的
        
//        TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
//            @Override
//            public int compare(String o1, String o2) {
//                // 按照长度排序
//                int i = o1.length() - o2.length();
//                //如果一样长则按照首字母排序
//                i = i == 0 ? o1.compareTo(o2) : i;
//                return i;
//            }
//        });
        
        TreeSet<String> ts = new TreeSet<>((o1, o2)->{
                // 按照长度排序
                int i = o1.length() - o2.length();
                //如果一样长则按照首字母排序
                i = i == 0 ? o1.compareTo(o2) : i;
                return i;
        });

        //2.添加元素
        ts.add("c");
        ts.add("ab");
        ts.add("df");
        ts.add("qwer");


        //3.打印集合
        System.out.println(ts);
    }
//学生类
public class Student2 implements Comparable<Student2> {
    ...
    ...
    ...

   /* 按照总分从高到低输出到控制台
    如果总分一样,按照语文成绩排
    如果语文一样,按照数学成绩排
    如果数学成绩一样,按照英语成绩排
    如果英文成绩一样,按照年龄排
    如果年龄一样,按照姓名的字母顺序排
    如果都一样,认为是同一个学生,不存。*/
    @Override
    public int compareTo(Student2 o) {
        int sum1 = this.getChinese() + this.getMath() + this.getEnglish();
        int sum2 = o.getChinese() + o.getMath() + o.getEnglish();

        //比较两者的总分
        int i = sum1 - sum2;
        //如果总分一样,就按照语文成绩排序
        i = i == 0 ? this.getChinese() - o.getChinese() : i;
        //如果语文成绩一样,就按照数学成绩排序
        i = i == 0 ? this.getMath() - o.getMath() : i;
        //如果数学成绩一样,按照英语成绩排序(可以省略不写)
        i = i == 0 ? this.getEnglish() - o.getEnglish() : i;
        //如果英文成绩一样,按照年龄排序
        i = i == 0 ? this.getAge() - o.getAge() : i;
        //如果年龄一样,按照姓名的字母顺序排序
        i = i == 0 ? this.getName().compareTo(o.getName()) : i;
        return i;
    }
}
 public static void main(String[] args) {
      /*  需求:创建5个学生对象
        属性:(姓名,年龄,语文成绩,数学成绩,英语成绩),
        按照总分从高到低输出到控制台
        如果总分一样,按照语文成绩排
        如果语文一样,按照数学成绩排
        如果数学成绩一样,按照英语成绩排
        如果英文成绩一样,按照年龄排
        如果年龄一样,按照姓名的字母顺序排
        如果都一样,认为是同一个学生,不存。

        第一种:默认排序/自然排序
        第二种:比较器排序

        默认情况下,用第一种排序方式,如果第一种不能满足当前的需求,采取第二种方式。


        课堂练习:
            要求:在遍历集合的时候,我想看到总分。

      */


        //1.创建学生对象
        Student2 s1 = new Student2("zhangsan",23,90,99,50);
        Student2 s2 = new Student2("lisi",24,90,98,50);
        Student2 s3 = new Student2("wangwu",25,95,100,30);
        Student2 s4 = new Student2("zhaoliu",26,60,99,70);
        Student2 s5 = new Student2("qianqi",26,70,80,70);


        //2.创建集合
        TreeSet<Student2> ts = new TreeSet<>();

        //3.添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);

        //4.打印集合
        //System.out.println(ts);
        for (Student2 t : ts) {
            System.out.println(t);
        }
    }

Map(双列集合)(接口)

双列集合的特点
双列集合一次需要存一对数据,分别为键和值
键不能重复,值可以重复
键和值是一一对应的,每一个键只能找到自己对应的值
键+值这个整体称之为”键值对“或者”键值对对象“,在Java中叫做”Entry对象"

方法名称

说明

V put(K key,V value)

添加元素

V remove(Object key)

根据键删除键值对元素

void clear()

移除所有的键值对元素

boolean containsKey(Object key)

判断集合是否包含指定的键

boolean containsValue(Object value)

判断集合是否包含指定的值

boolean isEmpty()

判断集合是否为空

int size()

集合的长度,也就是集合中键值对的个数

  • 在添加数据的时候,如果键不存在,那么直接把键值对对象添加到集合中,方法返回null;如果键是存在的,那么会把原来的键值对对象覆盖,会把覆盖的值进行返回

Map集合的遍历

键找值
//获取所有的键,把这些键放到一个单列集合当中
        Set<String> keys = map.keySet();
        for (String key : keys) {
            //利用map集合中的键获取对应的值
            String value = map.get(key);
            System.out.println(key + "=" + value);
键值对
 //通过一个方法获取所有的键值对对象,返回一个Set集合
        Set<Map.Entry<String, String>> entries = map.entrySet();
        //遍历entries集合,得到每一个键值对对象
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "=" + value);
Lambda表达式
map.forEach((key, value) -> { System.out.println(key + "=" + value);});

HashMap

特点都是由键决定的:无序、不重复、无索引
HashMap底层是哈希表结构
如果键存储的是自定义对象,需要重写hashCode和equals方法,如果值存储自定义对象则不需要重写
LinkedHashMap
有序、不重复、无索引
原理和LinkedHashSet相同

TreeMap

不重复、无索引、可排序:对键进行排序
原理与TreeSet相同

排序规则

  • 实现Comparable接口,指定比较规则

/**
         * 键:学生对象
         * 值:籍贯
         * 要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名年龄视为同一个人
         */
        TreeMap<Student,String> m = new TreeMap<>();
        Student s1 = new Student("zhangsan",21);
        Student s2 = new Student("lisi",23);
        Student s3 = new Student("wangwu",20);
        Student s4 = new Student("zhaoliu",20);

        m.put(s1,"河南");
        m.put(s2,"北京");
        m.put(s3,"上海");
        m.put(s4,"江苏");

        System.out.println(m);



//学生类
public class Student implements Comparable<Student>{
    ...
    ...
    ...
    @Override
    public int compareTo(Student o) {
        int i = this.getAge() - o.getAge();
        i = i == 0 ? this.getName().compareTo(o.getName()) : i;
        return i;
    }
}
  • 创建集合时传递Comparator比较器对象,指定比较规则

/**
         * 字符串”aababcabdcdcabe“
         * 统计字符串中每一个字符出现的次数,并按照一下格式输出
         * 输出结果:a(5) b(4) c(3) d(2) e(1)
         */
        String s = "aababcabdcdcabe";
        TreeMap<String,Integer> tm = new TreeMap<>((o1,o2) -> {
                return o1.compareTo(o2);
            }
        );

        for (int i = 0; i < s.length(); i++) {
            String c = s.charAt(i) + "";
            if (tm.containsKey(c)){
                int value = tm.get(c);
                value = value + 1;
                tm.put(c ,value);
            }else {
                tm.put(c ,1);
            }
        }
        StringBuffer sb = new StringBuffer();
        tm.forEach((key,value)->{
            sb.append(key).append(" (").append(value).append(") ");
        });

        System.out.println(sb);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值