首页 > 编程语言 >Java 集合框架之Collection,一文解决

Java 集合框架之Collection,一文解决

时间:2022-10-01 15:55:53浏览次数:72  
标签:元素 Java 一文 ArrayList Object list Collection add 集合

 

JDK提供了一些特殊的类,这些类可以存储任意类型的对象,并且长度可变,在Java中这些被称为集合。按照存储结构可以分为两大类,单列集合Collection和双列集合

常用集合类如下

 

 

Collection

Collection为单列集合类的跟接口,用于存储一些列符合某种规则的元素。有三个重要的子接口,分别是ListSet以及Queue

  • List特点是有序、可重复;Set特点是元素无序且不可重复。
  • List接口的主要实现类有ArrayListLinkListSet接口的主要实现类有HashSetTreeSet

 

方法声明

描述

boolean add(Object o)

向集合添加一个元素

boolean addAll(Collection c)

将指定的Collection中所有元素添加到该集合中

void clear

删除该集合中的所有元素

boolean remove(Object o)

删除该集合中的指定元素

boolean removeALL(Collection c)

删除该集合中所有元素

boolean isEmpty()

判断集合是否为空

boolean contains(Object o)

判断集合是否包含某个元素

boolean containsAll(Collection c)

判断该集合是否包含某个集合中的所有元素

Iterator iterator()

返回在该集合的元素上进行迭代的迭代器,用于遍历该集合的所有元素

int size()

获取该集合的元素个数

 

List

List集合特点:线性存储,有序,可重复的;并且List集合的每个元素都有其对应的顺序索引,即支持索引,索引从0开始。

list不但继承了Collection接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法。

void add(int index, Object element)

将元素element插入到List集合的index处

void addAll(int index, Collection c)

将集合c所包含的所有元素插入到List集合的index处

Object get(int index)

返回集合索引index处的元素

Object remove(int index)

删除index索引处的元素

Object set(int index, Object element)

将索引index处的元素替换为element对象,并将替换后的元素返回

int indexOf(Object o)

返回对象o在List集合中出现的位置索引

int lastIndexOf(Object o)

返回对象o在List集合中最后一次出现的位置索引

List subList(int fromIndex, int toIndex)

返回从索引fromIndex(包括)到toIndex(不包括)处所有元素组成的子集合

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

public class Demo01 {
    public static void main(String[] args) {
        List list = new ArrayList();//这里定义时没有指定存储类型如List<String> list  = new ArrayList<>();默认可以存储任意类型,如果表明String,那么就只能存储String
        list.add("xml");
        list.add(123);
        list.add('a');
        System.out.println(list);

        Iterator iterator = list.iterator();
        while (iterator.hasNext()){
            Object obj = iterator.next();
            System.out.println(obj);
        }

        for (Object obj : list){
            System.out.println(obj);
        }

        System.out.println(list.toArray());
    }
}

ArrayList

ArrayListList接口的一个实现类,也是程序中一种最常见的集合。

  • ArrayList可以存放null值并且可以存放多个
  • ArrayList底层使用数组实现的
    • ArrayList扩容机制:
    • ArrayList中维护了一个Object类型的数组elementData
    • 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第一次添加,则扩容为10;如果需要再次扩容,则扩容大小为elementData的1.5倍
    • 如果使用指定大小的构造器,则初始容量为指定的大小,再次扩容则为elementData的1.5倍
    • https://blog.csdn.net/weixin_42621338/article/details/82080167?spm=1001.2014.3001.5502
  • ArrayList是线程不安全的,不过执行效率高。多线程下,不建议使用该集合。

 

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

public class Demo01 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("xml");
        list.add(123);
        list.add('a');
        list.add("xml");
        System.out.println(list);

        Iterator iterator = list.iterator();
        while (iterator.hasNext()){
            Object obj = iterator.next();
            System.out.println(obj);
        }

        for (Object obj : list){
            System.out.println(obj);
        }

        System.out.println(list.toArray());
    }
}

LinkedList

LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度较慢。

另外,它还提供了List接口没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用(Java中使用的双向链表)

  • LinkedList底层实现了双向链表和双端队列的特点
    • LinkedList底层维护了一个双向链表
    • LinkedList中维护了两个属性first和last,分别指向首节点和尾节点
    • 每个节点里面维护了prev、next、item三个属性;prev:指向前一个、通过next指向后一个节点,最终实现双向链表
    • LinkedList中元素的添加或删除,不是通过数组实现的,效率相对较高
  • 可以任意添加元素,元素可重复、可为null
  • 线程不是安全的,没有实现同步

方法声明

描述

void add(int index, E element)

指定位置插入指定元素

void addFirst(Object o)

将指定元素插入列表开头

void addLast(Object o)

将指定元素插入列表结尾

Object getFirst()

返回列表的第一个元素

Object getLast()

返回列表的最后一个元素

Object removeFirst()

移除并且返回列表的第一个元素

Object removeLast()

移除并且返回列表的最后一个元素

import java.util.*;

public class Demo01 {
    public static void main(String[] args) {
        LinkedList link = new LinkedList();
        link.add("xml");
        link.add(123);
        link.add('y');
        System.out.println(link);

        link.addFirst("xml");
        link.addLast("ywj");
        System.out.println(link);

        link.remove("xml");//如果有重复元素,只能移除第一个出现的
        System.out.println(link);

        link.remove(3);//移除指定索引的元素
        System.out.println(link);

        Object obj = link.removeFirst();
        System.out.println(obj + " " + link);//移除开头的元素
    }
}

ArrayList和LinkedList比较

 

底层结构

增删效率

改查的效率

ArrayList

可变数组

较低,通过数组扩容

较高,不需要改变数组

LinkedList

双向链表

较高,通过链表追加

较低,需要通过node一个个遍历找到后操作

如何选择?

  • 如果改查操作较多,选择ArrayList
  • 如果增删操作较多,选择LinkedList
  • 一般来说在程序中大多数都是查询,因此大部分情况下会选择ArrayList
  • 不适合用于多线程,LinkedList和ArrayList的线程不是安全的

 

Vector(不推荐使用)

VectorArrayList一样也是通过数组实现的,不过不同的是它支持线程的同步,即在某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要的花费很高,因此访问它比访问ArrayList慢。

vector特点

  • 有序的,可以存储重复值和null值
  • 底层是数组实现的,线程安全。结构和ArrayList非常相似,同样是一个线性的动态可扩容数组
  • 初始容量是10,没有设置扩容增量的情况下以自身的2倍容量扩容;可以设置容量增量,初始容量和扩容两可以通过构造函数public Vetor(int initialCapacity, int capacityIncrement)进行初始化

查看Vector源码,和ArrayList几乎一模一样,区别就是Vector的方法使用了synchronized锁实现了线程安全

    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }
    
    public synchronized E remove(int index) {
        modCount++;
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        E oldValue = elementData(index);

        int numMoved = elementCount - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--elementCount] = null; // Let gc do its work

        return oldValue;
    }

那为什么很少见到使用Vector呢?

  • 因为Vector虽然线程安全,但是每个可能出现线程安全的方法上加上了synchronized关键字,所以效率低。但是其实并没有很好的解决线程安全问题,比如下面这段代码,在判断是否包含某元素后会释放锁,在不包含的情况下,执行add之前,锁很有可能会被抢占
if (!vector.contains(element)) 
    vector.add(element); 
}
  • Vector空间满了以后扩容是一倍,而ArrayList仅是一半。如果数据太多可能会导致内存分配失败
  • 只能在尾部进行插入和删除,效率较低
  • 现在已经有了更好的替代品CopyOnWriteArrayList

 

Set

Set是无序且值不重复的Collection。无序依赖于对象是否相等的判断,对象相等的本质是对象hashcode值判断的,如果想让两个不同的对象视为相等的,就必须覆盖Object的hashcode和equals方法。

 

HashSet

HashSet的哈希表边存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(和List不相同),而是按照哈希值来存的所以取数据也是按照哈希值取。

元素的哈希值是通过元素的hashcode方法来获取,HashSet首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals方法,如果equals结果为true,HashSet就视为一个元素。如果equals为false就不是同一个元素。HashSet通过hashCode值来确定元素在内存中的位置。因此一个hashCode位置上可以存放多个元素。

import java.util.*;

public class Demo01 {
    public static void main(String[] args) {
        Set set = new HashSet();
        set.add("xml");
        set.add('0');
        set.add("xml");
        set.add(1);
        set.add(null);
        set.add(2);

        Iterator iterator  = set.iterator();
        while (iterator.hasNext()){
            Object obj = iterator.next();
            System.out.println(obj);
        }
    }
}

 

TreeSet

TreeSet是使用二叉树的原理对新add()的对象按照指定的顺序排序(升序、降序),每增加一个对象都会进行排序,将对象插入到二叉树指定的位置。

Integer和String对象都可以进行默认的TreeSet排序,而自定义的对象是不可以的,自己定义的类必须实现Comparable接口,并且覆盖写对应的compareTo()函数,才可以正常使用。在覆盖写compare()函数时,要返回相应的值才能使TreeSet按照一定的规则来排序,比较此对象和指定对象的顺序,如果该对象小于、等于或者大于指定对象,则返回负整数、零或正整数。

不过treeset存储的对象必须是同类型的对象,而且存储的类型必须实现了Comparable接口。如果没有实现该接口,那么add进入集合时进行元素大小比较的时候,调用comparableTo方法时会报错ClassCastException异常

import java.util.*;

public class Demo01 {
    public static void main(String[] args) {
        Set set = new TreeSet();
        set.add("xml");
        set.add("ywj");
        set.add("xml");
        //set.add(null); 这里报错java.lang.NullPointerException,是不允许null值的
        set.add("test");

        Iterator iterator  = set.iterator();
        while (iterator.hasNext()){
            Object obj = iterator.next();
            System.out.println(obj);
        }
    }
}

 

Iterator

Iterator主要用于迭代访问Collection中的元素,因此Iterator对象也被称为迭代器。案例如上面写的demo。

 

标签:元素,Java,一文,ArrayList,Object,list,Collection,add,集合
From: https://www.cnblogs.com/cccrush/p/16747296.html

相关文章

  • 力扣209(java)-单词规律(简单)
    题目:给定一种规律pattern 和一个字符串 s ,判断s 是否遵循相同的规律。这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 s 中的每个非空单词之间存......
  • Java泛型中<T> T 与 T的区别和用法
    有的方法返回值是<T>T,有的是T,区别在哪里?下面是一个泛型方法,<T>声明此方法有一个泛型T,也可以理解声明一个泛型方法.    下面三个T,第一个T表示是泛型,第二个......
  • 肖sir___第二个月Javascript_04
    1.1JavaScript简介JavaScript是互联网上最流行的脚本语言,这门语言可用于HTML和web,更可广泛用于服务器、PC、笔记本电脑、平板电脑和智能手机等设备JavaScript是......
  • 肖sir___第二个月java操作JDBC_02
    1.1JDBC概述JDBC(JavaDataBaseConnectivity)是Java和数据库之间的一个桥梁,是一个规范而不是一个实现,能够执行SQL语句。它由一组用Java语言编写的类和接口组成。各种不同......
  • Java之POI导出Excel(一):单sheet
    相信在大部分的web项目中都会有导出导入Excel的需求,今天我们就来看看如何用Java代码去实现用POI导出Excel表格。一、pom引用pom文件中,添加以下依赖查看代码 <!--Exc......
  • 肖sir_Java注解__22
    Java注解 1.1注解介绍从Java5版本之后可以在源代码中嵌入一些补充信息,这种补充信息称为注解(Annotation),注解是Java平台中非常重要的一部分。注解都是@符号开头,......
  • 肖sir_Java 8 新特性__21
    1.1Lambda表达式Lambda表达式,也可称为闭包,它是推动Java8发布的最重要新特性。Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中)。语法1,(parameters......
  • Java 数组
    1.数组的定义数组是相同类型数据的有序集合。数字描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作数组元素,每一个数组元素可以通过......
  • 肖sir_Java 反射__20
    1.1反射概述Java中创建对象的方式1、使用new关键字:这是我们最常见的也是最简单的创建对象的方式2、使用Clone的方法:无论何时我们调用一个对象的clone方法,JVM就会创建一......
  • SpringBoot+Vue疫苗接种管理系统 新冠疫苗接种系统 预约疫苗接种管理系统Java
    ......