Java集合详解

Posted JWei_7

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java集合详解相关的知识,希望对你有一定的参考价值。

Java集合详解

开篇解答 c++的stl容器和java集合的区别 以及相识之处

(好了 总结一句 一个是java写的 一个是c++写的 很好 就是这样 皮一手)

集合和数组的区别

一、数组声明了它容纳的元素的类型,而集合不声明。

二、数组是静态的,一个数组实例具有固定的大小,一旦创建了就无法改变容量了。而集合是可以动态扩展容量,可以根据需要动态改变大小,集合提供更多的成员方法,能满足更多的需求。

三、数组的存放的类型只能是一种(基本类型/引用类型),集合存放的类型可以不是一种(不加泛型时添加的类型是Object)。

四、数组是java语言中内置的数据类型,是线性排列的,执行效率或者类型检查都是最快的。

java集合分类

Java 集合类型分为 Collection 和 Map,它们是 Java 集合的根接口,这两个接口又包含了一些子接口或实现类。图 1 和图 2 分别为 Collection 和 Map 的子接口及其实现类。

黄色块为集合的接口,蓝色块为集合的实现类

java集合类 分点做简单介绍 以及使用 介绍 优势以及劣势 以及 基本知识点

Conllection

Collection 接口是 List、Set 和 Queue 接口的父接口,通常情况下不被直接使用。Collection
接口定义了一些通用的方法,通过这些方法可以实现对集合的基本操作。定义的方法既可用于操作 Set 集合,也可用于操作 List 和 Queue
集合。

List


这里 我们介绍一下 Arraylist和LinkedList ,stack和vector 不做过多介绍 具体用法 和stl容器的差不多。

如何使用list接口

在Java中,必须导入 java.util.List 包才能使用List。

List<Integer> numbers = new LinkedList<>();
LinkedList<Integer> numbers = new LinkedList<>();

在这里,我们已经创建Vector,ArrayList和LinkedList类的对象。现在这些对象就可以使用List接口的功能。

List方法

List接口包括Collection接口的所有方法。 这是因为Collection是List的超级接口。

Collection接口中还提供了一些常用的List接口方法:

add() - 将元素添加到列表
addAll() - 将一个列表的所有元素添加到另一个
get() - 有助于从列表中随机访问元素
iterator() - 返回迭代器对象,该对象可用于顺序访问列表的元素
set() - 更改列表的元素
remove() - 从列表中删除一个元素
removeAll() - 从列表中删除所有元素
clear() - 从列表中删除所有元素(比removeAll()效率更高)
size() - 返回列表的长度
toArray() - 将列表转换为数组
contains() - 如果列表包含指定的元素,则返回true

list接口种的集合 通用!

List接口的实现

1.LinkedList
package com.example.demo;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;


public class working 
    public static void main(String[] args) 


        //使用LinkedList类创建列表
        List<Integer> numbers = new LinkedList<>();
        //将元素添加到列表
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        System.out.println("List: " + numbers);

        //从列表中访问元素
        int number = numbers.get(2);
        System.out.println("访问元素: " + number);

        //使用indexOf()方法
        int index = numbers.indexOf(2);
        System.out.println("位置3的元素是 " + index);

        //从列表中删除元素
        int removedNumber = numbers.remove(1);
        System.out.println("删除元素: " + removedNumber);

        //将列表转为数组
        Object[] array = numbers.toArray();
        System.out.print("剩余数组元素为:");
        for(int i=0;i<array.length;i++)
            System.out.print(array[i]+" ");

        //换行
        System.out.println();
        //从列表中查询某数
        System.out.println("能不能从数组中查询到1   "+numbers.contains(1));
    


(一)LinkedList的底层是什么?

双向链表

让我们来看看底层源码

 private void linkFirst(E e) 
        final Node<E> f = first;
        final Node<E> newNode = new Node<>(null, e, f);
        first = newNode;
        if (f == null)
            last = newNode;
        else
            f.prev = newNode;
        size++;
        modCount++;
    

    /**
     * Links e as last element.
     */
    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能不能作为队列使用?

开头就说了 因为LinkedList是双向循环链表 所以它也可以当成队列,栈和双端队列来使用
首先我们先来说一下LinkedList关于队列操作的源码。

队列的基本方法

//定义
LinkedList<Integer> queue = new LinkedList<Integer>();

//添加元素
queue.add(1);

//删除队列头元素
queue.poll();

//获取队列头元素,不删除
queue.peek();

演示:

首先定义就不说了 直接看源码:

.add()//添加元素

public boolean add(E e) 
        linkLast(e); //添加在队尾
        return true;
    

.poll()//删除队列头元素

  // 删除并返回第一个节点
        // 若LinkedList的大小为0,则返回null
        public E poll() 
            if (size == 0)
                return null;
            return removeFirst();
        

.peek()//获取队列头元素,不删除

     // 返回第一个节点
        // 若LinkedList的大小为0,则返回null
        public E peek() 
            if (size == 0)
                return null;
            return getFirst();
        
(三)LinkedList能不能作为栈使用?

栈的基本方法

//定义栈
LinkedList<Integer> stack = new LinkedList<Integer>();

//将元素插入到栈顶
stack.push(1)

//取出栈顶的元素并删除栈顶的元素
stack.pop()

//获取栈顶元素,不删除
stack.peek()

演示:

源码分析如下:

.push() //将元素插入到栈顶

 // 将e插入到双向链表开头
        public void push(E e) 
            addFirst(e);
        

.pop() //取出栈顶的元素并删除栈顶的元素

// 删除并返回第一个节点
        public E pop() 
            return removeFirst();
        

.peek() //获取栈顶元素,不删除

 // 返回第一个节点
        // 若LinkedList的大小为0,则返回null
        public E peekFirst() 
            if (size == 0)
                return null;
            return getFirst();
        

(四)LinkedList作为双端队列使用

双端队列的基本方法

//定义
LinkedList<Integer> deque = new LinkedList<Integer>();

deque.addFirst();	//在队列头部添加
deque.pollFirst();	//删除头部第一个元素(等价于poll())
deque.peekFirst();	//获取头部第一个元素(等价于peek())

deque.addLast(1); 	//在队列尾部添加(等价于add())
deque.pollLast();	//删除尾部第一个元素
deque.peekLast();	//获取尾部第一个元素

演示:

.addFirst() ; //在队列头部添加

// 将元素添加到LinkedList的起始位置
        public void addFirst(E e) 
            addBefore(e, header.next);
        

.pollFirst() ; //删除头部第一个元素(等价于poll())

// 删除并返回第一个节点
        // 若LinkedList的大小为0,则返回null
        public E pollFirst() 
            if (size == 0)
                return null;
            return removeFirst();
        


.peekFirst() ; //获取头部第一个元素(等价于peek())

          // 返回第一个节点
        // 若LinkedList的大小为0,则返回null
        public E peekFirst() 
            if (size == 0)
                return null;
            return getFirst();
        

.addLast() ; //在队列尾部添加(等价于add())

  // 将元素添加到LinkedList的结束位置
        public void addLast(E e) 
            addBefore(e, header);
        

.pollLast() ; // 删除并返回最后一个节点

     // 删除并返回最后一个节点
        // 若LinkedList的大小为0,则返回null
        public E pollLast() 
            if (size == 0)
                return null;
            return removeLast();
        

.peekLast() ; //获取尾部第一个元素

        // 返回最后一个节点
        // 若LinkedList的大小为0,则返回null
        public E peekLast() 
            if (size == 0)
                return null;
            return getLast();
        


总结

底层数据结构是链表,查询慢,增删快,线程不安全,效率高,可以存储重复元素

课后问题:
为什么LinkedList是线程不安全的?


2.ArrayList
package com.example.demo;

import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Vector;

public class working 
    public static void main(String[] args) 
        //使用ArrayList类创建列表
        List<Integer> numbers = new ArrayList<>();  // <里面不能使用基本类型>   这个在泛型的时候 会说到  要用包装类

        //将元素添加到列表
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        System.out.println("List: " + numbers);

        //从列表中访问元素
        int number = numbers.get(2);
        System.out.println("访问元素: " + number);

        //从列表中删除元素
        int removedNumber = numbers.remove(1);
        System.out.println("删除元素: " + removedNumber);

        //将列表转为数组
        Object[] array = numbers.toArray();
        System.out.print("剩余数组元素为:");
        for(int i=0;i<array.length;i++)
            System.out.print(array[i]+" ");

        //换行
        System.out.println();
        //从列表中查询某数
        System.out.println("能不能从数组中查询到1   "+numbers.contains(1));
    

(一)ArrayList的底层是数组,数组的名称是什么?类型是什么?

名称是elementData,类型是Object[],所以ArrayList里面可以存放任意类型的元素。

(二)扩容机制

我们都知道Arraylist是一个动态的数组(说白了 也就是 可以根据内容来确定数组的大小)

ArrayList在JDK1.8与JDK1.7底层区别

JDK1.7:ArrayList像 饿汉式 ,直接创建一个初始容量为10的数组,当数组的长度不能容下所添加的内容时候,数组会扩容至原大小的1.5倍

JDK1.8:ArrayList像
懒汉式,一开始创建一个长度为0的数组,当添加第一个元素时再创建一个始容量为10的数组,当数组的长度不能容下所添加的内容时候,数组会扩容至原大小的1.5倍

(三)ArrayList里面可以存null吗?

可以,ArrayList存储的类型是object,null属于object类型。

private void printList() 
    List<Integer> dataList = new ArrayList<>();
    dataList.add(1);
    dataList.add(null);
    dataList.add(null);

    for (Integer d : dataList) 
        System.out.println(d);
    

    System.out.println("------------------------");

    for (Integer d : dataList) 
        if (d != null)  // 需要这个判断吗?
            System.out.println(d);
        
    



输出:

1
null
null
------------------------
1
(四)ArrayList的底层是数组,它和数组有什么区别吗?

Array 可以包含基本类型对象类型,ArrayList 只能包含对象类型

Array 大小是固定的,ArrayList 的大小是动态变化的。

ArrayList 提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。

总结

底层数据结构是数组,查询快,增删慢,线程不安全,效率高,可以存储重复元素

课后问题: 为什么说ArrayList是线程不安全的?


面试常见问题

(一)ArrayList与Vector的区别?
(二)ArrayList与LinkedList的区别有哪些?
(三)在调用ArrayList的remove(int index)方法时,执行流程是怎样的?
(四)在ArrayList的增、删、改、查中,什么地方会修改modCount?
(五)ArrayList的时间复杂度是多少?

答案在以前写的Arraylist源码分析中:https://blog.csdn.net/qq_54729417/article/details/121066332

Queue

实现队列的类

由于Queue是一个接口,因此我们无法提供它的直接实现。

为了使用Queue的功能,我们需要使用实现它的类:

  • ArrayDeque
  • LinkedList
  • PriorityQueue

队列数据结构的工作流程

在队列中,以先进先出的方式存储和访问元素。也就是说,从后面添加元素,从前面删除元素。

Queue的方法

Queue接口的一些常用方法是:

  • add() - 将指定的元素插入队列。如果任务成功,则add()返回true,否则将引发异常。
  • offer() - 将指定的元素插入队列。如果任务成功,则offer()返回true,否则返回false。
  • element() - 返回队列的开头。如果队列为空,则引发异常。
  • peek() - 返回队列的开头。 如果队列为空,则返回null。
  • remove() - 返回并删除队列的头部。如果队列为空,则引发异常。
  • poll() - 返回并删除队列的开头。 如果队列为空,则返回null。

相信大家都看到了 这里很多方法都和相似 那么 它们之间有什么区别呢?

offer,add区别:

一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。
这时新的 offer 方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer()
返回的 false。

poll,remove区别:

remove() 和 poll() 方法都是从队列中删除第一个元素(head)。remove() 的行为与 Collection接口的版本相似,

但是新的 poll() 方法在用空集合调用时不是抛出异常,只是返回 null。因此新的方法更适合容易出现异常条件的情况。

peek,element区别:

element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element()
抛出一个异常,而 peek() 返回 null。

Set

如何使用set?

在Java中,必须导入java.util.Set包才能使用Set。

//使用HashSet实现Set
Set<String> animals = new HashSet<>();

set方法

Set接口中还提供了Collection接口的一些常用方法:

  • add() - 将指定的元素添加到集合中
  • addAll() - 将指定集合的所有元素添加到集合中
  • iterator() -返回一个迭代器,该迭代器可用于顺序访问集合中的元素
  • remove() - 从集合中移除指定的元素
  • removeAll() - 从存在于另一个指定集合中的集合中删除所有元素
  • keepAll() -保留集合中所有还存在于另一个指定集合中的所有元素
  • clear() - 从集合中删除所有元素
  • size() - 返回集合的长度(元素数)
  • toArray() - 返回包含集合中所有元素的数组
  • contains() - 如果集合包含指定的元素,则返回true
  • containsAll() - 如果集合包含指定集合的所有元素,则返回true
  • hashCode() -返回哈希码值(集合中元素的地址)

Set集合运算

Java Set接口允许我们执行基本的数学集合运算,例如并集,交集和子集。

  1. Union - 为了得到两个集合x和y的并集,我们可以使用x.addAll(y)
  2. Intersection - 要获得两个集合x和y的交集,我们可以使用x.retainAll(y)
  3. Subset - 要检查x是否是y的子集,我们可以使用y.containsAll(x)

Set接口的实现

1.HashSet
package com.example.demo;

import java.util.*;

public class working 
    public以上是关于Java集合详解的主要内容,如果未能解决你的问题,请参考以下文章

Java集合类详解

JAVA常用集合解析

Java集合

Java中List详解

java提高---queue集合

java读取xml文件并放入集合,然后返回集合数组。