Java编程思想读书笔记(八)

 **点击蓝字 关注我们**

哦豁!今天读到第八章了,对象的容纳,这一章主要讲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

期待你的分享点赞在看,扫码关注我们

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值