赞
踩
**点击蓝字 关注我们**
哦豁!今天读到第八章了,对象的容纳,这一章主要讲Java如何存储对象,如何快速搜索成千上万(或上百万,千万级别)有序的数据项。如何快速地在有序的序列中间插入元素或删除元素呢?
这一章我结合Java核心技术卷1中的第9章集合,一起编写的读书笔记,我感觉Java核心卷说的比Java编程思想好一点。因为Java编程思想,它的jdk版本太老了,有些集合用法没有正式发布,它就简单地说一下,所以我又翻出了之前公司叫我看的书。
“如果一个程序只含有数量固定的对象,而且已知他们的存在时间,那么这个程序可以说相当简单。”
一、Java集合的框架
Java集合类库将接口(interface)与实现(implementation)分离。首先我们看一下队列(queue)
1、队列quere
队列可以在尾部添加元素,在队列头部删除元素,并且可以,查找队列中的元素个数,当需要收集对象,按照“先进先出”的规则检索对象,就应该用队列如下图。
队列实现方式有两种:1、循环数组 2、链表 如下图所示
循环数组是一个有界集合,及容量有限,如果程序中收集的对象没有上限,那就用链表来展示。
2、Collection接口
在Java类库中,集合类的基本接口是Collection接口。Collection接口的代码给大家展示一下:
public interface Collection<E> extends Iterable<E> { int size(); boolean isEmpty(); Iterator<E> iterator(); Object[] toArray(); <T> T[] toArray(T[] a); boolean containsAll(Collection<?> c); default boolean removeIf(Predicate<? super E> filter) { Objects.requireNonNull(filter); boolean removed = false; final Iterator<E> each = iterator(); while (each.hasNext()) { if (filter.test(each.next())) { each.remove(); removed = true; } } return removed; } boolean add(E e); boolean retainAll(Collection<?> c); void clear(); boolean equals(Object o); int hashCode(); @Override default Spliterator<E> spliterator() { return Spliterators.spliterator(this, 0); } default Stream<E> stream() { return StreamSupport.stream(spliterator(), false); } default Stream<E> parallelStream() { return StreamSupport.stream(spliterator(), true); } }
这里面的add方法是用于向集合中添加元素,添加元素改变集合就返回true,反之返回false。Iterator方法用于实现Iterator接口的对象。
3、Iterator迭代器
Iterattor包含四个方法,源码展示一下:
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
通过反复调用next方法,可以逐个访问集合中的每个元素,但是当到达集合末尾的时候,next的方法会抛出NoSuchElementException的异常,所以当我们调用next方法前可以调用hasNext方法。如果迭代器对象还有多个供访问的元素,方法就返回true,如果想查看集合中的所有元素,就请求另一个迭代器,并在hasNext返回true时反复调用next方法。
在Iteratior接口中的remove方法将会删除上次调用next方法时返回的元素,并且next方法与remove方法的调用具有依赖性,如果调用remove方法之前没有调用next的方法是不合法的,会抛出IllegalStateException异常。
这里面还有很多其他用法,不在这里展示了,准备另写一篇总结一下api注释。
4、集合框架中的接口
集合有两个基本接口:Collection和Map。大家看一下,我画的这些接口图片,以及他们的继承关系。如下图
二、具体集合
Java类库中集合上一节最后给大家列出了它们之间的关系,映射的内容下一节展示,这一节就加单的介绍一下集合。
这图片是我在Java核心技术卷截图来的,之前读书的时候记得笔记。
1、ArrayList
ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。ArrayList 继承了 AbstractList ,并实现了 List 接口。
ArrayList 是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。下面我们展示一下ArrayList常用用法:
1、添加元素
添加元素到 ArrayList 可以使用 add() 方法:
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<String> company = new ArrayList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
System.out.println(company);
}
}
控制台输出
[Google, Baidu, Alibaba, Tencent]
2、访问元素
访问 ArrayList 中的元素可以使用 get() 方法:
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<String> company = new ArrayList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
System.out.println(company.get(1)); // 访问第二个元素,数组的索引值从 0 开始。
}
}
3、修改元素
如果要修改 ArrayList 中的元素可以使用 set() 方法:
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<String> company = new ArrayList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
company.set(2, "SpaceX"); // 第一个参数为索引位置,第二个为要修改的值
System.out.println(company);
}
}
控制台输出:
[Google, Baidu, SpaceX, Tencent]
4、删除元素
如果要删除 ArrayList 中的元素可以使用 remove() 方法:
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<String> company = new ArrayList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
company.remove(3); // 删除第四个元素
System.out.println(company);
}
}
控制台输出:
[Google, Baidu, Alibaba]
5、计算大小
如果要计算 ArrayList 中的元素数量可以使用 size() 方法:
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<String> company = new ArrayList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
System.out.println(company.size());
}
}
控制台输出:
4
6、迭代数组
ArrayList可以用for和for-each来迭代数组
(1)用 for 来迭代数组列表中的元素:
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<String> company = new ArrayList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
for (int i = 0; i < company.size(); i++) {
System.out.println(company.get(i));
}
}
}
控制台输出:
Google
Baidu
Alibaba
Tencent
(2)for-each 来迭代元素
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<String> company = new ArrayList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
for (String i : company) {
System.out.println(i);
}
}
}
控制台输出:
Google
Baidu
Alibaba
Tencent
7、其他的引用类型
ArrayList 中的元素实际上是对象,在以上实例中,数组列表元素都是字符串 String 类型。如果我们要存储其他类型,而 只能为引用数据类型,这时我们就需要使用到基本类型的包装类。
基本类型对应的包装类表如下:
8、ArrayList 排序
Collections 类也是一个非常有用的类,位于 java.util 包中,提供的 sort() 方法可以对字符或数字列表进行排序。以下实例对字母进行排序:
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<String> company = new ArrayList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
Collections.sort(company); // 字母排序
for (String i : company) {
System.out.println(i);
}
}
}
控制台输出:
Google
Baidu
Alibaba
Tencent
2、LinkedList
之前咱们介绍过链表,这一小节我们详细的说一下链表以及它的详细用法。之前说过数组和数组列表他们有重大缺陷,那就是删除元素的时候,需要将删除元素后的所有元素向前移动,插入也是如此。这十分麻烦,但是链表就能解决这一问题。在java中链表实际上是双向链接的想,没一个节点都有一个前驱节点。当删除元素时候,只需要更新被删除元素附近的链接。
下面我们介绍一下LinkedList,链表是一个有序集合,每个对象的位置上是十分重要,linkedList.add的方法将对象添加到链表的尾部,但是他常常将需要的元素加到链表的中间,这是由于迭代器来负责add的方法。只有对自然有序的集合使用迭代器添加元素才有实际的意义。
以下情况使用 ArrayList :
1、频繁访问列表中的某一个元素。
2、只需要在列表末尾进行添加和删除元素操作。
以下情况使用 LinkedList :
1、你需要通过循环迭代来访问列表中的某些元素。
2、需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作。
LinkedList继承和实现的接口:
1、LinkedList 继承了 AbstractSequentialList 类。
2、LinkedList 实现了 Queue 接口,可作为队列使用。
3、LinkedList 实现了 List 接口,可进行列表的相关操作。
4、LinkedList 实现了 Deque 接口,可作为队列使用。
5、LinkedList 实现了 Cloneable 接口,可实现克隆。
6、LinkedList 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。
接下来举些例子吧,看起来更加直观
1、创建LinkedList
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<String> company = new LinkedList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
System.out.println(company);
}
}
控制台输出:
[Google, Baidu, Alibaba, Tencent]
2、在列表开头添加元素:
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<String> company = new LinkedList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
// 使用 addFirst() 在头部添加元素
company.addFirst("SpaceX");
System.out.println(company);
}
}
控制台输出:
[SpaceX, Google, Baidu, Alibaba, Tencent]
3、在列表结尾添加元素:
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<String> company = new LinkedList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
// 使用 addLast() 在尾部添加元素
company.addLast("IBM");
System.out.println(company);
}
}
控制台输出:
[Google, Baidu, Alibaba, Tencent, IBM]
4、在列表开头移除元素:
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<String> company = new LinkedList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
// 使用 removeLast() 移除尾部元素
company.removeLast();
System.out.println(company);
}
}
控制台输出:
[Google, Baidu, Alibaba]
5、获取列表开头的元素
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<String> company = new LinkedList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
// 使用 getFirst() 获取头部元素
System.out.println(company.getFirst());
}
}
控制台输出:
Google
6、获取列表结尾的元素:
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<String> company = new LinkedList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
// 使用 getLast() 获取尾部元素
System.out.println(company.getLast());
}
}
控制台输出:
Tencent
7、迭代元素
在Linkedlist中可以用for配合size()来迭代列表中的元素,或者用for-each来迭代元素。
(1)for配合size()来迭代列表中的元素
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<String> company = new LinkedList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
//使用for配合size()来迭代列表中的元素
for (int size = company.size(), i = 0; i < size; i++) {
System.out.println(company.get(i));
}
}
}
控制台输出:
Google
Baidu
Alibaba
Tencent
(2)用for-each来迭代元素。
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<String> company = new LinkedList<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
//使用for-each来迭代
for (String i : company) {
System.out.println(i);
}
}
}
控制台输出:
Google
Baidu
Alibaba
Tencent
3、HashSet
散列集,HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。HashSet 允许有 null 值。HashSet 是无序的,即不会记录插入的顺序。HashSet 不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。 您必须在多线程访问时显式同步对 HashSet 的并发访问。HashSet 实现了 Set 接口。
HashSet 中的元素实际上是对象,一些常见的基本类型可以使用它的包装类,基本类型对应的包装类表如下:
散列表:散列表用链表数组来实现,每个列表被称为桶(bucket),要想查找表中对象的位置,就先要计算它的散列码,然后与桶的总数取余,所得到的就是保存这个元素的桶的索引。
HashSet基于散列表的集,可以用add方法添加元素。contain方法已经被重新定义,用来快速查看是否某个元素已经存在集中,它只是在桶中查询某个元素,不需要查看集合中所有的元素。HashSet 类提供了很多有用的方法,接下来我们展示一下HashSet常用用法:
1、添加元素
添加元素可以使用 add() 方法:
public class HashSetTest {
public static void main(String[] args) {
HashSet<String> company = new HashSet<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
company.add("Alibaba");// 重复的元素不会被添加
System.out.println(company);
}
}
控制台输出:在上面的实例中,Google被添加了两次,它在集合中也只会出现一次,因为集合中的每个元素都必须是唯一的。
[Google, Baidu, Alibaba, Tencent]
2、判断元素是否存在
我们可以使用 contains() 方法来判断元素是否存在于集合当中:
public class HashSetTest {
public static void main(String[] args) {
HashSet<String> company = new HashSet<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
System.out.println(company.contains("Alibaba"));
}
}
控制台输出:
true
3、删除元素
我们可以使用 remove() 方法来删除集合中的元素:
public class HashSetTest {
public static void main(String[] args) {
HashSet<String> company = new HashSet<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
company.add("Alibaba");// 重复的元素不会被添加
company.remove("Alibaba"); // 删除元素,删除成功返回 true,否则为 false
System.out.println(company);
}
}
当然我们也可以用clear 方法,clean是清除所有元素。
public class HashSetTest {
public static void main(String[] args) {
HashSet<String> company = new HashSet<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
company.add("Alibaba");// 重复的元素不会被添加
company.clear();
System.out.println(company);
}
}
控制台输出:
[]
4、计算大小
如果要计算 HashSet 中的元素数量可以使用 size() 方法:
public class HashSetTest {
public static void main(String[] args) {
HashSet<String> company = new HashSet<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
company.add("Alibaba");// 重复的元素不会被添加
System.out.println(company.size());
}
}
控制台输出:
4
5、迭代 HashSet
可以使用 for-each 来迭代 HashSet 中的元素。
public class HashSetTest {
public static void main(String[] args) {
HashSet<String> company = new HashSet<String>();
company.add("Google");
company.add("Baidu");
company.add("Alibaba");
company.add("Tencent");
company.add("Alibaba");// 重复的元素不会被添加
for (String i : company) {
System.out.println(i);
}
}
}
控制台输出:
Google
Baidu
Tencent
Alibaba
还有一个树集TreeSet这个我准备单独做一期来介绍一下,这里面还是比较复杂,需要时间来整理。下一期我们将会说映射Map的用法。我感觉集合这一章内容真的有点多,一顿吃不下,得分两顿来消化。今天就到这里了,明天咱们再见!觉得写得不错,点赞与分享与在看哦!2022年6月4日23:04:27
期待你的分享点赞在看,扫码关注我们
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。