首页 > 编程语言 >关于我学习java的小结07

关于我学习java的小结07

时间:2024-09-19 22:19:27浏览次数:11  
标签:map set java String 元素 add key 小结 07

一、知识点

本节课的知识点为集合、泛型、Map。

二、目标

  1. 了解集合关系图。

  2. 掌握List和Set的区别。

  3. 掌握ArrayList和LinkedList的区别。

  4. 熟练使用集合相关API。

三、内容分析

  1. 重点

    • 集合、泛型、Map。

  2. 难点

    • 集合相关API的使用。

    • 各个集合底层原理的区别。

四、内容

1、泛型

泛型的本质就是"参数化类型",将原来具体的类型参数化。

// 这个T可以换成随便一个字母,我们一般会使用大写字母。如果有多个,使用<T,R,...>
public class Student<T> {

    private String name;

    private T sex;

    public String getName() {
        return name;
    }

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

    public T getSex() {
        return sex;
    }

    public void setSex(T sex) {
        this.sex = sex;
    }

    public static void main(String[] args) {
        // 定义的时候设置<String>,意味着Student<T>的T就是String,所以在setSex中只能传递String类型的数据进去
        Student<String> student1 = new Student<>();
        student1.setSex("1");

        // 定义的时候设置<Integer>,意味着Student<T>的T就是Integer,所以在setSex中只能传递Integer类型的数据进去
        Student<Integer> student2 = new Student<>();
        student2.setSex(1);
    }
}

2、集合

用来存放多个对象的容器。

  1. 集合主要是两组(单列集合、双列集合)。

  2. Collection接口有两个重要的子接口 List Set,它们的实现子类都是单列集合。

  3. Map接口的实现子类是双列集合,存放的Key-Value(键值对)。

java.util.Collection下的接口和继承类关系简易结构图:

java.util.Map下的接口和继承类关系简易结构图:

2.1 List

存取有序的集合,并且有索引值,元素可以重复。

2.1.1 ArrayList

底层使用数组实现。不是线程安全的,查询速度快

//利用数组实现
// 一个学生数组
String[] strArr1 = new String[3];
strArr1[0] = "张三";
strArr1[1] = "李四";
strArr1[2] = "王五";

// 添加一个新同学
String[] strArr2 = new String[4];
for(int i = 0; i < strArr1.length; i++) {
    strArr2[i] = strArr1[i];
}
strArr2[3] = "赵六";
//用集合实现
public static void main(String[] args) {

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

    // 添加元素,使用add方法,add(类型由泛型决定)
    list.add("张三");
    list.add("李四");
    list.add("王五");

    // 获取元素, 使用get方法,get(下标从0开始)
    String name = list.get(1);
    System.out.println(name); // 李四

    // 遍历List
    for(int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }

    // 增强for循环遍历
    for(String str:list) {
        System.out.println(str);
    }

    // 使用迭代器遍历
    Iterator<String> iterator = list.iterator();
    while(iterator.hasNext()) {
        System.out.println(iterator.next());
    }
}

常用方法:查看jdk文档。

返回值类型方法和描述
booleanadd(E e) 将指定的元素追加到此列表的末尾。
voidadd(int index, E element) 在此列表中的指定位置插入指定的元素。
booleanaddAll(Collection<? extends E> c) 按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。
booleanaddAll(int index, Collection<? extends E> c) 将指定集合中的所有元素插入到此列表中,从指定的位置开始。
voidclear() 从列表中删除所有元素。
booleancontains(Object o) 如果此列表包含指定的元素,则返回 true
Eget(int index) 返回此列表中指定位置的元素。
intindexOf(Object o) 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
booleanisEmpty() 如果此列表不包含元素,则返回 true
Iterator<E>iterator() 以正确的顺序返回该列表中的元素的迭代器。
intlastIndexOf(Object o) 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
Eremove(int index) 删除该列表中指定位置的元素。
booleanremove(Object o) 从列表中删除指定元素的第一个出现(如果存在)。
booleanremoveAll(Collection<?> c) 从此列表中删除指定集合中包含的所有元素。
Eset(int index, E element) 用指定的元素替换此列表中指定位置的元素。
intsize() 返回此列表中的元素数。
Object[]toArray() 以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。

2.1.2 LinkedList

底层使用链表实现。

public static void main(String[] args) {

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

    // 添加元素,使用add方法,add(类型由泛型决定)
    list.add("张三");
    list.add("李四");
    list.add("王五");

    // 遍历
    for(int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }
}

常用方法:与ArrayList基本相似。

特点:添加、修改、删除的性能高,查询的性能不高

2.1.3 Vector

底层和ArrayList一样使用数组实现,线程安全的。缺点是效率比较低。

public static void main(String[] args) {

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

    // 添加元素,使用add方法,add(类型由泛型决定)
    list.add("张三");
    list.add("李四");
    list.add("王五");

    // 遍历
    for(int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }
}

常用方法:与ArrayList基本相似。

2.1.4 区别
  1. ArrayList底层是用数组实现的,查询修改的效率比较快,增删的效率比较慢。

  2. LinkedList底层是通过双向链表实现的,增删的速度较快,查询修改的速度比较慢。

  3. Vector和ArrayList一样,都是通过数组实现的,但是Vector是线程安全的。

2.2 Set

存取无序的集合,元素不能重复。

保证元素唯一性需要让元素重写两个方法:一个是 hashCode(),另一个是 equals()。HashSet在存储元素的过程中首先会去调用元素的hashCode()值,看其哈希值与已经存入HashSet的元素的哈希值是否相同,如果不同 :就直接添加到集合;如果相同 :则继续调用元素的equals() 和哈希值相同的这些元素依次去比较。如果说有返回true的,那就重复不添加;如果说比较结果是false,那就是不重复就添加。

2.2.1 HashSet

无序,元素不能重复,允许存在一个null值。

public static void main(String[] args) {

    Set<String> set = new HashSet<>();

    set.add("a");
    set.add("a");
    set.add("b");
    set.add("c");
    set.add("a1");

    System.out.println(set); // [a1, a, b, c]与添加的顺序是不一致的,是无序的。并且添加两个"a",最后只打印一个出来。
}

常用方法:查看jdk文档。

2.2.2 LinkedHashSet

有序的set,元素不能重复,允许一个null存在。

public static void main(String[] args) {

    Set<String> set = new LinkedHashSet<>();

    set.add("a");
    set.add("b");
    set.add("c");
    set.add("a1");

    System.out.println(set); // [a, b, c, a1],顺序与添加的顺序一致。
}

常用方法:查看jdk文档。

2.2.3 TreeSet

自定义排序,元素不能重复,不允许null存在。

Set<Integer> set = new TreeSet();

set.add(5);
set.add(10);
set.add(13);
set.add(3);
set.add(2);
set.add(4);
set.add(18);
set.add(11);
set.add(9);

// 会发现,打印出来的元素从小到大排序了。
System.out.println(set); // [2, 3, 4, 5, 9, 10, 13, 14, 18]

TreeSet使用二叉树进行排序,存储规则:

  1. 第一个元素作为根节点。

  2. 从第二个元素开始,每个元素从根节点开始比较。

  • 比根节点大,就作为右子树;

  • 比根节点小,就作为左子树;

  • 与根节点相等,表示重复,不存储。

图解:

  1. 首先,将5作为根节点;

  2. 插入10,由于10大于5,作为5的右子树;

  3. 插入13,由于13大于5,进入右子树,13又大于10,作为10的右子树;

  4. 插入3,由于3小于5,作为5的左子树;

  5. 插入2,由于2小于5,进入左子树,2又小于3,作为3的左子树;

  6. 插入4,由于4小于5,进入左子树,4大于3,作为3的右子树;

  7. 插入18,由于18大于5,进入右子树,18又大于10,进入10的右子树,18又大于13,作为13的右子树;

  8. 插入11,由于11大于5,进入右子树,11又大于10,进入10的右子树,11小于13,作为13的左子树;

  9. 插入9,由于9大于5,进入右子树,9小于10,作为10的左子树。

  10. 最后,进行中序遍历(左根右:首先遍历左子树,然后访问根结点,最后遍历右子树),得到结果【2,3,4,5,9,10,11,13,18】。

接下来介绍TreeSet具体如何实现:

让元素所在的类实现Comparable接口,并重写CompareTo() 方法,并根据CompareTo()的返回值来进行添加元素。

根据compareTo返回值决定:

  1. 返回1,认为新插入的元素比上一个元素大,于是二叉树存储时,会存在根的右侧。

  2. 返回-1,认为新插入的元素比上一个元素小,于是二叉树存储时,会存在根的左侧。

  3. 返回0,表示重复,不存储。

// Integer源码
// 为什么TreeSet里面存储Integer数据的时候会默认升序,因为Integer重写了Comparable接口的compareTo方法
public final class Integer extends Number implements Comparable<Integer> {
    
    public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }

    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }
    
}

接下来通过案例分析TreeSet实现自定义排序的过程:

假设有学生类(姓名name,年龄age),现在有若干个学生对象,现在要按照年龄排序,放到容器中,我们就可以选择使用TreeSet解决。

// 学生类
public class Student implements Comparable{

    private String name;

    private Integer age;

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

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

    @Override
    public int compareTo(Object o) {
        Student student = (Student) o;
        return (this.age < student.age) ? -1 : ((this.age == student.age) ? 0 : 1);
    }
}
// 测试
public static void main(String[] args) {

    // 有三个学生对象
    Student student1 = new Student("张三", 18);
    Student student2 = new Student("李四", 20);
    Student student3 = new Student("王五", 19);

    // 把学生存入set
    Set<Student> students = new TreeSet<>();
    students.add(student1);
    students.add(student2);
    students.add(student3);

    // 遍历set
    for(Student student:students) {
        /*
           打印结果:按照年龄升序。
           Student{name='张三', age=18}
           Student{name='王五', age=19}
           Student{name='李四', age=20}
        */
        System.out.println(student);
    }
}
2.3 Map(字典)

Map用于保存具有映射关系的数据,因此Map集合里保存着两组值,一组值用于保存Map里的key,另外一组值用于保存Map里的value。key和value都可以是任何引用类型的数据。

Map的存储结构:

2.3.1 HashMap
  1. 无序,存储元素和取出元素的顺序有可能不一致;

  2. key不能重复,key允许是null;允许多个 null值和一个null键(key重复值会被覆盖)

  3. 不是线程安全的。

Map<String, Integer> map = new HashMap<>();

// Map存值使用put(key, value)方法
map.put("a1", 100);
map.put("b", 150);
map.put("a2", 200);
map.put("a2", 300); // key重复,会把前面的值覆盖

// Map取值使用get(key) 方法
System.out.println(map.get("a1")); // 100
System.out.println(map.get("a2")); // 300


// keySet()获取map里面的key集合
Set<String> keys = map.keySet();
for(String key:keys) {
    System.out.println("key: " + key + "   value:" + map.get(key)); // 打印的顺序和存数据的顺序可能是不一致的
}
2.3.2 TreeMap
  1. 可以按照key来做排序,默认按照 key 进行升序排序,

  2. key不能重复,key不允许为null;

  3. 不是线程安全的。

Map<String, Integer> map = new TreeMap<>();

map.put("a1", 100);
map.put("b", 150);
map.put("a2", 200);

Set<String> keys = map.keySet();
for(String key:keys) {
    System.out.println(key); // 打印顺序:a1,a2,b。
}
Map<String, Integer> map = new TreeMap<>(new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return o2.compareTo(o1);
    }
});

map.put("a1", 100);
map.put("b", 150);
map.put("a2", 200);
// map.put(null, 1); // 有异常,不允许键为null

Set<String> keys = map.keySet();
for(String key:keys) {
    System.out.println(key); // 打印顺序:b,a1,a2。打印顺序和上面相反了
}
2.3.3 Hashtable
  1. 无序;

  2. 不允许有任何的null键和null值;

  3. 是线程安全的。

Map<String, Integer> map = new Hashtable<>();

// 运行会出现异常:NullPointerException
map.put(null, 1);
map.put("a", null);
2.3.4 LinkedHashMap
  1. 有序的;

  2. key不能重复,key允许是null;允许一个null键和多个null值

  3. 不是线程安全的。

Map<String, Integer> map = new LinkedHashMap<>();

map.put("a1", 100);
map.put("b", 150);
map.put("a2", 200);

Set<String> keys = map.keySet();
for(String key:keys) {
    System.out.println(key); // 打印的顺序与存储的顺序一致
}

标签:map,set,java,String,元素,add,key,小结,07
From: https://blog.csdn.net/qq_40508161/article/details/142150319

相关文章

  • day4[大模型全链路开源开放体系学习小结]
    书生·浦语大模型全链路开源开放体系涵盖数据收集、标注、训练、微调、评测、部署等全链路,学习了解其技术发展、性能提升、模型架构、开源生态等。书生·浦语大模型(英文名INTurnLLM)多次开源,性能不断提升,达到国际先进水平,在推理能力、上下文记忆、自主规划等方面表现优异,可应用......
  • 计算机毕业设计 基于协同过滤算法的个性化音乐推荐系统 Java+SpringBoot+Vue 前后端分
    ......
  • web - JavaScript
    JavaScript1,JavaScript简介JavaScript是一门跨平台、面向对象的脚本语言,而Java语言也是跨平台的、面向对象的语言,只不过Java是编译语言,是需要编译成字节码文件才能运行的;JavaScript是脚本语言,不需要编译,由浏览器直接解析并执行。JavaScript是用来控制网页行为的,它能使......
  • Java8的Optional简介
    文章目录环境背景方法1:直接获取方法2:防御式检查方法3:Java8的Optional概述map()测试flatMap()测试总结参考注:本文主要参考了《Java8实战》这本书。环境Ubuntu22.04jdk-17.0.3.1(兼容Java8)背景现有Insurance、Car、Person类,定义如下:Insurance:publ......
  • 20240919_214407 切片小结 树的遍历 随手笔记
    切片小结步长如果是正值那么找到下标的对应的成员左边切一刀最终向右包抄取值步长如果是负值找到下标对应的成员右边切一刀最终向左边包抄取值认识库SciPy:SciPy是一个开源的Python算法库和数学工具包,用于数学、科学、工程领域。它基于NumPy,提供了大量的数学算法和......
  • java_day3_Scanner,顺序结构,选择结构(if,switch),循环结构(for,while),
    一、Scanner键盘录入:程序运行过程中,用户可以根据自己的需求输入参与运算的值实现键盘录入的步骤1、导包2、创建键盘录入对象3、调用方法实现键盘录入1)输入整数2)输入字符串publicclassScannerDemo1{publicstaticvoidmain(String[......
  • 6. 什么是MySQL的事务?如何在Java中使用Connection接口管理事务?
    事务(Transaction)是一组可以看作一个逻辑单元的操作,这组操作要么全部成功,要么全部失败。事务确保了数据库操作的原子性、一致性、隔离性和持久性,这些性质统称为ACID特性:原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不完成,不会出现部分完成的情况。如果事务中某个......
  • 7. 在Java中集合mysql如何执行一条简单的SELECT查询,并获取结果集?
    在Java中,使用JDBC(JavaDatabaseConnectivity)可以执行SQL查询,并获取结果集(ResultSet)。以下是执行一条简单的SELECT查询,并获取和处理结果集的详细步骤:1.导入必要的包首先,确保导入了必要的JDBC包。你需要导入以下包来进行数据库连接和操作:importjava.sql.Connection;imp......
  • JavaScript高级——内存溢出和内存泄漏
    1、闭包的缺点与解决方法(1)缺点:函数执行完后,函数内的局部变量没有释放,占用内存时间会变长。 容易造成内存泄漏。(2)解决:能不用闭包就不用。 及时释放。2、内存溢出①一种程序运行出现的错误②当程序需要的内存超过了剩余的内存时,就会出现内存溢出的错误3、内存泄......
  • Java Workbook和XSSWorkbook 处理Excel
    JavaWorkbook和XSSWorkbook是ApachePOI库中用于处理Excel文件的两个主要类。ApachePOI是一个流行的JavaAPI,用于读写MicrosoftOffice格式的文档,特别是Excel(.xls和.xlsx)文件。下面将通过一些示例来展示如何使用这两个类处理Excel文件。使用HSSFWorkbook(处理......