首页 > 编程语言 >java基础2024(5.集合)

java基础2024(5.集合)

时间:2024-10-23 19:46:34浏览次数:3  
标签:map set java HashMap HashSet 元素 接口 2024 集合

集合(Collection)是一组用于存储和操作对象的数据结构。Java集合框架(Java Collections Framework, JCF)提供了一个统一的架构,用于表示和操作集合,它包含了一系列接口、实现类以及算法。

Collection接口

Collection接口是集合框架的根接口,它扩展了Iterable接口,定义了所有集合类型共有的方法。Collection接口本身并不提供直接的实现,而是作为其他更具体的集合接口(如List、Set和Queue)和类的超接口。以下是Collection接口的详细介绍:

List

List接口继承自Collection接口。List接口表示一个有序的集合,可以包含重复的元素,并且每个元素都有一个索引位置,可以通过这个索引来访问元素。

List接口的主要特点:

1. 有序性:List中的元素按照特定的顺序排列,这个顺序可以是元素插入的顺序,也可以是通过其他方式指定的顺序。

2. 可重复性:List允许包含重复的元素。

3. 有索引:List中的每个元素都可以通过索引来访问,索引从0开始。

List集合常用方法
void add(int index, E element)在指定索引处插入指定的元素
int indexOf(Object o)返回列表中第一次出现的指定元素的索引,如果列表不包含此元素,则返回-1
boolean addAll(Collection<? extends E> c)继承自Collection接口,将指定集合中的所有元素追加到列表的末尾
Object[] toArray()返回一个包含列表中所有元素的数组。
E remove(int index)移除列表中指定位置的元素
<T> T[] toArray(T[] a)返回一个包含列表中所有元素的数组,其运行时类型是指定数组的运行时类型。
E set(int index, E element)用指定的元素替换列表中指定位置的元素。

List接口的实现类:

ArrayList

ArrayList是基于动态实现的数组,当你使用无参构造函数ArrayList()创建一个空ArrayList对象时,它的底层数组长度为0,当你添加第一个元素是,数组容量会变为10,当数组容量不够时,其会将当前容量增加1.5倍,这个过程被称为扩容

如何创建ArrayList

ArrayList<String> list = new ArrayList<>();

一些方法的实例:

如果删除的不是最后一个元素,ArrayList 会将删除位置之后的元素向前移动,以填补空出来的位置。

ArrayList优点:实现了可调整大小的数组。允许包含重复的元素和null值。它是非同步的,适用于查找和更新操作。

LinkedList

LinkedList和ArrayList一样实现了List接口,但它在内部数据结构和性能存和ArrayList存在一些差异,ArrayList是基于动态数组实现的,而LinkedList是基于双向链表实现的,每个元素都包含数据和两个指针,分别指向前一个和后一个元素。

就像这样:

                         插入前                                                              插入后

双向链表在任何位置添加或删除元素都非常高效,因为只需要改变指针,时间复杂度为 O(1)。

创建LinkedList实例:

LinkedList<Integer> list = new LinkedList<>();

一些方法的示例:

ArrayList适用于需要频繁随机访问元素的场景和元素数量相对稳定,不需要频繁插入和删除的场景。

LinkedList适用于需要频繁插入和删除元素的场景和不需要频繁随机访问元素的场景。

*Iterator接口(不属于Collection)

Iterator接口是集合框架的一部分,它提供了一种遍历集合(例如 List、Set或 Map 的集合视图)中元素的方法,而不需要暴露其底层表示。Iterator接口位于 java.util包中。

boolean hasNext():如果迭代器在遍历集合的过程中还有更多的元素,则返回 true,如果所有元素都已经遍历完毕,则返回 false。

next():返回迭代器中的下一个元素。

remove():从迭代器指向的集合中移除迭代器返回的最后一个元素。每次调用 next()后只能调用一次 remove(),否则会抛出异常。

Iterator例子:

public class Main {
    public static void main(String[] args) {
        // 创建一个 List
        List<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");

        // 获取 Iterator
        Iterator<String> iterator = list.iterator();

        // 使用 Iterator 遍历 List
        while (iterator.hasNext()) {
            String fruit = iterator.next();
            System.out.println(fruit);
            
            // 如果需要,可以移除元素
            if (fruit.equals("Banana")) {
                iterator.remove();
            }
        }

        // 打印修改后的 List
        System.out.println(list);
    }
}

在这个示例中,我们创建了一个 ArrayList,并使用 iterator() 方法获取了一个 Iterator。然后,我们使用 hasNext() 和 next() 方法遍历列表中的每个元素,并打印出来。如果元素是 Banana,我们使用 remove() 方法将其从列表中移除。

Iterator接口是 Java 集合框架中的基础,它为遍历集合提供了一个通用的机制。

*foreach循环

Java 5 引入了 for-each 循环,它在内部使用了 Iterator,从而简化了集合的遍历。

foreach 循环的基本语法:

for (声明语句 : 表达式) {
    // 循环体
}

声明语句:用于声明一个局部变量,该变量的类型必须与数组或集合中元素的类型兼容。在每次迭代中,foreach 循环会将数组或集合中的下一个元素赋值给这个变量。
表达式:是一个数组或实现了 Iterable 接口的集合。

下面是使用 foreach循环遍历数组和集合的示例:

遍历数组:

int[] numbers = {1, 2, 3, 4, 5};

for (int number : numbers) {
    System.out.println(number);
}

遍历集合:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

for (String name : names) {
    System.out.println(name);
}

特点:

简洁:不需要显式地创建迭代器或处理索引。
安全:不会出现数组越界异常,因为 foreach 循环会自动处理边界。
不可变:在foreach 循环中不能直接修改集合或数组的内容,因为它每次迭代都只是获取元素的副本。如果需要修改元素,需要使用普通的 for 循环或迭代器。

foreach 循环的引入大大简化了遍历集合和数组的代码,使其更加直观和易于维护。

Set

Set 接口是 Java 集合框架中的一个根接口,它继承自 Collection 接口。Set 接口的特点是其元素是无序的,并且不包含任何重复的元素

Set接口主要有两个实现类,分别是HashSet和TreeSet。

HashSet

HashSet的特点:

唯一性:HashSet 不允许存储重复的元素。
无序性:HashSet不保证元素的顺序,即元素插入和遍历的顺序可能不同。
基于 HashMap 实现:HashSet 的实现是基于 HashMap,每个元素实际上是 HashMap 的一个键。

创建一个HashSet:

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

主要方法

add(E e):添加元素到 HashSet中。
(Object o):从HashSet中移除指定的元素。
contains(Object o):检查 HashSet是否包含指定的元素。
size():返回 HashSet中的元素数量。
clear():移除 HashSet中的所有元素。

下面是使用hashset的实例:

public class Example {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("Apple");
        set.add("Banana");
        set.add("Cherry");
        // 重复添加不会成功
        set.add("Apple");

        System.out.println(set); // 输出可能为 [Apple, Banana, Cherry] 或其他顺序
        System.out.println(set.contains("Banana")); // 输出 true
        System.out.println(set.size()); // 输出 3
    }
}

当你需要存储一组唯一元素,并且对元素的顺序没有要求时。
当你需要快速检索元素是否存在时,因为 HashSet的查找效率很高。

(在这些场景下使用HashSet比较好)

TreeSet

TreeSet是 Java 集合框架中的一个类,它实现了 NavigableSet接口,并且底层是基于红黑树实现的。TreeSet 用于存储一组有序的元素,以下是 TreeSet的详细介绍:

*红黑树:红黑树确保没有一条路径会比其他路径长出两倍,因而是近似平衡的,从而保证了树的高度大约是 log(n),其中 n 是树中节点的数量。这使得红黑树的查找、插入和删除操作的时间复杂度最坏情况下为 O(log n)。

特点:

1. 有序集合:TreeSet 中的元素按照自然顺序或者指定的比较器进行排序。这意味着元素是以升序排列的。

2. 唯一性:与 HashSet一样,TreeSet 不允许存储重复的元素。

方法

add(E e):添加元素到 TreeSet 中。
remove(Object o):从 TreeSet 中移除指定的元素。
contains(Object o):检查 TreeSet是否包含指定的元素。
size():返回 TreeSet 中的元素数量。
clear():移除 TreeSet 中的所有元素。
isEmpty():检查 TreeSet 是否为空。
first():返回 TreeSet 中最小的元素。
last():返回 TreeSet中最大的元素。

示例:

public class Example {
    public static void main(String[] args) {
        TreeSet<Integer> set = new TreeSet<>();
        set.add(10);
        set.add(5);
        set.add(20);
        // 重复添加不会成功
        set.add(10);

        System.out.println(set); // 输出 [5, 10, 20]
        System.out.println(set.first()); // 输出 5
        System.out.println(set.last()); // 输出 20
        System.out.println(set.size()); // 输出 3

        // 查找并移除元素
        set.remove(10);
        System.out.println(set); // 输出 [5, 20]
    }
}

使用场景:

需要存储一组唯一且有序的元素时。
当你需要按照元素的自然顺序或者自定义顺序遍历元素时。
当你需要高效地进行范围查询时。

TreeSet 的操作通常比 HashSet 的操作要慢,因为红黑树的操作复杂度是 O(log n),而 HashSet 的操作复杂度通常是 O(1)。

Map

map 是一种抽象数据类型,用于存储键值对。map 接口定义了一系列操作,这些操作允许用户根据键来存储、检索、更新和删除元素。

键(Key):每个键是唯一的,用于在map中标识一个值。
值(Value):与键相关联的数据。
键值对:键和值的组合,是map中存储的基本单元。

特点

键的唯一性:在 map 中,每个键只能对应一个值,因此键必须是唯一的。
无序性:标准的 map接口不保证元素的顺序。不过,有些实现提供了有序 map,如基于红黑树或平衡二叉搜索树的实现。
键的比较:map 通常要求键类型是可以比较的,以便能够确定键的唯一性。

HashMap

 HashMap是基于哈希表实现的映射接口的一个实现,它存储键值对,并允许快速检索。HashMap使用加载因子来确定何时进行扩容。当哈希桶中的元素数量达到当前容量与加载因子的乘积时,HashMap会进行扩容操作,通常是扩大为原来容量的两倍

特点

动态调整大小:HashMap 能够根据存储的元素数量动态调整其内部数组的大小,这个过程称为rehashing。

HashMap():创建一个默认初始容量(16)和默认加载因子(0.75)的空 HashMap。
HashMap(int initialCapacity):创建一个指定初始容量的空 HashMap。

创建一个HashMap:

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

常用方法:

put(K key, V value):将指定的键值对插入到 HashMap 中。
get(Object key):返回指定键所映射的值,如果找不到则返回 null。
remove(Object key):移除键对应的键值对,并返回被移除的值。
containsKey(Object key):检查 HashMap是否包含指定的键。
containsValue(Object value):检查 HashMap是否包含指定的值。
size():返回 HashMap中键值对的数量。

示例:

public class HashMapExample {
    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();
        
        // 插入键值对
        map.put("Apple", 1);
        map.put("Banana", 2);
        
        // 获取值
        int value = map.get("Apple"); // 返回 1
        
        // 删除键值对
        map.remove("Banana");
        
        // 检查键是否存在
        boolean contains = map.containsKey("Apple"); // 返回 true
        
        // 获取大小
        int size = map.size(); // 返回 1
        
        // 清空 HashMap
        map.clear();
    }
}

插入、删除和检索操作的平均时间复杂度是 O(1),在最坏情况下会退化为 O(n)。

*如果哈希桶的索引位置上有多个键值对,这些键值对将以链表的形式存储。在 Java 8 及以上版本中,当链表长度超过一定阈值时,链表会转换为红黑树,以优化查找性能。

TreeMap

TreeMap是 Java 中的一个集合类,它实现了 SortedMap接口,可以用来存储键值对,并且可以根据键的自然顺序或者通过构造器传入的 Comparator来排序。

特点:底层使用红黑树数据结构,保证了元素的有序性和较高的操作效率。

TreeMap():创建一个基于键的自然排序的空 TreeMap。
TreeMap(Comparator<? super K> comparator):创建一个根据指定 Comparator 排序的空 TreeMap。

创建一个TreeMap:

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

常用方法

put(K key, V value):将指定的键值对插入到 TreeMap 中。
get(Object key):返回指定键所映射的值,如果找不到则返回 null。
remove(Object key):移除键对应的键值对,并返回被移除的值。
containsKey(Object key):检查 TreeMap 是否包含指定的键。
containsValue(Object value):检查 TreeMap是否包含指定的值。
firstKey():返回 TreeMap 中第一个(最低)键。
lastKey():返回 TreeMap 中最后一个(最高)键。

示例:

public class TreeMapExample {
    public static void main(String[] args) {
        TreeMap<String, Integer> map = new TreeMap<>();

        // 插入键值对
        map.put("Apple", 1);
        map.put("Banana", 2);
        map.put("Cherry", 3);

        // 获取值
        int value = map.get("Apple"); // 返回 1

        // 删除键值对
        map.remove("Banana");

        // 检查键是否存在
        boolean contains = map.containsKey("Apple"); // 返回 true

        // 获取第一个键
        String firstKey = map.firstKey(); // 返回 "Apple"

        // 获取最后一个键
        String lastKey = map.lastKey(); // 返回 "Cherry"


        // 遍历 TreeMap
        for (String key : map.keySet()) {
            System.out.println(key + " -> " + map.get(key));
        }

    }
}

TreeMap维护了元素的顺序,所以在需要对键进行排序的场景下,TreeMap是一个很好的选择。

Lambda

Lambda 表达式是 Java 8 中引入的一个重要特性,它提供了一种简洁的语法来表示匿名函数,允许开发者更加灵活地处理函数式接口(即只包含一个抽象方法的接口)

Lambda 表达式的语法基本形式如下:

(parameters) -> expression
或
(parameters) ->{ statements; }

parameters 是参数列表,expression 或 { statements } 是Lambda 表达式的主体。如果只有一个参数,可以省略括号;如果没有参数,也需要空括号。

如果参数类型可以由编译器推断出来,那么参数的类型也可以省略:

(parameter) -> { body; }

如果只有一个参数,并且它的类型可以被推断出来,那么圆括号也可以省略:

parameter -> { body; }

Lambda 表达式可以访问以下作用域内的变量:

局部变量:Lambda 表达式可以访问局部变量,但这些变量必须是最终变量(即必须是不可变的)。
成员变量:Lambda 表达式可以访问或修改外围类的成员变量。
静态变量:Lambda 表达式可以访问静态变量。

方法引用

有时候 Lambda 表达式只是调用一个已存在的方法,在这种情况下,可以使用方法引用来进一步简化代码。方法引用的语法是:

 
Class::methodName
 

例如:

List<String> names = Arrays.asList("a", "B", "C");
names.forEach(System.out::println);

Lambda 表达式是 Java 8 函数式编程的基础,它简化了代码,并使 Java 更具表现力。

持续更新中

标签:map,set,java,HashMap,HashSet,元素,接口,2024,集合
From: https://blog.csdn.net/2301_81490350/article/details/143187885

相关文章

  • javascript数组splice和slice介绍
    一splice1.概述splice是JavaScript数组对象的一个方法,用于改变原数组的内容。它可以添加、删除或替换数组中的元素。2.语法array.splice(start,deleteCount,item1,item2,...)start:需要改变的数组的起始索引。如果是负数,则表示从数组末尾开始计数。de......
  • 挑战中,Java面试题复习第5天,坚持就是胜利。
     ......
  • 【Azure Developer】使用JavaScript通过SDK进行monitor-query的client认证报错问题
    问题描述使用JavaScript通过SDK进行monitor-query的client初始化时候,需要进行认证时报错AADSTS90002。代码如下:constcredential=newDefaultAzureCredential();constlogsQueryClient=newLogsQueryClient(credential,{endpoint:"https://api.loganalytics.azur......
  • java操作word
    word基础docx和doc的区别doc是微软特有的一种文件格式,其本质是一个二进制的文件docx是基于XML的开放文档格式,是OfficeOpenXml的一部分。docx组成部分一个完整的docx文档由4部分构成。即_rels、docProps、word和[Content_Types].xmlword文件夹定义了文档的内容......
  • 0基础学java之Day13
    static理解:静态的作用:1.修饰属性类加载到方法区时,JVM会扫描该类的所有属性并把静态属性加载到静态区中,静态属性属于类属性,该类所有的对象都共享该属性静态属性直到项目结束时才会被回收2.修饰方法属于类方法,直接用类名调用应用场景:工具类3.修饰代码块静态代......
  • 如何使用Java设计一个RDB格式的Redis
    RDB的使用场景数据备份:RDB适合定期备份Redis中的数据,帮助在系统崩溃或意外情况下恢复数据。冷备份:在不需要频繁写入数据的场景(如数据分析、报告生成),RDB可以作为冷备份使用。启动时数据加载:在系统启动时,通过加载RDB文件快速恢复数据,提高启动速度。数据迁移:使用RD......
  • 如何使用Java设计一个AOF格式的Redis
    AOF的使用场景高数据安全性需求:适用于对数据一致性要求高的应用场景,如金融交易系统、订单处理系统等。频繁写入操作:AOF适合频繁进行写操作的场景,因为它记录每个写命令,可以有效恢复最新数据。实时数据恢复:当系统崩溃或发生故障时,AOF能快速恢复数据,适合需要高可用性......
  • 2024/10/23日 日志--》关于Maven的基础学习--2 坐标与依赖范围
    对Maven的学习即将步入卫生,下面是Maven中的坐标和依赖范围的简单笔记点击查看代码--Maven坐标详解--·什么是坐标?---》Maven中的坐标是资源的唯一标识---》使用坐标来定义项目或引入项目中需要的依赖--·Maven坐标的主要组成---》groupld:定义当前Maven项目隶......
  • 20222404 2024-2025-1《网络与系统攻防》 实验二
    1.实验内容(一)本周课程内容了解后门概念,了解后门案例,后门会对系统安全造成的影响。对后门技术进行普及,包括各种进程隐藏技术。了解netcat、meterpreter,veil等常见工具。进一步学习shellcode注入的逻辑和多种情况。(二)问题回答(1)例举你能想到的一个后门进入到你系统中的可能......
  • Adobe AN软件简介、下载与安装步骤【2024】
    目录一、AdobeAN软件简介1.1产品概述1.2主要功能1.3系统要求二、下载三、安装步骤3.1Windows系统安装3.2macOS系统安装3.3后续操作一、AdobeAN软件简介1.1产品概述AdobeAN,全称AdobeAnimate,是AdobeSystems公司开发的一款功能强大的多媒体创作和电脑动......