【JAVA】part5-Java集合

Java 集合

Java集合概述

  • Java数组的局限性

    • 数组初始化后大小不可变;
    • 数组只能按索引顺序存取。
  • Java的java.util包主要提供了以下三种类型的集合:

    • List:一种有序列表的集合,例如,按索引排列的Student的List;
    • Set:一种保证没有重复元素的集合,例如,所有无重复名称的Student的Set;
    • Map:一种通过键值(key-value)查找的映射表集合,例如,根据Student的name查找对应Student的Map。
  • Java集合类:Collection,,它是除Map外所有其他集合类的根接口。

  • Java集合的设计特点

    • 一是实现了接口和实现类相分离
      例如,有序表的接口是List,具体的实现类有ArrayList,LinkedList等
    • 二是支持泛型
      我们可以限制在一个集合中只能放入同一种数据类型的元素,例如:List list = new ArrayList<>(); // 只能放入String类型
  • Java集合的访问

    Java访问集合总是通过统一的方式------迭代器(Iterator)来实现,它最明显的好处在于无需知道集合内部元素是按什么方式存储的。

使用List

ListIntro.java
ArrayList API

在Java中,List是一个接口,它继承自Collection接口,并表示一个有序的集合。List可以包含重复的元素,并且每个元素都有其索引。List接口的两个常用实现类是ArrayListLinkedList

  • ArrayLisy的简易实现与存在的问题
java 复制代码
public class ArrayList {
    private Object[] array;
    private int size;
    public void add(Object e) {...}
    public void remove(int index) {...}
    public Object get(int index) {...}
}

问题:没有使用泛型,所以使用这个ArrayList时,插入和检索元素都不会有编译时类型检查,可能需要强制类型转换,并且存在类型转换错误的风险。如果不使用泛型重新编写就必须这么写,泛型稍后再讲:

java 复制代码
ArrayList list = new ArrayList();
list.add("Hello");
// 获取到Object,必须强制转型为String:
String first = (String) list.get(0);

基本使用

以下是如何声明和使用List的一些基本示例:

声明并初始化一个List
java 复制代码
List<String> list = new ArrayList<String>(); // 使用泛型来指定List的元素类型为String

或者使用Java 7以后的菱形语法(diamond syntax):

java 复制代码
List<String> list = new ArrayList<>(); // Java 7+可以自动推断出泛型类型
添加元素

使用add方法可以向List中添加元素:

java 复制代码
list.add("Apple");
list.add("Banana");
list.add("Cherry");
访问元素

可以使用get方法通过索引访问List中的元素:

java 复制代码
String fruit = list.get(0); // 获取第一个元素,索引是0
修改元素

通过指定索引,我们可以替换List中的元素:

java 复制代码
list.set(1, "Blueberry"); // 将索引位置1的元素(即"Banana")替换为"Blueberry"
删除元素

List中删除元素可以使用remove方法:

java 复制代码
list.remove("Cherry"); // 删除指定的对象
list.remove(0); // 删除索引位置0的元素
遍历List

可以使用for-each循环来遍历List中的元素:

java 复制代码
for (String fruit : list) {
    System.out.println(fruit);
}

或者使用传统的for循环来通过索引访问:

java 复制代码
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

还可以使用IteratorListIterator来遍历:

java 复制代码
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}
列表大小

获取List的元素个数:

java 复制代码
int size = list.size();
判断列表是否为空

判断List是否为空:

java 复制代码
boolean isEmpty = list.isEmpty();
清空列表

删除List中的所有元素:

java 复制代码
list.clear();
检查元素是否存在

检查某个元素是否在List中:

java 复制代码
boolean contains = list.contains("Apple");

ArrayList vs LinkedList

  • ArrayList:基于动态数组实现,提供快速的随机访问和快速的遍历。但添加或删除元素(尤其是在列表的前面或中间)可能较慢,因为可能涉及到数组的复制和移动。

  • LinkedList:基于双向链表实现,添加和删除元素通常更快,但随机访问较慢。

根据具体的使用场景选择合适的List实现是重要的,如果频繁进行随机访问,ArrayList通常是更好的选择;如果频繁插入和删除元素,LinkedList可能更有优势。

编写equals和hashCode

EqualsMethod.java

编写一个正确的 equals() 方法很重要,以确保对象在比较时表现出正确的行为。以下是编写 equals() 方法的标准准则和步骤:

  1. 使用 == 检查"引用相等" :先检查被比较的对象是否是对同一个对象的引用。如果是,直接返回 true。这不仅是一个性能优化,也是逻辑正确性的保障。

    java 复制代码
    if (this == obj) return true;
  2. 检查 null :检查传入的对象是否为 null。如果是,返回 false。因为按照约定,任何非空引用值与 null 比较时,都应该返回 false

    java 复制代码
    if (obj == null) return false;
  3. 比较类类型是否相同 :检查 thisobj 是否属于同一个类。如果你希望具有相同类继承层次的对象在逻辑上视为相等,可以使用 instanceof 检查。否则,使用 getClass() 方法进行比较以确保类型完全相同。

    java 复制代码
    if (getClass() != obj.getClass()) return false;
  4. 类型转换:将传入的对象转换(强制类型转换)为正确的类型,以便可以访问其属性或方法。

    java 复制代码
    MyClass myClassObj = (MyClass) obj;
  5. 比较关键字段 :对类中每个"重要"属性进行比较。如果是基本数据类型,可以直接使用 ==;对于对象类型,则应使用 equals() 进行比较。对于数组类型的字段,可以使用 Arrays.equals() 检查每个元素。

    java 复制代码
    return (this.field1 == myClassObj.field1) &&
           (this.field2.equals(myClassObj.field2));
  6. 编写 hashCode() 方法 :当重写 equals() 方法时,也必须重写 hashCode() 方法,以保持 hashCode 的一致性。即,如果两个对象通过 equals() 方法判断相等,它们的 hashCode 值也必须相同。

    java 复制代码
    @Override
    public int hashCode() {
        // 使用Objects.hash或者自定义逻辑来生成hashCode
        return Objects.hash(field1, field2);
    }

遵循以上准则,可以确保您的 equals() 方法是正确、高效且符合Java相等性约定的。如果不调用List的contains()、indexOf()这些方法,那么放入的元素就不需要实现equals()方法。

使用Map

MapIntro.java

以下是一些常用的 Map 接口操作:

  • put(K key, V value): 将指定的值与此映射中的指定键关联(可选操作)。
  • get(Object key): 返回指定键所映射的值;如果此映射不含该键的映射关系,则返回 null
  • remove(Object key): 如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。
  • containsKey(Object key): 如果此映射包含指定键的映射关系,则返回 true
  • containsValue(Object value): 如果此映射将一个或多个键映射到指定值,则返回 true
  • size(): 返回此映射中的键值映射关系数。
  • isEmpty(): 如果此映射不包含键值映射关系,则返回 true
  • clear(): 从此映射中移除所有的映射关系(可选操作)。
  • keySet(): 返回此映射中包含的键的 Set 视图。
  • values(): 返回此映射中包含的值的 Collection 视图。
  • entrySet(): 返回此映射中包含的映射关系的 Set 视图。

使用Set

SetIntro.java

Map用于存储key-value的映射,对于充当key的对象,是不能重复的,并且,不但需要正确覆写equals()方法,还要正确覆写hashCode()方法。

如果我们只需要存储不重复的key,并不需要存储映射的value,那么就可以使用Set。无序,不重复。

以下是 Set 接口中的一些基本操作:

  • add(E e): 如果指定元素尚未存在于集合中,则添加该元素(可选操作)。
  • remove(Object o): 如果指定元素存在于集合中,则移除它(可选操作)。
  • contains(Object o): 如果集合包含指定元素,则返回 true
  • size(): 返回集合中元素的数量。
  • isEmpty(): 如果集合不包含元素,则返回 true
  • clear(): 移除集合中所有元素(可选操作)。
  • iterator(): 返回在此集合中元素上进行迭代的迭代器。

使用Collections

CollectionsIntro.java

Java 的 Collections 类(注意是复数形式)是一个包含静态方法的工具类,这些方法可以用于对集合(如列表、集合和映射)进行操作和转换。Collections 类位于 java.util 包中,提供了一系列的静态方法,用于实现集合的搜索、排序、线程安全化、只读化等操作。

这里是 Collections 类的一些常用方法:

排序和混排

  • sort(List list): 对指定列表按照自然顺序进行排序。
  • sort(List list, Comparator<? super T> c): 根据提供的比较器对列表进行排序。
  • shuffle(List<?> list): 使用默认随机源对列表进行置换,打乱列表中元素的顺序。

查找和替换

  • binarySearch(List<? extends Comparable<? super T>> list, T key): 使用二分搜索法搜索指定列表,以获得指定对象,前提是列表已经排序。
  • binarySearch(List<? extends T> list, T key, Comparator<? super T> c): 根据指定比较器使用二分搜索法搜索指定列表。
  • replace(List list, T oldVal, T newVal): 替换列表中所有出现的旧元素。

反转和旋转

  • reverse(List<?> list): 反转指定列表中元素的顺序。
  • rotate(List<?> list, int distance): 根据指定的距离旋转列表。

最大值和最小值

  • max(Collection<? extends T> coll): 根据元素的自然顺序,返回给定集合的最大元素。
  • max(Collection<? extends T> coll, Comparator<? super T> comp): 根据指定比较器,返回给定集合的最大元素。
  • min(Collection<? extends T> coll): 根据元素的自然顺序,返回给定集合的最小元素。
  • min(Collection<? extends T> coll, Comparator<? super T> comp): 根据指定比较器,返回给定集合的最小元素。

同步控制

  • synchronizedCollection(Collection c): 返回由指定集合支持的同步(线程安全的)集合。
  • synchronizedList(List list): 返回由指定列表支持的同步(线程安全的)列表。
  • 等等,类似的还有 synchronizedMap, synchronizedSet, synchronizedSortedMap, synchronizedSortedSet

不可修改的集合

  • unmodifiableCollection(Collection<? extends T> c): 返回指定集合的不可修改视图。
  • unmodifiableList(List<? extends T> list): 返回指定列表的不可修改视图。
  • 等等,类似的还有 unmodifiableMap, unmodifiableSet, unmodifiableSortedMap, unmodifiableSortedSet

示例:使用 Collections.sort()

java 复制代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CollectionsExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("banana");
        list.add("apple");
        list.add("cherry");
        
        // 排序前
        System.out.println("Before sorting: " + list);
        
        // 排序
        Collections.sort(list);
        
        // 排序后
        System.out.println("After sorting: " + list);
    }
}

在这个示例中,创建了一个字符串列表,并使用 Collections.sort() 方法对其进行了排序。这是 Collections 类中许多有用方法之一,可以大大简化常见的集合操作。

相关推荐
考虑考虑1 小时前
Jpa使用union all
java·spring boot·后端
用户3721574261351 小时前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊2 小时前
Java学习第22天 - 云原生与容器化
java
渣哥4 小时前
原来 Java 里线程安全集合有这么多种
java
间彧4 小时前
Spring Boot集成Spring Security完整指南
java
间彧5 小时前
Spring Secutiy基本原理及工作流程
java
Java水解6 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆8 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学8 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole8 小时前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端