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接口的两个常用实现类是ArrayList和LinkedList。
- 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));
}还可以使用Iterator或ListIterator来遍历:
            
            
              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() 方法的标准准则和步骤:
- 
使用 ==检查"引用相等" :先检查被比较的对象是否是对同一个对象的引用。如果是,直接返回true。这不仅是一个性能优化,也是逻辑正确性的保障。javaif (this == obj) return true;
- 
检查 null:检查传入的对象是否为null。如果是,返回false。因为按照约定,任何非空引用值与null比较时,都应该返回false。javaif (obj == null) return false;
- 
比较类类型是否相同 :检查 this和obj是否属于同一个类。如果你希望具有相同类继承层次的对象在逻辑上视为相等,可以使用instanceof检查。否则,使用getClass()方法进行比较以确保类型完全相同。javaif (getClass() != obj.getClass()) return false;
- 
类型转换:将传入的对象转换(强制类型转换)为正确的类型,以便可以访问其属性或方法。 javaMyClass myClassObj = (MyClass) obj;
- 
比较关键字段 :对类中每个"重要"属性进行比较。如果是基本数据类型,可以直接使用 ==;对于对象类型,则应使用equals()进行比较。对于数组类型的字段,可以使用Arrays.equals()检查每个元素。javareturn (this.field1 == myClassObj.field1) && (this.field2.equals(myClassObj.field2));
- 
编写 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 类中许多有用方法之一,可以大大简化常见的集合操作。