Java集合框架之List ArrayList LinkedList使用详解刨析

目录
  • 1. List
    • 1.1 List 的常见方法
    • 1.2 代码示例
  • 2. ArrayList
    • 2.1 介绍
    • 2.2 ArrayList 的构造方法
    • 2.3 ArrayList 底层数组的大小
  • 3. LinkedList
    • 3.1 介绍
    • 3.2 LinkedList 的构造方法
  • 4. 练习题
  • 5. 扑克牌小游戏

1. List

1.1 List 的常见方法

方法 描述
boolean add(E e) 尾插 e
void add(int index, E element) 将 e 插入到 index 位置
boolean addAll(Collection<? extends E> c) 尾插 c 中的元素
E remove(int index) 删除 index 位置的元素
boolean remove(Object o) 删除遇到的第一个 o
E get(int index) 获取下标 index 位置的元素
E set(int index, E element) 将下标 index 位置元素设置为 element
void clear() 清空
boolean contains(Object o) 判断 o 是否在线性表中
int indexOf(Object o) 返回第一个 o 所在下标
int lastIndexOf(Object o) 返回最后一个 o 的下标
List<E> subList(int fromIndex, int toIndex) 截取部分 list

1.2 代码示例

注意: 下面的示例都是一份代码分开拿出来的,上下其实是有逻辑关系的

示例一: 用 List 构造一个元素为整形的顺序表

List<Integer> list = new ArrayList<>();

示例二: 尾插 e

list.add(1);
list.add(2);
System.out.println(list);
// 结果为:[1, 2]

示例三: 将 e 插入到 index 位置

list.add(0,10);
System.out.println(list);
// 结果为:[10, 1, 2]

示例四: 尾插 c 中的元素

List<Integer> list1=new LinkedList<>();
list1.add(99);
list1.add(100);
list.addAll(list1);
System.out.println(list);
// 结果为:[10, 1, 2, 99, 100]

只要是继承于 Collection 的集合类的元素都可以被插入进去,但要注意传过来的具体的类型要么是和 list 的具体类型是一样的,要么是 list 具体类型的子类

示例五: 删除 index 位置的元素

System.out.println(list.remove(0));
System.out.println(list);
// 结果为:10 和 [1, 2, 99, 100]

示例六: 删除遇到的第一个 o

System.out.println(list.remove((Integer) 100));
System.out.println(list);
// 结果为:true 和 [1, 2, 99]

示例七: 获取下标 index 位置的元素

System.out.println(list.get(0));
// 结果为:1

示例八: 将下标 index 位置元素设置为 element

System.out.println(list.set(2,3));
System.out.println(list);
// 结果为:99 和 [1, 2, 3]

示例九: 判断 o 是否在线性表中

System.out.println(list.contains(1));
// 结果为:true

示例十: 返回第一个 o 所在下标

System.out.println(list.indexOf(1));
// 结果为:0

示例十一: 返回最后一个 o 的下标

list.add(1);
System.out.println(list.lastIndexOf(1));
// 结果为:3

示例十二: 截取部分 list

List<Integer> list2=list.subList(1,3);
System.out.println(list2);
// 结果为:[2, 3]

注意,当我们将 list2 通过 set 更改元素,其实对 list 也会有影响

list2.set(0,5);
System.out.println(list2);
System.out.println(list);
// 结果为:[5, 3] 和 [1, 5, 3, 1]

通过 subList 方法进行的截取,得到的集合的数值指向的地址和原集合中数值的地址是一样的

2. ArrayList

2.1 介绍

ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。其继承了 AbstractList,并实现了 List 接口。LinkedList 不仅实现了 List 接口,还实现了 Queue 和 Deque 接口,可以作为队列去使用。

ArrayList 类位于 java.util 包中,使用前需要引入它。

2.2 ArrayList 的构造方法

方法 描述
ArrayList() 无参构造
ArrayList(Collection<? extends E> c) 利用其他 Collection 构建 ArrayList
ArrayList(int initialCapacity) 指定顺序表初始容量

示例一:

ArrayList<Integer> list1 = new ArrayList<>();

示例二:

ArrayList<Integer> list2 = new ArrayList<>(10);
// 该构造方法就是在构建时就将底层数组大小设置为了10

示例三:

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
ArrayList<Integer> list3 = new ArrayList<>(list);

Collection<? extends E> c 只要是具体类型都和 list3 是一样的集合都可以放入转化成 ArrayList

2.3 ArrayList 底层数组的大小

当我们使用 add 方法给 ArrayList 的对象进行尾插时,突然想到了一个问题:既然 ArrayList 的底层是一个数组,那么这个数组有多大呢?

为了解决这个问题,我进行了如下探索

跳转到 ArrayList 的定义,我们看到了 elementDataDEFAULTCAPACITY_EMPTY_ELEMENTDATA

跳转到 elementData 的定义,我们可以了解 ArrayList 底层是数组的原因

跳转到 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的定义,初步分析得到这个数组其实是空的

为什么这个数组是空的但存储元素的时候没有报异常呢?我们再去了解下 add 是怎样存储的

通过转到 ArrayList 的 add 方法的定义

通过定义,不难发现,数组容量和 ensureCapacityInternal 这个东西有关,那我们就看看它的定义

我们看里面的 calculateCapacity ,他有两个参数,此时数组为空,那么 minCapacity 就为 1。我们再转到 calculateCapacity 看看它的定义

此时我们就好像可以与之前串起来了,当数组为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 时,就返回 DeFauLt_CAPACITYminCapacity(此时为1) 的最大值。DeFauLt_CAPACITY 其实是默认容量的意思,我们可以转到它的定义看看有多大

DeFauLt_CAPACITY 的值是10,故 calculateCapacity 函数此时的返回值为10,最后我们再确定一下 ensureExplicitCapacity 是干啥的

此时 minCapacity 的值是10,而数组为空时数组长度为0,所以进入 if 语句,执行 grow 方法,我们继续转到 grow 的定义

此时我们就可以了解,当我们创建一个 ArrayList 时,其底层数组大小其实是0。当我们第一次 add 的时候,经过 grow ,数组的大小就被扩容为了10。并且这大小为10的容量放满以后,就会按1.5倍的大小继续扩容。至于这个数组最大能存放多少,大家可以再转到 MAX_ARRAY_SIZE 的定义去查看。

3. LinkedList

3.1 介绍

LinkedList 类是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址。

Java 的 LinkedList 底层是一个双向链表,位于 java.util 包中,使用前需要引入它

3.2 LinkedList 的构造方法

方法 描述
LinkedList() 无参构造
LinkedList(Collection<? extends E> c) 利用其他 Collection 构建 LinkedList

示例一:

LinkedList<Integer> list1 = new LinkedList<>();

示例二:

List<Integer> list = new LinkedList<>();
list.add(1);
list.add(2);
LinkedList<Integer> list2 = new LinkedList<>(list);

Collection<? extends E> c 只要是具体类型都和 list2 是一样的集合都可以放入转化成 LinkedList

4. 练习题

习题一

题目描述:

霍格沃茨学院有若干学生(学生对象放在一个 List 中),每个学生有一个姓名(String)、班级(String)和考试成绩(double)。某次考试结束后,每个学生都获得了一个考试成绩。遍历 list 集合,并把每个学生对象的属性都打印出来

本题代码:

class Student{
    private String name;
    private String classes;
    private double score;
	// 重写构造方法
    public Student(String name, String classes, double score) {
        this.name = name;
        this.classes = classes;
        this.score = score;
    }
	// 构造 get 和 set 方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getClasses() {
        return classes;
    }

    public void setClasses(String classes) {
        this.classes = classes;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }
	// 重写 toString 方法
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", classes='" + classes + '\'' +
                ", score=" + score +
                '}';
    }
}
public class TestDemo {
    public static void main(String[] args) {
        ArrayList<Student> students = new ArrayList<>();
        students.add(new Student("哈利波特","大二班",95.5));
        students.add(new Student("赫敏格兰杰","小三班",93));
        students.add(new Student("罗恩韦斯莱","小二班",91));
        for(Student s: students){
            System.out.println(s);
        }
    }
}
// 结果为:
// Student{name='哈利波特', classes='大二班', score=95.5}
// Student{name='赫敏格兰杰', classes='小三班', score=93.0}
// Student{name='罗恩韦斯莱', classes='小二班', score=91.0}

习题二

题目描述:

有一个 List 当中存放的是整形的数据,要求使用 Collections.sort 对 List 进行排序

该题代码:

public class TestDemo {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(3);
        list.add(7);
        list.add(1);
        list.add(6);
        list.add(2);
        Collections.sort(list);
        System.out.println(list);
    }
}
// 结果为:[1, 2, 3, 6, 7]

补充:

Collections 是一个工具类,sort 是其中的静态方法,它是用来对 List 类型进行排序的

注意:

如果具体的类是类似于习题一那样的 Student 类,该类中含有多个属性,那就不能直接使用这个方法。要对 comparator 或者 comparable 接口进行重写,确定比较的是哪个属性才行

习题三

题目描述:

输出删除了第一个字符串当中出现的第二个字符串中的字符的字符串,例如

String str1 = "welcome to harrypotter";
String str2 = "come";
// 结果为:wl t harrypttr

希望本题可以使用集合来解决

该题代码:

public static void removeS(String str1, String str2){
    if(str1==null || str2==null){
        return;
    }
    List<Character> list = new ArrayList<>();
    int lenStr1=str1.length();
    for(int i=0; i<lenStr1; i++){
        char c = str1.charAt(i);
        if(!str2.contains(c+"")){
            list.add(c);
        }
    }
    for(char ch: list){
        System.out.print(ch);
    }
}

5. 扑克牌小游戏

我们可以通过上述所学,运用 List 的知识,去写一个关于扑克牌的逻辑代码(如:获取一副牌、洗牌、发牌等等)

class Card{
    private String suit;   // 花色
    private int rank;       // 牌面值
    public Card(String suit, int rank){
        this.suit=suit;
        this.rank=rank;
    }
    @Override
    public String toString() {
        return "[ "+suit+" "+rank+" ] ";
    }
}
public class TestDemo {
    public static String[] suits = {"♣", "♦", "♥", "♠"};
    // 获取一副牌
    public static List<Card> getNewCards(){
        // 存放 52 张牌
        List<Card> card = new ArrayList<>();
        for(int i=0; i<4; i++){
            for(int j=1; j<=13; j++) {
                card.add(new Card(suits[i], j));
            }
        }
        return card;
    }
    public static void swap(List<Card> card, int i, int j){
        Card tmp = card.get(i);
        card.set(i, card.get(j));
        card.set(j, tmp);
    }
    // 洗牌
    public static void shuffle(List<Card> card){
        int size = card.size();
        for(int i=size-1; i>0; i--){
            Random random = new Random();
            int randNum = random.nextInt(i);
            swap(card, i, randNum);
        }
    }
    public static void main(String[] args) {
        // 得到一副新的牌
        List<Card> cardList = getNewCards();
        System.out.println("已获取新的扑克牌");
        System.out.println("洗牌:");
        shuffle(cardList);
        System.out.println(cardList);
        System.out.println("抓牌:(3个人,每人轮流抓牌总共抓5张)");
        List<Card> hand1 = new ArrayList<>();
        List<Card> hand2 = new ArrayList<>();
        List<Card> hand3 = new ArrayList<>();
        List<List<Card>> hands = new ArrayList<>();
        hands.add(hand1);
        hands.add(hand2);
        hands.add(hand3);
        for(int i=0; i<5; i++){
            for(int j=0; j<3; j++){
                Card card = cardList.remove(0);
                hands.get(j).add(card);
            }
        }
        System.out.println("第一个人的牌:"+hand1);
        System.out.println("第二个人的牌:"+hand2);
        System.out.println("第三个人的牌:"+hand3);
    }
}
/**
结果为:
已获取新的扑克牌
洗牌:
[[ ♥ 9 ] , [ ♦ 6 ] , [ ♣ 8 ] , [ ♦ 2 ] , [ ♣ 6 ] , [ ♦ 4 ] , [ ♣ 11 ] , [ ♣ 9 ] , [ ♠ 8 ] , [ ♣ 5 ] , [ ♦ 8 ] , [ ♦ 10 ] , [ ♦ 1 ] , [ ♦ 12 ] , [ ♥ 10 ] , [ ♥ 7 ] , [ ♠ 12 ] , [ ♥ 12 ] , [ ♦ 7 ] , [ ♣ 13 ] , [ ♠ 6 ] , [ ♠ 5 ] , [ ♥ 3 ] , [ ♦ 5 ] , [ ♦ 11 ] , [ ♣ 12 ] , [ ♠ 7 ] , [ ♦ 3 ] , [ ♥ 5 ] , [ ♦ 13 ] , [ ♣ 1 ] , [ ♥ 8 ] , [ ♠ 10 ] , [ ♠ 4 ] , [ ♣ 4 ] , [ ♣ 7 ] , [ ♥ 1 ] , [ ♠ 1 ] , [ ♣ 3 ] , [ ♥ 11 ] , [ ♥ 13 ] , [ ♦ 9 ] , [ ♠ 13 ] , [ ♣ 10 ] , [ ♥ 6 ] , [ ♠ 11 ] , [ ♠ 3 ] , [ ♣ 2 ] , [ ♠ 2 ] , [ ♥ 2 ] , [ ♥ 4 ] , [ ♠ 9 ] ]
抓牌:(3个人,每人轮流抓牌总共抓5张)
第一个人的牌:[[ ♥ 9 ] , [ ♦ 2 ] , [ ♣ 11 ] , [ ♣ 5 ] , [ ♦ 1 ] ]
第二个人的牌:[[ ♦ 6 ] , [ ♣ 6 ] , [ ♣ 9 ] , [ ♦ 8 ] , [ ♦ 12 ] ]
第三个人的牌:[[ ♣ 8 ] , [ ♦ 4 ] , [ ♠ 8 ] , [ ♦ 10 ] , [ ♥ 10 ] ]
*/

上述代码中有一处代码是这样写的 List<List<Card>>,其实不难理解,这个类型其实就是 List 中存放的每个元素都是一个 List 类型的,并且每一个 List 元素中的元素都是 Card 类型,类似于二维数组。

以上就是Java集合框架之List ArrayList LinkedList使用详解刨析的详细内容,更多关于Java 集合框架的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java集合框架之Stack Queue Deque使用详解刨析

    目录 1. Stack 1.1 介绍 1.2 常见方法 2. Queue 2.1 介绍 2.2 常见方法 3. Deque 3.1 介绍 3.2 常见方法 1. Stack 1.1 介绍 Stack 栈是 Vector 的一个子类,它实现了一个标准的后进先出的栈.它的底层是一个数组. 堆栈只定义了默认构造函数,用来创建一个空栈.堆栈除了包括由 Vector 定义的所有方法,也定义了自己的一些方法. 1.2 常见方法 方法 描述 E push(E item) 压栈 E pop() 出栈 E pee

  • 简单了解java集合框架LinkedList使用方法

    代码如下 package cn.burce.List; import java.util.LinkedList; public class LinkedListdemo { // LinkedList 链表集合的特有 // 自身特点:链表底层实现,查询慢,增删快 // 子类特有功能,不能多态 public static void main(String[] args) { fun(); } public static void fun() { LinkedList<String> list =

  • Java集合框架LinkedList详解及实例

    Java集合框架LinkedList详解 LinkedList定义 package java.util; public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable{ transient int size = 0; transient Node<E> first;

  • Java 集合框架之List 的使用(附小游戏练习)

    目录 1. List 1.1 List 的常见方法 1.2 代码示例 2. ArrayList 2.1 介绍 2.2 ArrayList 的构造方法 2.3 ArrayList 底层数组的大小 3. LinkedList 3.1 介绍 3.2 LinkedList 的构造方法 4. 练习题 5. 扑克牌小游戏 1. List 1.1 List 的常见方法 1.2 代码示例 注意: 下面的示例都是一份代码分开拿出来的,上下其实是有逻辑关系的 示例一: 用 List 构造一个元素为整形的顺序表 Li

  • Java集合框架入门之泛型和包装类

    目录 1. 预备知识-泛型(Generic) 1.1 泛型的引入 1.2 泛型的分类 1.3 泛型类的定义 1.4 泛型编译的机制 2. 预备知识-包装类(Wrapper Class) 2.1 基本数据类型和包装类的对应关系 2.2 包装类介绍 2.3 装箱(boxing)和拆箱(unboxing) 2.4 自动装箱(autoboxing)和自动拆箱(autounboxing) 2.5 包装类面试题 前言: 本章主要是为了后面学习集合框架所做的知识补充.补充了泛型以及包装类两个知识,但是该章泛型

  • Java集合框架超详细小结

    目录 一:Collection集合 1.1集合概述: 1.2集合架构 1.3Collection集合常用方法 二:迭代器Iterator 2.1Iterator接口 2.2Iterator的实现原理: 2.3增强for() 2.4迭代器注意事项 三:泛型 3.1泛型概述 3.2泛型的优缺点 3.3泛型的定义与使用 泛型方法 泛型接口 3.4泛型的通配符 通配符高级使用-----受限泛型 四:Java常见数据结构 4.1栈 4.2队列 4.3数组 4.4链表 4.5红黑树 五:List集合体系 5

  • Java基础之集合框架详解

    一.前言 本节学习到的内容有以下5类,不分先后顺序: 集合Collection体系结构 List子类 与集合结合使用的迭代器对象 集合与数组的区别? 常见的一般数据结构整理 二.集合的由来? Collection List ArrayList Vector LinkedList Set hashSet treeSet 在集合没有出现之前,使用对象数组来存储对象,但是,对象数组的长度一旦确定,则不可以发生变化,所以我们希望存在一个容器就像StringBuffer一样存储字符串,同时依据传入的值的个

  • Java集合框架之List ArrayList LinkedList使用详解刨析

    目录 1. List 1.1 List 的常见方法 1.2 代码示例 2. ArrayList 2.1 介绍 2.2 ArrayList 的构造方法 2.3 ArrayList 底层数组的大小 3. LinkedList 3.1 介绍 3.2 LinkedList 的构造方法 4. 练习题 5. 扑克牌小游戏 1. List 1.1 List 的常见方法 方法 描述 boolean add(E e) 尾插 e void add(int index, E element) 将 e 插入到 inde

  • Java集合框架源码分析之LinkedHashMap详解

    LinkedHashMap简介 LinkedHashMap是HashMap的子类,与HashMap有着同样的存储结构,但它加入了一个双向链表的头结点,将所有put到LinkedHashmap的节点一一串成了一个双向循环链表,因此它保留了节点插入的顺序,可以使节点的输出顺序与输入顺序相同. LinkedHashMap可以用来实现LRU算法(这会在下面的源码中进行分析). LinkedHashMap同样是非线程安全的,只在单线程环境下使用. LinkedHashMap源码剖析 LinkedHashM

  • Java集合的定义与Collection类使用详解

    什么是集合? 概念:对象的容器,定义了对多个对象进行操作的常用方法.可实现数组的功能. 集合和数组的区别: 数组长度固定,集合长度不固定 数组可以存储基本类型和引用类型,集合只能引用类型 Collection : Collection体系结构: Collection的使用:包括增加元素.删除元素.遍历元素(两种方法)和判断 直接看代码: package com.collections; import java.util.ArrayList; import java.util.Collection

  • Java集合之Map接口与实现类详解

    目录 初识Map Map中常用方法 HashMap LinkedHashMap TreeMap HashMap和TreeMap的比较 Hashtable 集合中元素的遍历 iterator接口中的方法 Enumeration接口中的方法 初识Map Map接口没有从Collection接口继承,Map接口用于维护“键-值”对数据,这个“键-值”对就是Map中的元素,Map提供“键(Key)”到“值(value)”的映射,一个Map中键值必须是唯一的,不能有重复的键,因为Map中的“键-值”对元素

  • Java 逻辑结构与方法函数详解刨析

    ⭐前言⭐ 本文主要介绍JavaSE的逻辑结构和方法. 对一门编程语言逻辑结构和方法的理解是站在C语言之上的,建议配套C语言版本的分析一起食用 链接直达:

  • Java集合的Collection接口和List接口详解

    目录 1集合的概念 2集合的父类Collection接口 2.1常用方法 2.2遍历 3List接口 3.1List接口常用方法 3.2遍历 4集合中元素的去重 总结 1集合的概念 把集合看做是一个容器,集合不是一个类,是一套集合框架,框架体系包含很多的集合类,java api提供了 集合存储任意类型(基本包装类型,引用类型) 集合对元素的增删查改操作起来非常方便的,专门提供很多方便操作的方法 开发中经常集合来操作数据的,开发地位比较高的,考虑对数据的操作效率上的问题 2 集合的父类Collec

  • Java集合中的fail-fast(快速失败)机制详解

    简介 我们知道Java中Collection接口下的很多集合都是线程不安全的, 比如 java.util.ArrayList不是线程安全的, 因此如果在使用迭代器的过程中有其他线程修改了list,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略. 这一策略在源码中的实现是通过 modCount 域,modCount 顾名思义就是修改次数,对ArrayList 内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的 exp

  • java 集合之实现类ArrayList和LinkedList的方法

    List 的方法列表 方法名 功能说明 ArrayList() 构造方法,用于创建一个空的数组列表 add(E e) 将指定的元素添加到此列表的尾部 get(int index) 返回此列表中指定位置上的元素 size() 返回此列表中的元素数 clear() 移除此列表中的所有元素 isEmpty() 如果此列表中没有元素,则返回true remove(int index) 移除此列表中指定位置上的元素 indextof(Object o) 返回此列表中首次出现的指定元素的索引,或如果此列表不

随机推荐