20220806 第五组 罗大禹 学习笔记

20220806 第五小组 罗大禹 学习笔记

Java 集合

学习重点

1.比较接口
2.集合

学习内容

Java 集合

比较接口:

Comparable接口:自然排序,排序规则是固定。

​ 实现Comparable接口,重写compareTo方法

compareTo方法返回值代表什么?

​ 返回值类型为int
​ 代表排序结果
​ 负数-1:比较的两个值,调用者小
​ 0:两个值相等
​ 正数1:比较的两个值,调用者大

举例说明

public class Person implements Comparable<Person> {

    private String name;
    private Integer id;
    @Override
    public int compareTo(Person p) {
        if(this.id > p.id){
            return -1;
        }
        if(this.id.equals(p.id)){
            return 0;
        }

        return 1;
    }
}
Comparator接口:临时排序
举例说明:
// 用的时候重写sort方法传入的实参,传入的实参应该为Comparator对象
list.sort((o1,o2) -> {
    if(o1.getId() < o2.getId()){
        return -1;
    }
    if(o1.getId().equals(o2.getId())){
        return 0;
    }
    return 1;
});

集合框架(重要)

集合:

容器,存放数据的一个容器

使用集合的目的:

更方便的存储和操作数据,CRUD。

集合继承结构:
1.Collection:(泛型接口)

存放单值的最大父接口

List(泛型接口):

​ 和数组类似,List可以动态增长,查找元素效率高。插入删除元素的效率低,因为会引起其他元素位置的改变。

有顺序,元素可以重复,顺序指的是添加的先后顺序

Set(泛型接口):

检索元素效率低,删除和插入的效率高,插入和删除不会引起元素移位。

没有顺序,元素不可以重复,顺序指的是添加的先后顺序。

​ Set其实是有顺序,内部有一个专门排序的算法。

  1. 所谓的无序不等于随机
  2. 所谓的无序指的是没有按照添加的先后顺序,其实内部是做了排序的。
2.Map<K,V>:

存放对值的最大父接口
Map(映射):用于保存具有映射关系的数据,Map保存着两组数据:key和value。key和value都可以是任意的引用数据类型,但key不能重复。

注意:List,Set继承自Collection,Map不是

ArrayList:内部结构是一个数组

默认长度为10

实现了List

举例说明:
package com.jsoft.afternoon;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Ch02 {

    public static void main(String[] args) {
        // 创建了一个ArrayList集合
        // 开发中,一般情况下,使用多态创建集合
        // 向上转型
        List<Integer> l1 = new ArrayList<>();
        // 集合的新增
        l1.add(1);
        l1.add(2);
        l1.add(3);
        l1.add(4);
        l1.add(5);
        l1.add(1,-1);

        List<Integer> l2 = new ArrayList<>();
        l2.add(-1);
        l2.add(-2);
        l2.add(-3);
        l2.add(-4);
        l2.add(-5);
        // 在指定位置添加数据
        l2.add(1,100);
		// 将l2集合添加至l1集合尾部
        l1.addAll(l2);

        // 清空集合
        // 清空之后,集合中没有数据size==0,集合为null
        l1.clear();
        
		// 删除指定数据
        l1.remove(Integer.valueOf(100));
        
        // 取出指定位置的元素
        l1.get(0);
        
        // 用指定元素替换指定位置的元素
        l1.set(0,200);
        
        // 判断集合是否为空
        l1.isEmpty();
        
        // 判断集合中是否有该元素,返回值为boolean类型
        l1.contains(1);
        
        // 查找数据,返回下标
        l1.indexOf(2);
        
		// 打印输出集合长度
        System.out.println(l1.size());

        // 集合和数组之间的转换
        
        // 集合--->数组
		// 将l1集合转为数组
        Object[] objects = l1.toArray();
        
        // 数组--->集合     
        // 将数组存进集合 
        int [] arr = new int[]{1,2,3,4,5};
        List<int[]> arr1 = List.of(arr);
        // 打印输出arr第0位数据
        System.out.println(arr1.get(0)[0]);
        // 将数据存进集合
        List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> integers1 = List.of(1, 23, 4, 5);        
    }
}
数组和集合之间的转换,建议自己封装一个工具类
import java.util.ArrayList;
import java.util.List;

public class ArrayConvertUtil {

    // 传入集合,将集合转为数组
    public static Object[] toArrayConvert(List list) {

        Object[] objects = new Object[list.size()];

        for (int i = 0; i < list.size(); i++) {
            objects[i] = list.get(i);
        }

        return objects;
    }
    
	// 传入数组,将数组转为集合
    public static List toListConvert(Object [] arr) {

        List list = new ArrayList();

        for (Object o : arr) {
            list.add(o);
        }

        return list;
    }

    public static void main(String[] args) {

        List<Integer> l1 = new ArrayList<>();
        l1.add(1);
        l1.add(2);
        l1.add(3);
        l1.add(4);
        l1.add(5);
        l1.add(1,-1);

        Object[] objects = ArrayConvertUtil.toArrayConvert(l1);
        System.out.println(objects[0]);

    }

}
注意:
  1. 如果初始化集合尽量指定初始化容量,如果确定不了,默认指定为16
  2. 使用泛型时候,一定要使用引用数据类型。

面试题:

  1. List和Set的区别

    List:有顺序,元素可以重复,顺序指的是添加的先后顺序

    Set:没有顺序,元素不可以重复,顺序指的是添加的先后顺序。

  2. HashSet(内部结构Hash表)和LinkedHashSet的区别和联系

package com.jsoft.afternoon;

import java.util.HashSet;
import java.util.Set;

 public class Ch02 {

    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        set.add(Integer.valueOf(200));
        set.add(4);
        set.add(15);
        set.add(38);
        set.add(Integer.valueOf(200));
        System.out.println(set);
    }
}

List

数据是有顺序(添加的先后顺序)的,数据是可以重复。
ArrayList:内部结构是数组。比较适合做高频率的查找,遍历。
LinkedList:内部结构是双向链表。比较适合做高频率的新增和删除。
Vector:和ArrayList几乎一模一样。
面试题:

  1. Collection和Map接口的区别

    Collection:存储单值的最大父接口

    Map:存储对值的最大父接口

  2. ArrayList和LinkedList的区别

    ArrayList:内部结构是数组。比较适合做高频率的查找,遍历。
    LinkedList:双向链表。比较适合做高频率的新增和删除。

  3. ArrayList和Vector的区别
    ArrayList是线程异步的,线程不安全,效率高
    Vector是线程同步的,线程安全,效率低

举例说明:
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

public class Ch01 {


    public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");

        // 若我们在创建对象的时候用的是多态
        // 父类对象---子类引用
        // 那么我们创建出来的对象只能够调用父类和子类中都有的方法
        
        // LinkedList中的方法
        list.addFirst("z");
        list.addLast("x");

        list.removeFirst();
        list.removeLast();

        // 根据下标索引获取指定位置的元素
        System.out.println(list.get(2));
        System.out.println(list);
    }
}

Set

没有顺序,元素不可以重复,顺序指的是添加的先后顺序

若传入的是引用数据类型,默认情况下比较地址

Set集合如何确保数据的不重复?

引用数据类型的类要重写hashCode和equals方法。

  1. HashSet
  2. TreeSet
  3. LinkedHashSet
举例说明
package com.jsoft.afternoon;


public class Person implements Comparable<Person> {

    private String name;
    private Integer id;

    public Person(String name, Integer id) {
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Person person = (Person) o;

        if (!name.equals(person.name)) return false;
        return id.equals(person.id);
    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + id.hashCode();
        return result;
    }
}
HashSet

无法get,没有输入先后顺序

  1. HashSet集合底层采用了哈希表这种数据结构
  2. HashSet在实例化时,底层实际实例化了个HashMap
  3. 往HashSet集合中存储元素,实际存放到了HashMap集合的key部分
TreeSet

排序规则:要排序的对象的类必须实现Comparable接口

  1. 无序 不可重复 可自动排序(从小到大排序,字符串根据ACSII码从小大排序)
  2. TreeSet集合底层采用了二叉树这种数据结构
  3. TreeSet在实例化时,底层实际实例化了个TreeMap
  4. 往TreeSet集合中存储元素,实际时存放到了TreeMap集合的key部分
LinkedHashSet:

由链表和Hash表实现

继承HashSet,有输入先后顺序,但也不能get,在添加数据的同时维护数据的添加顺序,效率要比HashSet略低一些。

Map(泛型接口)

put根据key来取value

  1. 存储对值K-V
  2. key不能重复,value是可以重复的
  3. 没有顺序(添加的先后顺序)

简单介绍几个子类:

  1. HashMap
  2. Hashtable
  3. Properties
HashMap内部存储结构

HashMap集合底层采用了哈希表这种数据结构

HashMap内部存储结构:

​ jdk1.7之前:链表 + 二叉树

​ jdk1.8及之后:链表 + 数组 + 红黑树

​ HashMap基本上面试上90%会问原理

举例说明:

import java.util.HashMap;
import java.util.Map;

public class Ch07 {

    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();
        map.put("1001","张岳");
        map.put("1002","赵红兵");
        map.put("1003","小北京");
        map.put("1004","李四");
        System.out.println(map);
    }
}
Hashtable实现类:(唯一一个没有驼峰的类)

​ Hashtable和HashMap几乎一模一样

Hashtable集合底层采用了哈希表这种数据结构

面试题:Hashtable和HashMap区别?

​ 1.HashMap是线程异步的,线程不安全的

​ Hashtable是线程同步的,线程安全的

​ 2.HashMap的key可以为null的,

​ Hashtable的key是不可以为null的

Properties:属性

Properties是Hashtable的子类,更多地是用来操作属性文件,用IO流读取属性文件

其他的集合:
  1. LinkedHashMap,在HashMap的基础上维护了一个双向链表。
  2. TreeMap:天然支持排序
  3. Collections:Collections是一个工具类

遍历

List集合的遍历
举例说明:
package com.jsoft.afternoon;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Ch10 {

    public static void main(String[] args) {
       List<String> list = new ArrayList<>();
       list.add("a");
       list.add("b");
       list.add("c");
       list.add("d");

        // 1.for循环
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        // 2.foreach语句
        for (String s : list) {
            System.out.println(s);
        }
        // 3.迭代器
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()) {
            String s = iterator.next();
            iterator.remove();
            System.out.println(s);
        }
    }
}
Set集合的 遍历
举例说明:
package com.jsoft.afternoon;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Ch11 {

    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        set.add(4);
        set.add(15);
        set.add(38);

        // 2.迭代器
        Iterator<Integer> iterator = set.iterator();
        while(iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        // 1.增强for
        for (Integer integer : set) {
            System.out.println(integer);
        }
    }
}
Map集合的遍历
举例说明:
import java.util.*;

public class Ch12 {

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("1001","张岳");
        map.put("1002","赵红兵");
        map.put("1003","小北京");
        map.put("1004","李四");
        map.put("1005","张浩然");

        // 4.迭代器
        Set<String> strings = map.keySet();
        Iterator<String> iterator = strings.iterator();
        while(iterator.hasNext()) {
            String s = iterator.next();
            System.out.println(s + "->" + map.get(s));
        }

        // 3.增强for循环
        // Entry是hashmap的一个内部类
        // 每一组键值对就是一个Entry对象
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            System.out.print(entry.getKey() + "->");
            System.out.println(entry.getValue());
        }

        // 2.增强for循环
        Set<String> strings = map.keySet();
        Collection<String> values = map.values();

        // 1.for循环
        Set<String> strings = map.keySet();
        for (String s : strings) {
            System.out.println(s + "->" + map.get(s));
        }
    }
}
迭代中删除元素
举例说明:
package com.jsoft.afternoon;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

public class Ch13 {

    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("tom");
        names.add("lucy");
        names.add("lucy");
        names.add("lucy");
        names.add("jerry");
	   // 1.for循环
       for (int i = 0; i < names.size(); i++) {
            if(Objects.equals(names.get(i),"lucy")){
                names.remove(i);
                // 1.回调指针
                i--;
            }
            if("lucy".equals(names.get(i))){

            }
        }
        // 2.逆序遍历
        for (int i = names.size() - 1; i >= 0; i--) {
            if(Objects.equals(names.get(i),"lucy")){
                names.remove(i);
            }
        }
        // 3.使用迭代器(推荐)万无一失
        Iterator<String> iterator = names.iterator();
        while(iterator.hasNext()) {
            String s = iterator.next();
            if(Objects.equals(s,"lucy")){
                iterator.remove();
            }
        }
        // 4.增强for循环
        for (String s : names) {
            if(Objects.equals(s,"lucy")){
                names.remove(names.indexOf(s));
            }
        }
        System.out.println(names);
    }
}

面试题
线程安全的问题
并发修改异常
用普通方法遍历,但是用迭代器的方法删除元素,普通方法还在遍历,不知道新增或者删除了元素,相当于多线程操作,会出现并发修改异常
反之一样
foreach循环底层是迭代器方法,不能用普通方法删除元素
迭代器是依赖于集合存在,判断成功以后,如果是新增或删除了元素,但是迭代器不知道,所以报错了

解决:
1.迭代器遍历元素,迭代器删除元素
2.普通for循环遍历,集合删除

集合目前需要掌握的:

  1. 如何创建需要的集合:主要用多态

    主要用List,Map

  2. 各种区别(面试题)

  3. 各种集合方法

  4. 两个比较接口

  5. 各种集合的特点:从接口的层面到实现类的层面

  6. 各种集合API的调用

  7. 重点集合的内部结构。ArrayList、HashSet、HashMap

  8. 各种集合的遍历

  9. 并发问题

  10. 接口、实现类的方法要去看,有个印象

最重要的集合:
ArrayList和HashMap
积压的问题
  1. synchronize原理
  2. ReentrantLock原理
  3. ArrayList原理
  4. LinkedList原理
  5. HashMap原理:重点,面试重灾区
  6. HashSet原理:底层先是HashMap
posted @ 2022-08-07 21:06  怂还嘴硬  阅读(35)  评论(0)    收藏  举报