Java 的集合体系

数组与集合的区别

  • 数组的长度是固定的,集合的长度是可变的;
  • 数组中可以存储基本数据类型,也可以存储对象,而集合中只能存储对象;

集合的分类

  • Collection:表示一组对象;
  • Map :表示一组映射关系或键值对;

集合体系

Iterable 接口

iterator() 方法返回 Iterator 接口的实例,用于遍历Collection元素;
只要是实现了 Iterable 接口的集合类都可以直接使用加强for循环来遍历;
加强 for 循环内部帮我们使用 Iterator 遍历;

public interface Iterable<T> {
	Iterator<T> iterator();
	default void forEach(Consumer<? super T> action) {....};
}

Iterator 接口

Java 访问 Collection 总是通过统一 的方式——迭代器(Iterator)来实现;
优点在于:

  • ​无需知道集合内部元素是按什么方式存储的;
  • ​对于不同的集合类型,返回的 Iterator 对象实现也是不同的,但总是具有最高的访问效率
  • 迭代器使用的注意点:
    集合对象每次调用 iterator() 方法都会得到一个全新的迭代器对象;游标默认在第一个元素之前;
    remove 方法的注意点:
    • 未调用 next() 就 remove;
    • 调用一个next,连续调用2次 remove;
      报异常:IllegalStateException;
// Iterator 接口,取代了原始的迭代器:Enumeration接口
public interface Iterator<E> {
	boolean hasNext();
	E next();
	//如果在迭代过程中以除调用此方法之外的任何方式修改了基础集合,则迭代器的行为是未指定的。
	//这个方法在每次调用 next 时只能被调用一次;
	default void remove(){}default void forEachRemaining(Consumer<? super E> action){
	Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
        }}

Collection接口

Collection : 表示一组对象,此接口继承了 Iterable 接口;

  • List :有序列表,按照元素放入的先后顺序存放,每个元素都可以通过索引确定自己的位置;
    -ArrayList :内部使用数组来存储所有的元素;
    -Vector: 一种线程安全的 List 实现;
    - -Stack:栈
    -LinkedList:通过双向链表的方式实现;(实现了List和Deque接口)
  • Set :没有重复元素的集合;
    -HashSet
    - -LinkedHashSet : 可以按照添加顺序遍历
    -TreeSet : 自然顺序(从小到大),必须是实现 Comparable接口的同一类型数据;
  • Queue :队列,先进先出的有序表;
    -Deque :双端队列接口;
    - -LinkedList
    - -ArrayDeque
    -PriorityQueue:优先级队列,类;
    -BlockingQueue:阻塞对列接口,获取元素时可能会让线程变成等待状态 ;java.util.concurrent
    - -ArrayBlockingQueue: 由数组结构组成的有界阻塞队列。
    - -SynchronousQueue:不存储元素的阻塞队列,也即单个元素的队列;
    - -LinkedBlockingQueue:由链表结构组成的有界阻塞队列。
    - -PriorityBlockingQueue:支持优先级排序的无界阻塞队列;
    注:
    1、list可以在任意位置添加和删除元素,而 Queue 只有两个操作:
    • 把元素添加到队列末尾;add() / offer
    • 从队列头部取出元素;remove() / poll()

2、LinkedList 既实现了 List 接口,又实现了 Queue 和 Deque 接口,使用的时候根据需要来指定引用:

//List
List<String> list = new LinkedList<>();
//Queue
Queue<String> queue = new LinkedList<>();
//Deque
Deque<String> deque = new LinkedList<>();

3、PriorityQueue : 优先队列
PriorityQueue 和 Queue 的区别在于,它的出队顺序与元素的优先级有关,调用 remove 或 poll,返回的总是优先级最高的元素

放入 PriorityQueue 的元素,必须实现 Comparable 接口,PriorityQueue 会根据元素的排序顺序决定出队的优先级;

如果我们要放入的元素并没有实现Comparable接口,PriorityQueue允许我们提供一个Comparator对象来判断两个元素的顺序。

队列中的元素按照自然顺序(从小到大)弹出,“小元素”的优先级最高;

public class Main {
    public static void main(String[] args) {
        Queue<String> q = new PriorityQueue<>();
        // 添加3个元素到队列:
        q.offer("apple");
        q.offer("pear");
        q.offer("banana");
        System.out.println(q.poll()); // apple
        System.out.println(q.poll()); // banana
        System.out.println(q.poll()); // pear
        System.out.println(q.poll()); // null,因为队列为空
    }
}

4、Stack

	一种后进先出(LIFO)的数据结构;

stack 的相关操作:

​ 压栈:push(E);

​ 弹出栈顶的元素: pop();

​ 取栈顶元素但不弹出:peek();

Collection 接口

常用方法:

  1. boolean add(Object obj) # 添加元素
  2. boolean c1.addAll(Collection c2) # 提取 c2 中的元素,分别添加到 c1;
  3. int c.size() # 获取集合中元素的数量;
  4. void c.clear() # 清空集合;
  5. boolean c.isEmpty() # 判断集合是否为空;
  6. boolean c.remove(Object obj) # 删除指定的元素,如果列表中有重复的元素,则只能删除第一个;
  7. boolean c1.removeAll(c2) # 求差集;从 c1 中移除c2中的所有元素;
  8. boolean c1.retainAll(c2) # c1 改变为与 c2 的交集;
  9. boolean c.contains(Object) # 判断集合内是否包含指定元素,调用 equals;
  10. boolean c1.containsAll(Collection c2) # 判断 c2 中的元素是否都存在于 c1 中;
  11. Object[] c.toArray() # 转为数组;
  12. boolean c1.equals(c2) # 判断 c1 与 c2 是否想相等; List : 元素 +顺序; set 只看元素;

List 接口

接口中的方法

List接口中的方法增加了索引操作:
1、void add(int index, Object ele) # 在 index 位置插入 ele 元素;

​ 2、boolean addAll([int index],Collection eles) # 从 Index 位置开始,将 eles 中的所有元素添加进来;

​ 3、Object get(int index) # 获取指定 index 位置的元素;

​ 4、int indexOf(Object obj ) # 返回 obj 在集合中首次出现的位置,找不到返回 -1;

​ 5、int lastIndexOf( Object obj) # 返回 obj 在当前集合中末次出现的位置;

​ 6、Object remove(int index)

​ 7、Object set(int index, Object ele) # 返回原值;

​ 8、List subList(int fromIndex, int toIndex) : 左闭右开

注意:
要正确使用 List 的 contains() 、 indexOf() 这些方法,放入的实例必须正确覆写 equals() 方法否则查找不到

怎样正确编写 equals方法?

1、先确定实例相等的逻辑,即哪些字段相等,就认为实例相等;
​ 2、用 instanceof 判断传入的待比较的 Object 是不是当前类型,如果是,继续比较,否则,返回 false;
​ 3、对引用类型用 Objects.equals() 比较,对基本类型直接用 == 比较;

List 与数组之间的转换

List 转数组:

1、Object[] array = list.toArray(); # 会丢失类型信息;
2、给 toArray(T[]) 传入一个类型相同的 Array,List内部自动把元素复制到传入的 Array 中:
Integer[] array = list.toArray(new Integer[3]);
或者
Integer[] array = list.toArray(Integer[] : :new );

注意:
1、如果数组类型与集合存储的类型不一致,会抛异常: ArrayStoreException;
2、如果传入的数组不够大,List内部会创建刚好够大的数组,填充后返回;
3、如果传入的数组比 List 元素还要多,剩下的数组元素一律填充 null;
4、List 可以直接打印出其中的元素,而对于数组则需要调用Arrays.toString(strArray);

// 只有List指定了泛型,且toArray传入了对应类型数组作为参数,才能返回指定类型的数组
List<String> list =new ArrayList<>();
String[] strArry = list.toArray(new String[]{}); 

//未泛型但指定参数;返回的仍然是Object数组
List list2 =new ArrayList();
Object[] objects = list2.toArray(new String[]{});
数组转List

Arrays.asList(T…t) : 快速创建一个list 并赋值;

接收可变长的参数,转换成一个不可变的集合;返回一个受指定数组支持的固定大小的列表;
不可变:
不能进行 add 、remove,否则报UnsupportedOperationException
可以进行 set(index,obf) 修改;但是index如果超出索引下标范围,会 ArrayIndexOutOfBoundsException;

注意:
Arrays.asList(T…t) # 里面是一个个对象,如果传入基本数据类型的一个数组,会被看做一个引用数据类型整体添加;
List list1 = Arrays.asList(new int[]{1,2,3});
System.out.println("list1.size() = " + list1.size()); //1
对于非基本数据类型的数组
List list2 = Arrays.asList(new String[]{“a”,“b”,“c”});
System.out.println("list2.size() = " + list2.size());//3

Set接口中的方法

Set 接口在 Collection 接口的基础上没有额外提供方法;
只实现了 Collection 接口中的默认方法:
default boolean removeIf(Predicate<? super E> filter);

set集合不允许包含相同的元素,如果添加相同的元素到一个set集合中,则添加失败(不会报错)!

set 根据 equals 方法的返回值来判断两个对象是否相等;

放入 Set 的元素,必须正确实现 equals 和 hashCode 方法;

Set相当于只存储 key 不存储 value 的Map,我们通常用它来去除重复元素;

public HashSet() {
        map = new HashMap<>();
    }

  // 存放元素时,只使用了HashMap的key,
   public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
 // value是一个静态常量,所有key共用同一个 value,节省了内存
  private static final Object PRESENT = new Object();

利用 Set 快速对 list 进行去重:

Set set = new HashSet();
set.addAll(list);
List newList = new ArrayList(set);

Queue 接口中的方法

Throw Exception返回false或null
添加元素到队尾boolean add(E e)boolean offer(E e)
取队首元素并删除E remove()E poll()
取队首元素但不删除E element()E peek()

ArrayList

底层采用Object数组;大小可变数组的一种实现;
底层使用的是 Arrays.copyOf():

public static <T> T[] copyOf(T[] original, int newLength)
# original: 将要被复制的数组
# newLength: 返回的复制后的数组的长度
# 返回原始数组的副本

ArrayList的构造器

1、传入一个集合,按照从此集合迭代器中,迭代出来的元素顺序,构造一个ArrayLsit;

public ArrayList(Collection<? extends E> c) {...}

2、开发过程中如果知道数组的长度,可以使用带参的构造器,传入一个合适的初始容量,避免使用过程中发生扩容;

public ArrayList(int initialCapacity) {...}

3、空参构造器
JDK1.7:new对象时,空参构造器默认创建一个长度为 10 的Object 数组;容量不够时扩大为原来的1.5倍;
​JDK1.8:new对象时,生成的是长度为 0 的Object数组,第一次添加元素时才会生成一个长度为10 的数组;

扩容

存储的数据个数 > 底层数组长度, 执行扩容;

Map 接口

继承关系

Map接口:

​ – HashMap (主要实现类,线程不安全,可以存储 null 的 key 和 value)

​ ----LinkedHashMap(在HashMap的基础上加了一对指针,HashMap 的子类,保证可以按照添加顺序遍历 map,对于频繁的遍历操作,此类的执行效率比较高)

​ – HashTable (古老实现类,线程安全,key和value不能为 null);

​ ---- Properties (常用来处理配置文件,key 和 vlaue 都是 String);

​ – SortedMap(接口)

​ ---- TreeMap (底层是红黑树,可以实现排序遍历,key必须是同一个类的对象);

CurrentHashMap : 高并发条件下使用的一种线程安全的 Map;

接口中常用方法

Object put(Object key , Object value ) : 添加或修改,key已存在时,修改操作,返回的是旧值, key 不存在时,添加操作,返回的是 null;

void putAll(Map m) : 将 m 中的所有 k-v 放入到当前 map 中;

Object remove(Object key) : 移除指定 key 的 k-v 对,并返回 value;如果 key不存在,则返回 null;

boolean remove(Object key , Object value) : key不存在或者 key 对应的 value 与形参不一致,返回 false;

void clear() : 清空当前 map 中的所有数据;

V replace(K key , V value) # key 不存在返回 null; key 存在,替换旧值,并返回旧值;

boolean replace( K key , V oldValue , V newValue) # key & value 都存在,替换成功,返回 true,否则返回 false;

Object get(Object key) :

​boolean containsKey(Object key)

​boolean containsValue(Object value)

​int size():

​boolean isEmpty()

​boolean equals(Object obj)

Set keySet( ) : 返回所有 key 构成的 Set 集合;

Collection values() : 所有 value 构成的 Collection 集合;

Set entrySet() : 返回所有 key-value 对 构成的 Set 集合,Entry对象中可以 entry.getKey() , entry.getValue();

equals() 与 hashCode()的编写规则

equals() 返回 true , hashCode 计算的值(一个 int 整数)必须相同;

equals 返回 false, 两个对象的 hashCode() 尽量不要相等

HashMap的存储过程

首先调用key所在类的 hashCode 方法,计算 hash值,与数组索引做映射,找到存储位置
- - 如果索引位置为空,直接添加;
- - 如果索引位置不为空,则判断 key 与已存在key的hash值是否相等;
- - - - 如果不相等,则添加成功;
- - - - 如果相等,则调用 key 的 equals 方法,
- - - - - - 如果返回 true 则修改value;
- - - - - - 如果返回 false 则添加;

HashMap 的扩容与树化

JDK7
扩容:添加元素时,Map 中键值对的数量大于等于阈值,且添加位置不为空,扩容为原来的2倍,旧数据重新存放;
树化:JDK7无树化行为;

JDK8
扩容:

  1. ​ size 大于等于阈值,扩容为原来的2倍,扩容后旧数据要重新存放;
  2. ​ 当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前数组的长度 < 64 时;

树化:
当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前数组的长度 >= 64 时,此时此索引位置上的所有数据改为使用红黑树存储;

1、HashMap的设计者不希望一个桶里面有太多元素,同时,也不想让桶内的元素树化,如果能够通过扩容数组达到分散元素的目的,尽量扩容数组,
2、如果数组已经足够长 > 64 , 设计者才考虑将桶内元素树化,增强元素查找性能;
3、加载因子的合理值是0.75; 如果太小数组的利用率低,如果太大树化长度程度又太高;

equals 与 == 的区别

“==” :用于比较基本数据类型和引用类型数据:
1、当比较基本数据类型的时候比较的是数值;
​ 2、判断两个引用是否指向同一个对象

如果编程人员没有显示地重写 equals() 方法,则默认比较两个引用是否指向同一个对象。

//Object类中的equals()方法源码 
public boolean equals(Object obj) {  
  return (this == obj);
}

TreeMap

遍历 TreeMap 得到的顺序一定是排好序的;

TreeMap 不使用 equals 和 hashCode;

放入的 key 必须实现 Comparable 接口(实现 int compareTo(T o));

如果 key 没有实现 Comparable 接口,那么在创建 TreeMap 时需要传入 Comparator 接口的实现类;

Map<Person, Integer> map = new TreeMap<>(new Comparator<Person>(){
    public int compare(Person p1,Person p2){
        return p1.name.compareTo(p2.name);
    }  
});

TreeMap 在比较两个 Key是否相等时,依赖 Key 的 compareTo() 方法 或者 Comparator.compare()方法,当两个key相等时,必须返回 0 。 否则 map.get(xxx); 会返回 null;

Properties

读取 .properties 文件:

String f = "setting.properties";
Properties props = new Properties();
props.load(new FileInputStream(f));
// 从 Classpath 读取配置文件
props.load(getClass().getResourceAsStream("/commom/setting.properties"));
// key 不存在将返回 null。我们可以设置一个默认值;
String filepath = props.getProperty("auto_save_interval""120");
props.setProperty("language", "Java");
props.store(new FileOutputStream("C:\\conf\\setting.properties"), "这是写入的properties注释");

如果有多个.properties文件,可以反复调用load()读取,后读取的key-value会覆盖已读取的key-value;

Collections 工具类

Collections 是一个操作 Set、List 和 Map 等集合的工具类;

排序:

​ 1、reverse(List) : 反转 List 中元素的顺序;

​ 2、shuffle(List) : 对 List 集合元素进行随机排序;

​ 3、sort(List)

​ 4、sort(List, Comparator)

​ 5、swap(List,int i int j) : 交换 i 处 和 j 处元素;

​ Object max(Collection) : 返回集合中自然顺序,最大的元素;

​ Object min(Collection) : 返回最小元素;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值