【Java系列】:集合(上)

如果你不相信努力和时光,那么成果就会是第一个选择辜负你的。不要去否定你自己的过去,也不要用你的过去牵扯你现在的努力和对未来的展望。不是因为拥有希望你才去努力,而是去努力了,你才有可能看到希望的光芒。【Java系列】:集合(上),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

在这里插入图片描述

📚1.集合的理解

前面我们保存多个数据使用的是数组,那么数组有不足的地方呢?

📒1.1 数组

  1. 长度开始时必须指定,而且一旦指定,不能更改
  2. 保存的必须为同一类型的元素
  3. 使用数组进行增加/删除元素的示意代码-比较麻烦

分析:写出Person数组扩容示意代码。

Person[l pers = new Person[1];//大小是1
per[0]=new Person();

如何增加新的Person对象?

Person[l pers2 = new Person[pers.length+1];//新创建数组
for()//拷贝pers数组的元素到pers2
pers2[pers2.length-1]=new Person()://添加新的对象

📒1.2 集合

  1. 可以动态保存任意多个对象,使用比较方便!
  2. 提供了一系列方便的操作对象的方法:add、remove、set、get等
  3. 使用集合添加,删除新元素的代码简洁了

📚2.集合的框架体系

Java 的集合类很多,主要分为两大类Collection和Map

  1. 集合主要是两组(单列集合,双列集合)
  2. Collection接口有两个重要的子接口 List Set,他们的实现子类都是单列集合
  3. Map接口的实现子类是双列集合,存放的 K-V
  4. 把梳理的两张图记住

🍀Collection接口

在这里插入图片描述

🍀Map接口

在这里插入图片描述
☕️代码示例:

import java.util.ArrayList;
import java.util.HashMap;

public class Collection_ {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        //老韩解读
        //1. 集合主要是两组(单列集合 , 双列集合)
        //2. Collection 接口有两个重要的子接口 List Set , 他们的实现子类都是单列集合
        //3. Map 接口的实现子类 是双列集合,存放的 K-V
        //4. 梳理的两张图记住
        //Collection
        //Map
        ArrayList arrayList = new ArrayList();
        arrayList.add("jack");
        arrayList.add("tom");
        HashMap hashMap = new HashMap();
        hashMap.put("NO1", "北京");
        hashMap.put("NO2", "上海");
    }
}

📚3.Collection 接口和常用方法

📒3.1 Collection 接口实现类的特点

1. Collection类是继承自lterable类的。

public interface Collection<E> extends lterable<E>

2. collection实现子类可以存放多个元素,每个元素可以是Object
3. 有些Collection的实现类,可以存放重复的元素,有些不可以
4. 有些Collection的实现类,有些是有序的(List),有些不是有序(Set)
5. Collection接口没有直接的实现子类,是通过它的子接口Set 和 List来实现的
☕️代码示例:

import java.util.ArrayList;
import java.util.List;

public class CollectionMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        List list = new ArrayList();
        // add:添加单个元素
        list.add("jack");
        list.add(10);//list.add(new Integer(10))
        list.add(true);
        System.out.println("list=" + list);//list=[jack, 10, true]
        // remove:删除指定元素
        //list.remove(0);//删除第一个元素
        list.remove(true);//指定删除某个元素
        System.out.println("list=" + list);//list=[jack, 10]
        // contains:查找元素是否存在
        System.out.println(list.contains("jack"));//T
        // size:获取元素个数
        System.out.println(list.size());//2
        // isEmpty:判断是否为空
        System.out.println(list.isEmpty());//F
        // clear:清空
        list.clear();
        System.out.println("list=" + list);//list=[]
        // addAll:添加多个元素
        ArrayList list2 = new ArrayList();
        list2.add("红楼梦");
        list2.add("三国演义");
        list.addAll(list2);
        System.out.println("list=" + list);//list=[红楼梦, 三国演义]
        // containsAll:查找多个元素是否都存在
        System.out.println(list.containsAll(list2));//T
        // removeAll:删除多个元素
        list.add("聊斋");
        list.removeAll(list2);
        System.out.println("list=" + list);//[聊斋]
        // 说明:以 ArrayList 实现类来演示. }
    }
}

☕️代码运行:

list=[jack, 10, true]
list=[jack, 10]
true
2
false
list=[]
list=[红楼梦, 三国演义]
true
list=[聊斋]

📒3.2 Collection 接口遍历元素方式

💡3.2.1 方法一:使用 Iterator(迭代器)

💭基本介绍:
在这里插入图片描述
1. Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。
2. 所有实现了Collection接口的集合类都有一个iterator()方法,用以返回
一个实现了Iterator接口的对象,即可以返回一个迭代器。

在这里插入图片描述

3. Iterator的结构
在这里插入图片描述
在这里插入图片描述

4. Iterator仅用于遍历集合,Iterator本身并不存放对象。

💭Iterator接口的方法:
在这里插入图片描述

💭代码示例
Book类:

class Book {
    private String name;
    private String author;
    private double price;

    public Book(String name, String author, double price) {
        this.name = name;
        this.author = author;
        this.price = price;
    }

    public String getName() {
        return name;
    }

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

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }
}

主类:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionIterator {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Collection col = new ArrayList();

        col.add(new Book("三国演义", "罗贯中", 10.1));
        col.add(new Book("小李飞刀", "古龙", 5.1));
        col.add(new Book("红楼梦", "曹雪芹", 34.6));
        //System.out.print("col="+col);
        //现在我们需要遍历col集合
        //1.先得到 col对应的迭代器
        Iterator iterator= col.iterator();
        //2.使用while循环遍历
        while (iterator.hasNext()){//判断是否还有数据
            //返回下一个元素,类型是Object
            Object obj=iterator.next();
            System.out.println("obj="+obj);
        }
        //3.当退出while循环后,这时iterator迭代器,指向最后的元素
        // iterator.next();//NoSuchElementException
        //4. 如果希望再次遍历,需要重置我们的迭代器
        iterator = col.iterator();
        System.out.println("===第二次遍历===");
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println("obj=" + obj);
        }
    }
}

运行结果:

obj=Book{name='三国演义', author='罗贯中', price=10.1}
obj=Book{name='小李飞刀', author='古龙', price=5.1}
obj=Book{name='红楼梦', author='曹雪芹', price=34.6}

💭分析:
上述代码中使用迭代器的过程:
第一个

//1.先得到 col对应的迭代器
Iterator iterator= col.iterator();        

第二个

//2.使用while循环遍历
while (iterator.hasNext()){//判断是否还有数据
    //返回下一个元素,类型是Object
    Object obj=iterator.next();
    System.out.println("obj="+obj);
}

这里告诉大家一个快速生成迭代器while循环的快捷键:itit
显示所有的快捷键的的快捷键:ctrl + j

💭另外的细节:
1.当退出while循环后,这时iterator迭代器,指向最后的元素

iterator.next();//NoSuchElementException

2.如果希望再次遍历,需要重置我们的迭代器


iterator = col.iterator();
 System.out.println("===第二次遍历===");
 while (iterator.hasNext()) {
     Object obj = iterator.next();
     System.out.println("obj=" + obj);
 }

💡3.2.2 方法二:增强for循环

💭基本介绍:
增强for循环,可以代替iterator迭代器,特点:增强for就是简化版的iterator本质一样,只能用于遍历集合或数组
💭基本语法:

for(元素类型元素名:集合名或数组名){
	访问元素
}

💭代码示例:

import java.util.ArrayList;
import java.util.Collection;

public class 增强for {
    public static void main(String[] args) {
        Collection col = new ArrayList();

        col.add(new Book("三国演义", "罗贯中", 10.1));
        col.add(new Book("小李飞刀", "古龙", 5.1));
        col.add(new Book("红楼梦", "曹雪芹", 34.6));

        //1.使用增强for,在Collection集合
        //2.底层依旧是迭代器
        //3.增强for就是简化版的迭代器
        for(Object book:col){
            System.out.println("book"+book);
        }
        //增强for,也可以直接在数组中使用
        int[] nums={1,2,3,4};
        for(int i:nums){
            System.out.println(i);
        }
    }
}

💭运行结果:

bookBook{name='三国演义', author='罗贯中', price=10.1}
bookBook{name='小李飞刀', author='古龙', price=5.1}
bookBook{name='红楼梦', author='曹雪芹', price=34.6}
1
2
3
4

📚4.List 接口和常用方法

📒4.1List接口的基本介绍

  1. List 接口是 Collection接口的子接口
  2. List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复

import java.util.ArrayList;
import java.util.List;

public class List_ {
    public static void main(String[] args) {
        //1. List 集合类中元素有序(即添加顺序和取出顺序一致)、且可重复 [案例]
        List list = new ArrayList();
        list.add("jack");
        list.add("tom");
        list.add("mary");
        list.add("hj");
        list.add("tom");
        System.out.println("list=" + list);//list=[jack, tom, mary, hj, tom]

        //2. List 集合中的每个元素都有其对应的顺序索引,即支持索引
        // 索引是从 0 开始的
        System.out.println(list.get(3));//hj
    }
}

运行结果:

list=[jack, tom, mary, hj, tom]
hj

  1. List集合中的每个元素都有其对应的顺序索引,即支持索引
  2. List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
  3. JDK API中List接口的实现类有:
    在这里插入图片描述

📒4.2 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在集合中首次出现的位置

  5. int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置

  6. Object remove(int index):移除指定index位置的元素,并返回此元素

  7. Object set(int index, Object ele):设置指定index位置的元素为ele 相当于是替换.

  8. List subList(int fromlndex, int tolndex):返回从fromIndex到 tolndex位置的子集合

import java.util.ArrayList;
import java.util.List;

public class ListMethod {
    public static void main(String[] args) {
        List list=new ArrayList();
        list.add("张三丰");
        list.add("贾宝玉");
        //增:add(),删:remove(),改:set(),查:get().
        // void add(int index, Object ele):在 index 位置插入 ele 元素
        //在 index = 1
        list.add(1,"胡坚");
        System.out.println("list="+list);//list=[张三丰, 胡坚, 贾宝玉]
        // boolean addAll(int index, Collection eles):从 index 位置开始将 eles 中的所有元素添加进来
        List list2 = new ArrayList();
        list2.add("jack");
        list2.add("tom");
        list.addAll(1, list2);
        System.out.println("list=" + list);//list=[张三丰, jack, tom, 胡坚, 贾宝玉]
        // Object get(int index):获取指定 index 位置的元素
        System.out.println(list.get(0));//张三丰
        // int indexOf(Object obj):返回 obj 在
        System.out.println(list.indexOf("tom"));//2
        // int lastIndexOf(Object obj):返回 obj 在当前集合中末次出现的位置
        list.add("胡坚");
        System.out.println("list=" + list);
        System.out.println(list.lastIndexOf("胡坚"));//5
        // Object remove(int index):移除指定 index 位置的元素,并返回此元素
        list.remove(0);
        System.out.println("list=" + list);
        // Object set(int index, Object ele):设置指定 index 位置的元素为 ele , 相当于是替换.
        list.set(1, "玛丽");
        System.out.println("list=" + list);//list=[jack, 玛丽, 胡坚, 贾宝玉, 胡坚]
        // List subList(int fromIndex, int toIndex):返回从 fromIndex 到 toIndex 位置的子集合
        // 注意返回的子集合 fromIndex <= subList < toIndex
        List returnlist = list.subList(0, 2);
        System.out.println("returnlist=" + returnlist);//returnlist=[jack, 玛丽]

    }
}

📒4.3 List 接口练习

添加10个以上的元素(比如String “hello” ),在2号位插入一个元素”hj”,获得第5个元素,删除第6个元素,修改第7个元素,在使用迭代器遍历集合,要求:使用List的实现类ArrayList完成。

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListExercise {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        /*
        添加 10 个以上的元素(比如 String "hello" ),在 2 号位插入一个元素"韩顺平教育",
        获得第 5 个元素,删除第 6 个元素,修改第 7 个元素,在使用迭代器遍历集合,
        要求:使用 List 的实现类 ArrayList 完成。
        */
        List list = new ArrayList();
        for (int i = 0; i < 12; i++) {
            list.add("hello" + i);
        }
        System.out.println("list=" + list);
        //在 2 号位插入一个元素"韩顺平教育"
        list.add(1, "韩顺平教育");
        System.out.println("list=" + list);
        //获得第 5 个元素
        System.out.println("第五个元素=" + list.get(4));
        //删除第 6 个元素
        list.remove(5);
        System.out.println("list=" + list);
        //修改第 7 个元素
        list.set(6, "三国演义");
        System.out.println("list=" + list);
        //在使用迭代器遍历集合
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println("obj=" + obj);
        }
    }
}

📒4.4 List 的三种遍历

方式一:使用iterator

lterator iter = col.iterator();
while(iter.hasNext(){
	Object o = iter.next(;
}

方式二:使用增强for

for(Object o:col){}

方式三:使用普通for

for(int i=0;i<list.size();i++) {
	Object object = list.get(i);
	System.out.println(object);
}
import java.util.*;

public class ListFor {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        //List 接口的实现子类 Vector LinkedList
        //List list = new ArrayList();
        //List list = new Vector();
        List list = new LinkedList();
        list.add("jack");
        list.add("tom");
        list.add("鱼香肉丝");
        list.add("北京烤鸭子");
        //遍历
        //1. 迭代器
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println(obj);
        }
        System.out.println("=====增强 for=====");
        //2. 增强 for
        for (Object o : list) {
            System.out.println("o=" + o);
        }
        System.out.println("=====普通 for====");
        //3. 使用普通 for
        //长度使用list.size()
        for (int i = 0; i < list.size(); i++) {
            System.out.println("对象=" + list.get(i));
        }
    }
}

说明:使用LinkedList完成使用方式和ArrayList一样

📒4.5 实现类的练习

在这里插入图片描述
Book类:

class Book {
    private String name;
    private String author;
    private double price;

    public Book(String name, String author, double price) {
        this.name = name;
        this.author = author;
        this.price = price;
    }

    public String getName() {
        return name;
    }

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

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price
                ;
    }
}

实现类

import java.util.ArrayList;
import java.util.List;

public class 练习 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(new Book("红楼梦", "曹雪芹", 100));
        list.add(new Book("西游记", "吴承恩", 10));
        list.add(new Book("水浒传", "施耐庵", 19));
        list.add(new Book("三国", "罗贯中", 80));
        //排序
        sort(list);
        //输出
        for(Object o:list){
            System.out.println(o);
        }
    }
    public static void sort(List list){
        int listsize=list.size();
        for(int i=0;i<listsize-1;i++){
            for(int j=0;j<listsize-1-i;j++){
                Book book1=(Book) list.get(j);
                Book book2=(Book) list.get(j+1);
                if(book1.getPrice()>book2.getPrice()){
                    list.set(j,book2);
                    list.set(j+1,book1);
                }
            }
        }
    }
}

运行结果:

name='西游记', author='吴承恩', price=10.0
name='水浒传', author='施耐庵', price=19.0
name='三国', author='罗贯中', price=80.0
name='红楼梦', author='曹雪芹', price=100.0

📚5.ArrayList 底层结构和源码分析

📒5.1 ArrayList 的注意事项

1. permits all elements, including null ,ArrayList可以加入null,并且多个

import java.util.ArrayList;

public class ArrayListDetail {
    public static void main(String[] args) {
        ArrayList arrayList=new ArrayList();
        arrayList.add(null);
        arrayList.add("hj");
        arrayList.add(null);
        System.out.println(arrayList);//[null, hj, null]
    }
}

2. ArrayList是由数组来实现数据存储的
3. ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高)看源码,没有synchronized.在多线程情况下,不建议使用ArrayList.
在这里插入图片描述

📒5.2 ArrayList 的底层操作机制源码分析(重点)

先说结论,再分析源码(示意图)

  1. ArrayList中维护了一个0bject类型的数组elementData. [debug看源码]
transient Object[] elementData; //transient表示瞬间,短暂的,表示该属性不会被序列号

在这里插入图片描述

  1. 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍。

在这里插入图片描述

  1. 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。

在这里插入图片描述

建议:自己去debug一把我们的ArrayList的创建和扩容的流程.

import java.util.ArrayList;

@SuppressWarnings({"all"})
public class ArrayListSource {
    public static void main(String[] args) {
        //解读源码
        //注意,注意,注意,Idea 默认情况下,Debug 显示的数据是简化后的,如果希望看到完整的数据
        //需要做设置. //使用无参构造器创建 ArrayList 对象
        ArrayList list = new ArrayList();
        //使用 for 给 list 集合添加 1-10 数据
        for (int i = 1; i <= 10; i++) {
            list.add(i);
        }
        //使用 for 给 list 集合添加 11-15 数据
        for (int i = 11; i <= 15; i++) {
            list.add(i);
        }
        list.add(100);
        list.add(200);
        list.add(null);
    }
}

💡源码分析

建议看视频讲解韩顺平Java_ArrayList底层源码
分析使用无参构造器,创建和使用ArrayList的源码:
首先在ArrayList创建的语句加上断点,再debug上面的代码。(不会调试的去学习一下再来看)
点击step into,就会跳转至ArrayList源码。
在这里插入图片描述
在这里插入图片描述
进入第一个for循环后会调用list.add():
在这里插入图片描述
跳入ensureCapacityInternal(size + 1);
在这里插入图片描述
再跳入ensureExplicitCapacity(int mincapacity)
在这里插入图片描述
看一下grow(int minCapacity)
在这里插入图片描述
在这里插入图片描述

分析使用有参构造器,创建和使用ArrayList 的源码:
在这里插入图片描述
在这里插入图片描述

📚6.Vector 底层结构和源码剖析

📒6.1Vector基本介绍

1. Vector类的定义说明
在这里插入图片描述
2. Vector底层也是一个对象数组

protected object[] elementData;

3. Vector是线程同步的,即线程安全, Vector类的操作方法带有

synchronizedpublic synchronized E get(int index) {
	if (index >= elementCount)
		throw new ArraylndexOutOfBoundsException(index);
	return elementData(index);
}

4. 在开发中,需要线程同步安全时,考虑使用Vector

📒6.2Vector底层结构和ArrayList的比较

在这里插入图片描述

📒6.3分析

import java.util.Vector;

@SuppressWarnings({"all"})
public class Vector_ {
    public static void main(String[] args) {
        //无参构造器
        //有参数的构造
        Vector vector = new Vector(8);
        for (int i = 0; i < 10; i++) {
            vector.add(i);

        }
        vector.add(100);
        System.out.println("vector=" + vector);
        //解读源码
        //1. new Vector() 底层
        /*
        public Vector() {
        this(10);
        }
        补充:如果是 Vector vector = new Vector(8);
        走的方法:
        public Vector(int initialCapacity) {
        this(initialCapacity, 0);
        }
        2. vector.add(i)
        2.1 //下面这个方法就添加数据到 vector 集合
        public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
        }
        2.2 //确定是否需要扩容 条件 : minCapacity - elementData.length>0
        private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
        grow(minCapacity);
        }
        2.3 //如果 需要的数组大小 不够用,就扩容 , 扩容的算法
        //newCapacity = oldCapacity + ((capacityIncrement > 0) ?
        // capacityIncrement : oldCapacity);
        //就是扩容两倍. private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
        capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
        }
        */
    }
}

📚7.LinkedList底层结构(维护了一个双向链表)

📒7.1LinkedList的底层操作机制

  1. LinkedList底层维护了一个双向链表.

  2. LinkedList中维护了两个属性first和last分别指向首节点和尾节点
    在这里插入图片描述

  3. 每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表.

  4. 所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高

📒7.2 模拟一个简单的双向链表

在这里插入图片描述

定义一个 Node 类,Node 对象 表示双向链表的一个结点:

//定义一个 Node 类,Node 对象 表示双向链表的一个结点
class Node {
    public Object item; //真正存放数据
    public Node next; //指向后一个结点
    public Node pre; //指向前一个结点

    public Node(Object name) {
        this.item = name;
    }

    public String toString() {
        return "Node name=" + item;
    }
}

模拟一个简单的双向链表:

public class LinkedList01 {
    public static void main(String[] args) {
        //模拟一个简单的双向链表
        Node jack = new Node("jack");
        Node tom = new Node("tom");
        Node hsp = new Node("老韩");

        //连接三个结点,形成双向链表
        //jack->tom->hsp
        jack.next = tom;
        tom.next = hsp;
        //hsp->tom->jack
        hsp.pre = tom;
        tom.pre = jack;

        Node first = jack;//让 first 引用指向 jack,就是双向链表的头结点
        Node last = hsp; //让 last 引用指向 hsp,就是双向链表的尾结点
    }
}

演示从头到尾进行遍历和从头到尾进行遍历

public class LinkedList01 {
    public static void main(String[] args) {
        //模拟一个简单的双向链表
        Node jack = new Node("jack");
        Node tom = new Node("tom");
        Node hsp = new Node("老韩");

        //连接三个结点,形成双向链表
        //jack->tom->hsp
        jack.next = tom;
        tom.next = hsp;
        //hsp->tom->jack
        hsp.pre = tom;
        tom.pre = jack;

        Node first = jack;//让 first 引用指向 jack,就是双向链表的头结点
        Node last = hsp; //让 last 引用指向 hsp,就是双向链表的尾结点

        //演示从头到尾进行遍历
        while (true) {
            if (first == null) {
                break;
            }
            //输出first的信息
            System.out.println(first);
            //Node name=jack
            //Node name=tom
            //Node name=老韩
            first = first.next;
        }
        //演示从尾到头的遍历
        while (true) {
            if (last == null) {
                break;
            }
            System.out.println(last);
            //Node name=老韩
            //Node name=tom
            //Node name=jack
            last = last.pre;
        }
    }
}

运行结果:

Node name=jack
Node name=tom
Node name=老韩
Node name=老韩
Node name=tom
Node name=jack

演示链表的添加对象(数据):

public class LinkedList01 {
    public static void main(String[] args) {
        //模拟一个简单的双向链表
        Node jack = new Node("jack");
        Node tom = new Node("tom");
        Node hsp = new Node("老韩");

        //连接三个结点,形成双向链表
        //jack->tom->hsp
        jack.next = tom;
        tom.next = hsp;
        //hsp->tom->jack
        hsp.pre = tom;
        tom.pre = jack;

        Node first = jack;//让 first 引用指向 jack,就是双向链表的头结点
        Node last = hsp; //让 last 引用指向 hsp,就是双向链表的尾结点
        //演示链表的添加对象/数据,是多么的方便
        //要求,是在tom和hsp之间直接插入一个对象 smith
        //1. 先创建一个 Node 结点,name 就是 smith
        Node smith = new Node("smith");
        //下面就把 smith 加入到双向链表了
        smith.next = hsp;
        smith.pre = tom;
        hsp.pre = smith;
        tom.next = smith;
        //让 first 再次指向 jack
        first = jack;//让 first 引用指向 jack,就是双向链表的头结点
        System.out.println("===从头到尾进行遍历===");
        while (true) {
            if (first == null) {
                break;
            }
            //输出 first 信息
            System.out.println(first);
            first = first.next;
        }
        last = hsp; //让 last 重新指向最后一个结点
        //演示,从尾到头的遍历
        System.out.println("====从尾到头的遍历====");
        while (true) {
            if (last == null) {
                break;
            }
            //输出 last 信息
            System.out.println(last);
            last = last.pre;
        }
    }
}

在这里插入图片描述

📒7.3 LinkedList 的增删改查案例

import java.util.Iterator;
import java.util.LinkedList;

@SuppressWarnings({"all"})
public class LinkedListCRUD {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);
        System.out.println("linkedList=" + linkedList);//linkedList=[1, 2, 3]
        //演示一个删除结点的
        linkedList.remove(); // 这里默认删除的是第一个结点
        //linkedList.remove(2);
        System.out.println("linkedList=" + linkedList);//linkedList=[2, 3]
        //修改某个结点对象
        linkedList.set(1, 999);
        System.out.println("linkedList=" + linkedList);//linkedList=[2, 999]
        //得到某个结点对象
        //get(1) 是得到双向链表的第二个对象
        Object o = linkedList.get(1);
        System.out.println(o);//999
        //因为 LinkedList 是 实现了 List 接口, 遍历方式
        System.out.println("===LinkeList 遍历迭代器====");
        Iterator iterator = linkedList.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println("next=" + next);
        }
        System.out.println("===LinkeList 遍历增强 for====");
        for (Object o1 : linkedList) {
            System.out.println("o1=" + o1);
        }
        System.out.println("===LinkeList 遍历普通 for====");
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i));
        }
    }
}

📒7.4 源码分析

建议看视频讲解:韩顺平Java_LinkedList源码图解

创建:

LinkedList linkedList = new LinkedList();

调用无参构造器 public LinkedList() {}

增加:

执行 添加
public boolean add (E e){
    linkLast(e);
    return true;
}
       
将新的结点,加入到双向链表的最后
void linkLast (E e){
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

删除:

linkedList.remove(); // 这里默认删除的是第一个结点
 1. 执行 removeFirst
 public E remove() {
 return removeFirst();
 }
 2. 执行
 public E removeFirst() {
	 final Node<E> f = first;
	 if (f == null)
		 throw new NoSuchElementException();
	 return unlinkFirst(f);
 }
 3. 执行 unlinkFirst, 将 f 指向的双向链表的第一个结点拿掉
 private E unlinkFirst(Node<E> f) {
	 // assert f == first && f != null;
	 final E element = f.item;
	 final Node<E> next = f.next;
	 f.item = null;
	 f.next = null; // help GC
	 first = next;
	 if (next == null)
	 	last = null;
	 else
	 	next.prev = null;
	 size--;
	 modCount++;
	 return element;
 }

📒7.5 ArrayList 和 LinkedList 的比较

在这里插入图片描述
如何选择ArrayList和LinkedList:

  1. 如果我们改查的操作多,选择ArrayList
  2. 如果我们增删的操作多,选择LinkedList
  3. 一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList
  4. 在一个项目中,根据业务灵活选择,也可能这样,一个模块使用的是ArrayList,另外一个模块是LinkedList,也就是说,要根据业务来进行选择

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/199751.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!