Java集合探秘:从单列到双列,探索全部集合框架的奥秘

简介: Java集合探秘:从单列到双列,探索全部集合框架的奥秘

集合的概念

在计算机科学中,集合是一组元素的容器,这些元素可以是相同类型的对象,也可以是不同类型的对象。Java集合框架提供了一系列接口和类,用于处理和操作这些集合。

集合框架的层次结构

Java集合框架包括多个接口和类,它们按照一定的层次结构进行组织。以下是集合框架的主要接口:

单列集合

Collection接口

  • 是所有集合类的根接口,它定义了一些基本的集合操作方法,如添加、删除、遍历等。
  • 常用方法
  • add(E e):将给定的对象添加到集合中。
  • clear():清空集合中的所有元素。
  • remove(E e):从集合中删除给定的对象。
  • contains(E e):判断集合中是否包含给定的对象。
  • isEmpty():判断集合是否为空。
  • size():返回集合中元素的个数。
  • toArray():将集合中的元素存储到数组中
import java.util.*;
public class CollectionDemo {
    public static void main(String[] args) {
        // 创建一个ArrayList来存放整数
        List<Integer> numbers = new ArrayList<>();
        // 添加元素到集合
        numbers.add(10);
        numbers.add(20);
        numbers.add(30);
        // 判断集合是否为空
        boolean isEmpty = numbers.isEmpty();
        System.out.println("集合是否为空:" + isEmpty);
        // 获取集合中元素的个数
        int size = numbers.size();
        System.out.println("集合中元素的个数:" + size);
        // 从集合中删除元素
        numbers.remove(Integer.valueOf(20));
    }
}

List接口

  • 是有序的集合,允许重复元素。常见的实现类有ArrayList、LinkedList和Vector。
  • 常用的List集合实现类:ArrayList和LinkedList

ArrayList
  • ArrayList是一个基于数组实现的List集合。它具有以下特点:
  • 查询效率高:由于使用数组存储元素,可以通过索引直接访问元素,查询效率很高。
  • 添加、删除效率较低:在添加和删除元素时,可能需要移动数组中的其他元素,导致效率相对较低。
  • 底层实现:底层使用Object[]数组存储元素。
ArrayList()
ArrayList(Collection<? extends E> c)
  • List集合常用方法
  • 在使用List集合时,我们常用的方法包括:
  • public boolean add(E e): 将给定的对象添加到集合中。
  • public void clear(): 清空集合中的所有元素。
  • public boolean remove(E e): 从集合中删除给定的对象。
  • public boolean contains(E e): 判断集合是否包含给定的对象。
  • public boolean isEmpty(): 判断集合是否为空。
  • public int size(): 返回集合中元素的个数。
  • public Object[] toArray(): 将集合中的元素存储到数组中。
  • public void add(int index, E element): 将指定的元素添加到集合的指定位置。
  • public E get(int index): 返回集合中指定位置的元素。
  • public E remove(int index): 移除集合中指定位置的元素,并返回被移除的元素。
  • public E set(int index, E element): 用指定的元素替换集合中指定位置的元素,并返回替换前的元素。
import java.util.ArrayList;
import java.util.List;
public class ListMethodsExample {
    public static void main(String[] args) {
        // 创建一个使用ArrayList的List
        List<String> myList = new ArrayList<>();
        // 向List中添加元素
        myList.add("苹果");
        myList.add("香蕉");
        myList.add("橙子");
        // 显示List内容
        System.out.println("原始列表: " + myList);
        // 在特定索引位置添加元素
        myList.add(1, "葡萄");
        System.out.println("在索引1添加'葡萄'后的列表: " + myList);
        // 获取特定索引位置的元素
        String 在索引2的水果 = myList.get(2);
        System.out.println("索引2的元素: " + 在索引2的水果);
        // 移除特定索引位置的元素
        String 移除的元素 = myList.remove(0);
        System.out.println("移除索引0的元素: " + 移除的元素);
        System.out.println("移除元素后的列表: " + myList);
        // 替换特定索引位置的元素
        String 替换前的元素 = myList.set(1, "菠萝");
        System.out.println("替换索引1的元素: " + 替换前的元素);
        System.out.println("替换元素后的列表: " + myList);
        // 检查列表是否包含特定元素
        boolean 包含橙子 = myList.contains("橙子");
        System.out.println("列表是否包含'橙子': " + 包含橙子);
        // 检查列表是否为空
        boolean 是否为空 = myList.isEmpty();
        System.out.println("列表是否为空? " + 是否为空);
        // 获取列表的大小
        int 列表大小 = myList.size();
        System.out.println("列表的大小: " + 列表大小);
        // 将列表转换为数组
        Object[] 数组 = myList.toArray();
        System.out.print("从列表转换的数组: ");
        for (Object item : 数组) {
            System.out.print(item + " ");
        }
    }
}
LinkedList

LinkedList是一个基于双向链表实现的List集合。它具有以下特点:

  • 查询效率较低:由于需要遍历链表才能访问元素,查询效率较低。
  • 添加、删除效率较高:在链表中添加和删除元素的效率很高。
  • 底层实现:底层使用双向链表存储元素。

构造方法

//创建一个空列表
LinkedList();
//创建一个包含指定集合元素的列表,按集合的迭代器返回顺序添加。
LinkedList(Collection<? extends E> c);

常用方法

  • void addFirst(E e): 在列表的开始处插入指定元素。
  • void addLast(E e): 在列表的末尾插入指定元素。
  • E getFirst(): 返回列表中的第一个元素。
  • E getLast(): 返回列表中的最后一个元素。
  • E removeFirst(): 移除并返回列表中的第一个元素。
  • E removeLast(): 移除并返回列表中的最后一个元素。
  • void push(E e): 将元素推入到由该列表表示的堆栈上。
  • E pollFirst(): 检索并移除列表的第一个元素,若列表为空则返回 null
  • E pollLast(): 检索并移除列表的最后一个元素,若列表为空则返回 null
import java.util.LinkedList;
public class LinkedListExample {
    public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<>();
        // 添加元素
        linkedList.addFirst("Apple");
        linkedList.addLast("Banana");
        // 获取第一个和最后一个元素
        String firstElement = linkedList.getFirst();
        String lastElement = linkedList.getLast();
        System.out.println("First Element: " + firstElement);
        System.out.println("Last Element: " + lastElement);
        // 移除并返回第一个和最后一个元素
        String removedFirstElement = linkedList.removeFirst();
        String removedLastElement = linkedList.removeLast();
        System.out.println("Removed First Element: " + removedFirstElement);
        System.out.println("Removed Last Element: " + removedLastElement);
        // 将元素推入堆栈
        linkedList.push("Cherry");
        // 检索并移除第一个和最后一个元素
        String polledFirstElement = linkedList.pollFirst();
        String polledLastElement = linkedList.pollLast();
        System.out.println("Polled First Element: " + polledFirstElement);
        System.out.println("Polled Last Element: " + polledLastElement);
    }
}

Set接口

  • 不允许重复元素的集合。常见的实现类有HashSet、LinkedHashSet。

HashSet
  • 无序性:HashSet 中的元素是无序的,不能保证元素的顺序。
  • 不允许重复:HashSet 中的元素不允许重复,相同的元素只会保存一份。
  • 高效的添加、查找和删除操作: 哈希表的底层实现使得添加、查找和删除元素的操作都具有很高的效率。

构造方法

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

示例

Set<String> hashSet = new HashSet<>();
hashSet.add("apple");
hashSet.add("banana");
hashSet.add("apple"); // 不会重复添加
System.out.println(hashSet); // 输出:[banana, apple]

HashSetSet接口的一个实现类,它是一个无序的、不重复的集合。其底层实现是基于HashMap,将元素作为键存储在HashMap中。

LinkedHashSet
  • 有序性:LinkedHashSet 中的元素是有序的,它会根据元素的插入顺序维护一个链表,从而保持插入顺序。
  • 不允许重复: 同样,LinkedHashSet 中的元素不允许重复。

构造方法

LinkedHashSet<E> linkedHashSet = new LinkedHashSet<>();

示例

Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("apple");
linkedHashSet.add("banana");
linkedHashSet.add("apple"); // 不会重复添加
System.out.println(linkedHashSet); // 输出:[apple, banana]

双列集合

Map接口

  • Map 接口定义了键和值之间映射的规范,它有两个泛型参数:K 表示键的类型,V 表示值的类型。
  • 实现类:HashMap 和 LinkedHashMap

HashMap
  • 基于哈希表实现的映射,具有高效的添加、查找和删除操作。它的键不允许重复,值可以重复。如果存放的元素中键值相同,后面的值会覆盖前面的值。键和值都可以为 null,但一个键只能对应一个 null 值。

构造方法

HashMap<K, V> hashMap = new HashMap<>();

常用方法

  • V put(K key, V value): 将指定的值与键关联。
  • V get(Object key): 返回指定键映射的值,如果键不存在则返回 null
  • V remove(Object key): 从映射中移除指定键的映射。
  • V replace(K key, V value): 仅当键当前映射到某一值时,替换指定键的值。
  • int size(): 返回键值对的数目。
HashMap<String, Integer> hashMap = new HashMap<>();
// 添加键值对
hashMap.put("apple", 3);
hashMap.put("banana", 2);
hashMap.put("orange", 4);
// 获取值
int value = hashMap.get("apple");
// 移除键值对
hashMap.remove("banana");
// 替换值
hashMap.replace("orange", 5);
// 获取键值对数目
int size = hashMap.size();

集合遍历

HashMap<String, Integer> hashMap = new HashMap<>();
// 遍历所有的键
Set<String> keys = hashMap.keySet();
for (String key : keys) {
    Integer value = hashMap.get(key);
}
// 获取所有的值
Collection<Integer> values = hashMap.values();
// 遍历所有的键值对
Set<Map.Entry<String, Integer>> entries = hashMap.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
    String key = entry.getKey();
    Integer value = entry.getValue();
}
LinkedHashMap
  • HashMap 的基础上增加了维护插入顺序的功能,保持键值对的插入顺序。其他特性与 HashMap 类似。

补充知识

迭代器

迭代器是用于遍历集合中元素的工具。通过iterator()方法可以获得一个迭代器对象,接着使用迭代器的方法来遍历集合。主要的迭代器接口是Iterator,其中包括了hasNext()next()remove()方法。

迭代器的原理

迭代器首先通过hasNext()方法判断集合中是否还有下一个元素,然后通过next()方法获取下一个元素的值。迭代器在遍历时会自动将索引指向下一个元素。

增强for循环

增强for循环是一种简化遍历集合或数组的方式。它可以直接在循环中获取每个元素,而不需要使用索引。需要注意的是,增强for循环不能用于删除元素,如果需要在遍历时删除元素,应该使用迭代器的方式。

// 使用迭代器遍历集合并输出元素
        System.out.print("集合中的元素:");
        Iterator<Integer> iterator = numbers.iterator();
        while (iterator.hasNext()) {
            int number = iterator.next();
            System.out.print(number + " ");
        }
        System.out.println();
        // 使用增强for循环遍历集合并输出元素
        System.out.print("使用增强for循环遍历集合:");
        for (int num : numbers) {
            System.out.print(num + " ");
        }
        System.out.println();

泛型

泛型的最大好处是在编译期间捕获类型错误,从而避免在运行时出现异常。通过在代码中约定数据类型,编译器可以检查数据类型的匹配性,确保我们不会错误地使用错误的数据类型。这大大提高了代码的健壮性和可维护性。

1.泛型的使用场景

1.1 泛型类

可以在类的声明中使用泛型,以便在使用该类时指定数据类型。这使得类可以在不同的上下文中适用于不同的数据类型。

public class GenericClass<T> {
    private T data;
    public GenericClass(T data) {
        this.data = data;
    }
    public T getData() {
        return data;
    }
}

1.2. 泛型方法

可以在方法中使用泛型,以便在方法调用时指定数据类型。这样,方法可以适用于不同类型的参数。

a. 类已经添加了泛型,方法参数可以直接使用:

public class GenericMethodClass<M> {
    void show(M m) {
        System.out.println(m);
    }
}

b. 类未添加泛型,方法参数需要在返回值前添加泛型:

public class GenericMethodClass2 {
    public <M> void show(M m) {
        System.out.println(m);
    }
}

1.3. 泛型接口

接口也可以使用泛型,实现类可以确定泛型的具体类型。

a. 接口的实现类确定泛型的类型:

public class InterfaceImpl implements MyInterface<String> {
    @Override
    public void show(String s) {
        System.out.println(s);
    }
}

b. 接口的实现类继续使用泛型,实例化时确定泛型的类型:

public class InterfaceImpl2<E> implements MyInterface<E> {
    @Override
    public void show(E e) {
        System.out.println(e);
    }
}

2.泛型通配符

泛型通配符用于处理不同泛型类型之间的关系。在Java中,通配符有两种使用方式:? extends T? super T

  • ? extends T:表示该类型应为指定类型T或其子类。这被称为上限通配符。
  • ? super T:表示该类型应为指定类型T或其父类。这被称为下限通配符。
相关文章
|
4月前
|
Java 数据库
在Java中使用Seata框架实现分布式事务的详细步骤
通过以上步骤,利用 Seata 框架可以实现较为简单的分布式事务处理。在实际应用中,还需要根据具体业务需求进行更详细的配置和处理。同时,要注意处理各种异常情况,以确保分布式事务的正确执行。
|
4月前
|
消息中间件 Java Kafka
在Java中实现分布式事务的常用框架和方法
总之,选择合适的分布式事务框架和方法需要综合考虑业务需求、性能、复杂度等因素。不同的框架和方法都有其特点和适用场景,需要根据具体情况进行评估和选择。同时,随着技术的不断发展,分布式事务的解决方案也在不断更新和完善,以更好地满足业务的需求。你还可以进一步深入研究和了解这些框架和方法,以便在实际应用中更好地实现分布式事务管理。
|
3月前
|
存储 安全 Java
Java 集合框架中的老炮与新秀:HashTable 和 HashMap 谁更胜一筹?
嗨,大家好,我是技术伙伴小米。今天通过讲故事的方式,详细介绍 Java 中 HashMap 和 HashTable 的区别。从版本、线程安全、null 值支持、性能及迭代器行为等方面对比,帮助你轻松应对面试中的经典问题。HashMap 更高效灵活,适合单线程或需手动处理线程安全的场景;HashTable 较古老,线程安全但性能不佳。现代项目推荐使用 ConcurrentHashMap。关注我的公众号“软件求生”,获取更多技术干货!
61 3
|
1月前
|
存储 缓存 Java
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
116 3
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
|
8天前
|
存储 监控 数据可视化
SaaS云计算技术的智慧工地源码,基于Java+Spring Cloud框架开发
智慧工地源码基于微服务+Java+Spring Cloud +UniApp +MySql架构,利用传感器、监控摄像头、AI、大数据等技术,实现施工现场的实时监测、数据分析与智能决策。平台涵盖人员、车辆、视频监控、施工质量、设备、环境和能耗管理七大维度,提供可视化管理、智能化报警、移动智能办公及分布计算存储等功能,全面提升工地的安全性、效率和质量。
|
2月前
|
并行计算 算法 Java
Java中的Fork/Join框架详解
Fork/Join框架是Java并行计算的强大工具,尤其适用于需要将任务分解为子任务的场景。通过正确使用Fork/Join框架,可以显著提升应用程序的性能和响应速度。在实际应用中,应结合具体需求选择合适的任务拆分策略,以最大化并行计算的效率。
66 23
|
3月前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
76 5
|
4月前
|
存储 缓存 安全
Java 集合框架优化:从基础到高级应用
《Java集合框架优化:从基础到高级应用》深入解析Java集合框架的核心原理与优化技巧,涵盖列表、集合、映射等常用数据结构,结合实际案例,指导开发者高效使用和优化Java集合。
85 4
|
4月前
|
开发框架 Java 关系型数据库
Java哪个框架适合开发API接口?
在快速发展的软件开发领域,API接口连接了不同的系统和服务。Java作为成熟的编程语言,其生态系统中出现了许多API开发框架。Magic-API因其独特优势和强大功能,成为Java开发者优选的API开发框架。本文将从核心优势、实际应用价值及未来展望等方面,深入探讨Magic-API为何值得选择。
169 2
|
4月前
|
前端开发 Java 数据库连接
你不可不知道的JAVA EE 框架有哪些?
本文介绍了框架的基本概念及其在编程领域的应用,强调了软件框架作为通用、可复用的软件环境的重要性。文章分析了早期Java EE开发中使用JSP+Servlet技术的弊端,包括可维护性差和代码重用性低等问题,并阐述了使用框架的优势,如提高开发效率、增强代码规范性和可维护性及提升软件性能。最后,文中详细描述了几种主流的Java EE框架,包括Spring、Spring MVC、MyBatis、Hibernate和Struts 2,这些框架通过提供强大的功能和支持,显著提升了Java EE应用的开发效率和稳定性。
328 1

热门文章

最新文章