Java集合(一)

简介: Java集合(一)

Java集合

集合的概念

在java中,集合是一个名词而不是动词,集合是一种存储数据的容器。

如果只是为了容纳数据,可以使用数组。为什么有数组了还需要集合来存储数据呢?

  • 数组使用时要确定元素个数,当使用场景中的元素个数不确定时,使用数组不太方便。

集合指的是一系列框架,在java.util中。包含了集合一系列的接口和类。

对不确定个数的有关系的数据进行相同的逻辑处理时,我们使用集合来操作更好。

根据数据的不同,java中的集合分为两种类型:

  • 单一数据体系:Collection接口定义了相关规范
  • 成对出现的数据体系:所谓的成对,是值一对数据相关联,可根据第一个数据关联到第二个数据。也称之为键值对数据("kevin",20)->(key,value)。比如Map接口就定义了这种规则。

常用接口和类

Collection接口:

常用的子接口

  • List:按照插入顺序保存数据,数据可以重复。
    • 主要的具体实现类为:ArrayList,LinkedList
  • Set:集,无序保存。数据不能重复。
    • 主要的具体实现类为:HashSet
  • Queue:队列
    • 主要的具体实现类为:ArrayBlockingQueue

Map接口:

  • 主要的具体实现类为:HashMap,HashTable

List

ArrayList

List:表示列表,清单。在清单中我们是先取出先插入的,所以list也是按照插入顺序读取,第一个插入,读取时也是第一个。并且它可以存储重复的数据。

Array:表示数组,序列。

在ArrayList这个集合类的内部就是使用数组来存储数据的。

ArrayList对象的创建:

ArrayList arrayList = new ArrayList();

其中,有三种方式创建一个ArrayList:

  • 不传参数,直接new。底层会创建一个空数组
  • 传一个int类型的参数,用于设定底层数组的长度
  • 传一个Collection集合类型的对象,用于将其他集合放置在当前集合中

我们来打印这个ArrayList对象:

ArrayList arrayList = new ArrayList();
System.out.println(arrayList);// []

返回的集合对象中的数据(当前为空)

集合对象的基本操作

增加数据

我们使用add方法向集合添加数据:

ArrayList arrayList = new ArrayList();
arrayList.add("kevin");
arrayList.add("qina");
arrayList.add("kun");
System.out.println(arrayList);// [kevin, qina, kun]

对于一个没有传参new出的对象,它底层的数组长度会被自动设置为10。

那如果我们的数据超出了底层的数组长度会怎样呢?

为了方便,我们就声明一个底层数组长度为3的集合:

ArrayList arrayList = new ArrayList(3);
arrayList.add("kevin");
arrayList.add("qina");
arrayList.add("kun");
arrayList.add("yes");
System.out.println(arrayList);// [kevin, qina, kun, yes]

我们看到,依然会进行添加数据。并且也没有报错,那这是为什么呢?

原来,在底层,遇到元素个数超出数组长度时。会创建一个更大的数组,并且将索引的内存空间指向原来的对象,然后再进行添加。这个操作叫扩容。而原来的数组就不会被使用了。

image-20230109205656166

获取数据

使用get方法获取数据,传入参数为索引。使用size()方法来获取集合的元素个数

ArrayList arrayList = new ArrayList(3);
arrayList.add("kevin");
arrayList.add("qian");
arrayList.add("kun");
arrayList.add("yes");

System.out.println(arrayList.size());// 4
System.out.println(arrayList.get(1));// qian

使用for循环来遍历集合:

for (int i = 0; i < arrayList.size(); i++) {
    System.out.println(arrayList.get(i));
}

如果不关心数据的位置,我们可以使用forin来遍历(按顺序遍历):

  • for(类型 循环对象:集合){}
for (Object o : arrayList) {
    System.out.println(o);
}

修改数据

使用set()方法修改数据,传入两个参数:

  • 第一个参数:下标(索引)
  • 第二个参数:修改的值

方法会返回结果,返回值为更新前的值:

ArrayList arrayList = new ArrayList(3);
arrayList.add("kevin");
arrayList.add("qian");
arrayList.add("kun");
arrayList.add("yes");

Object chage = arrayList.set(3, "no");
arrayList.set(0, 3.0);
System.out.println(chage);// yes
System.out.println(arrayList);// [3.0, qian, kun, no]

删除数据

使用remove()方法可以删除集合的数据,传入参数为数据的位置(索引):

方法会返回结果,返回值为要删除的值

ArrayList arrayList = new ArrayList(3);
arrayList.add("kevin");
arrayList.add("qian");
arrayList.add("kun");
arrayList.add("yes");

Object o = arrayList.remove(1);
System.out.println(o);//qian
System.out.println(arrayList.size());// 3
System.out.println(arrayList);// [kevin, kun, yes]

ArrayList常用方法

add()传入两个参数时,可以用于向集合指定位置插入数据:

  • 第一个参数:索引
  • 第二个参数:添加的数据
ArrayList arrayList = new ArrayList();
arrayList.add("kevin");
arrayList.add("qian");

arrayList.add(0, "demo");
System.out.println(arrayList);// [demo, kevin, qian]

当插入数据时,之前该位置的数据会与后面的数据一起向后移。

使用clear()方法来清空集合中的数据:

ArrayList arrayList = new ArrayList();
arrayList.add("kevin");
arrayList.add("qian");

System.out.println(arrayList.size());// 2
arrayList.clear();
System.out.println(arrayList);// []
System.out.println(arrayList.size());// 0

使用removeAll()来删除集合中的指定数据(如果移除了返回true,反之为false):

参数类型是一个集合,可以使用Collections.singleton()来转为一个集合。

使用addAll()方法可以将一个集合的所有数据添加到该集合中(同样可以传两个参数)。

ArrayList arrayList = new ArrayList();
arrayList.add("kevin");
arrayList.add("qian");
arrayList.add("qian");
arrayList.add("qian");

ArrayList list2 = new ArrayList();
list2.add("ok");
list2.add("nice");

arrayList.addAll(list2);

arrayList.removeAll(Collections.singleton("qian"));
System.out.println(arrayList);//[kevin, ok, nice]

boolean b = arrayList.removeAll(list2);
boolean b1 = arrayList.removeAll(Collections.singleton("lll"));
System.out.println(b);//true
System.out.println(b1);//false
System.out.println(arrayList);//[kevin]

使用isEmpty()方法来判断集合是否为空:

ArrayList arrayList = new ArrayList();
arrayList.add("kevin");
arrayList.add("qian");
arrayList.add("qian");
arrayList.add("qian");

ArrayList list2 = new ArrayList();
System.out.println(arrayList.isEmpty());// false
System.out.println(list2.isEmpty());// true

使用contains()方法来判断集合中是否有这个数据:

ArrayList arrayList = new ArrayList();
arrayList.add("kevin");
arrayList.add("qian");
arrayList.add("qian");
arrayList.add("qian");

System.out.println(arrayList.contains("kevin"));// true
System.out.println(arrayList.contains("kun"));// false

使用indexOf()方法和lastIndexOf()找到第一次出现和最后一次出现该数据的位置

ArrayList arrayList = new ArrayList();
arrayList.add("kevin");
arrayList.add("qian");
arrayList.add("qian");
arrayList.add("qian");

System.out.println(arrayList.indexOf("qian"));// 1
System.out.println(arrayList.lastIndexOf("qian"));// 3

集合转数组:

ArrayList arrayList = new ArrayList();
arrayList.add("kevin");
arrayList.add("qian");
arrayList.add("qian");
arrayList.add("qian");

Object[] objects = arrayList.toArray();
System.out.println(objects[1]);//qian

复制一份集合:

ArrayList arrayList = new ArrayList();
arrayList.add("kevin");
arrayList.add("qian");
arrayList.add("qian");
arrayList.add("qian");

Object clone = arrayList.clone();
System.out.println(clone);// [kevin, qian, qian, qian]

LinkedList

LinkedList是一种链表结构

LinkedList list = new LinkedList();
list.addFirst("kevin");
System.out.println(list.getFirst());// kevin
System.out.println(list.getLast());// kevin
System.out.println(list);// [kevin]

取第一个数据和最后一个:

LinkedList list = new LinkedList();
list.addFirst("kevin");
list.addFirst("qian");

System.out.println(list.getFirst());// qian
System.out.println(list.getLast());// kevin
System.out.println(list);// [qian, kevin]

添加数据(add默认添加到最后,两个参数为插入该索引位置):

LinkedList list = new LinkedList();
list.addFirst("kevin");
list.addFirst("qian");
list.add(1, "kun");

System.out.println(list);// [qian, kun, kevin]

get方法取数据

LinkedList list = new LinkedList();
list.addFirst("kevin");
list.addFirst("qian");
list.add(1, "kun");

System.out.println(list.get(1));// kun

使用for循环遍历

LinkedList list = new LinkedList();
list.addFirst("kevin");
list.addFirst("qian");
list.add(1, "kun");

for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}
// qian
// kun
// kevin

使用forin遍历:

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

set方法修改数据

LinkedList list = new LinkedList();
list.addFirst("kevin");
list.addFirst("qian");
list.add(1, "kun");

list.set(0, "kkkevin");
System.out.println(list.getFirst());// kkkevin

remove方法移除集合中的传入第一个数据:

LinkedList list = new LinkedList();
list.addFirst("kevin");
list.addFirst("qian");
list.add(1, "kun");
list.addLast("kevin");

list.remove("kevin");
System.out.println(list);// [qian, kun, kevin]

LinkedList常用方法

除了上面的一些方法外,它还有一些api我们经常使用:

push()方法用于向开头添加数据,类似addFirst。

LinkedList list = new LinkedList();

list.push("kevin");
list.push("qian");
list.push("kun");
list.add("yt");

System.out.println(list);//[kun, qian, kevin, yt]

element()方法用于取第一个数据,类似getFirst。

System.out.println(list.element());//kun

pop用于弹出数据,弹出第一个数据,返回值也是弹出的数据。

LinkedList list = new LinkedList();

list.push("kevin");
list.push("qian");
list.push("kun");
list.add("yt");

System.out.println(list);//[kun, qian, kevin, yt]

System.out.println(list.pop());// kun
System.out.println(list);// [qian, kevin, yt]

泛型

由于多态性,集合在默认情况下下使用的时候非常不方便,因为数据的默认类型都是Object:

ArrayList list = new ArrayList();
list.add(new Person());
list.add(new Person());
Object o = list.get(1);
o.personName();// 无法解析 'Object' 中的方法 'personName'

Person类:

class Person {
    public void personName() {
        System.out.println("person...");
    }
}

如果要使用,就必须使用强制类型转换。非常不方便,而且可能出现类型转换错误的异常。

Person o = (Person) list.get(1);
o.personName();// person...

这时候我们可以使用泛型,我们传入的数据都是同一个类型:

ArrayList<Person> list = new ArrayList();
list.add(new Person());
Person person = list.get(0);
person.personName();// person...

类型存在多态的使用,而泛型是没有多态的。

public class JavaCollection_05 {
    public static void main(String[] args) {
        Contains<User5> contains = new Contains();
        test(contains);// 需要的类型:Contains<Object> 提供的类型:Contains<User5>
    }

    public static void test(Contains<Object> contains) {
        System.out.println(contains);
    }
}

class Contains<C> {
    public C data;
}

class User5 {
}

比较器

集合提供了sort方法来进行排序,传入的是一个实现了比较器接口的类的实例对象

import java.util.ArrayList;
import java.util.Comparator;

public class JavaCollection_06 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(2);
        list.add(1);
        list.add(3);
        list.add(0);

        list.sort(new NumberComparator());
        System.out.println(list);// [0, 1, 2, 3]
    }
}

class NumberComparator implements Comparator<Integer> {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1 - o2;// 升序
    }
}

其中,compare方法中:

  • 参数1>参数2,返回值为正数,表示升序
  • 参数1<参数,返回值为负,表示降序
  • 参数1==参数2,返回值为0。

官方解释:compare方法比较其两个顺序参数。返回负整数、零或正整数,因为第一个参数小于、等于或大于第二个参数。

ArrayList与LinkedList比较

添加第一条数据,LinkedList更快

image-20230110191430567

添加后面的数据,ArrayList更快

但是,当ArrayList需要扩容时,LinkedList更快。

而插入数据,LinkedList更快。

image-20230110193639330

由于LinkedList没有索引的概念(在LinkedList中叫顺序),在LinkedList中使用索引实际上还是在按着顺序找。所以使用索引查找时,ArrayList更快。

如果不使用索引查找,两个集合的查找没有本质区别。

相关文章
|
1月前
|
安全 Java 容器
【Java集合类面试二十七】、谈谈CopyOnWriteArrayList的原理
CopyOnWriteArrayList是一种线程安全的ArrayList,通过在写操作时复制新数组来保证线程安全,适用于读多写少的场景,但可能因内存占用和无法保证实时性而有性能问题。
|
1月前
|
存储 安全 Java
【Java集合类面试二十五】、有哪些线程安全的List?
线程安全的List包括Vector、Collections.SynchronizedList和CopyOnWriteArrayList,其中CopyOnWriteArrayList通过复制底层数组实现写操作,提供了最优的线程安全性能。
|
1月前
|
Java
【Java集合类面试二十八】、说一说TreeSet和HashSet的区别
HashSet基于哈希表实现,无序且可以有一个null元素;TreeSet基于红黑树实现,支持排序,不允许null元素。
|
1月前
|
Java
【Java集合类面试二十三】、List和Set有什么区别?
List和Set的主要区别在于List是一个有序且允许元素重复的集合,而Set是一个无序且元素不重复的集合。
|
1月前
|
Java
【Java集合类面试二十六】、介绍一下ArrayList的数据结构?
ArrayList是基于可动态扩展的数组实现的,支持快速随机访问,但在插入和删除操作时可能需要数组复制而性能较差。
|
1月前
|
存储 Java 索引
【Java集合类面试二十四】、ArrayList和LinkedList有什么区别?
ArrayList基于动态数组实现,支持快速随机访问;LinkedList基于双向链表实现,插入和删除操作更高效,但占用更多内存。
|
6天前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
21天前
|
Java
用JAVA架建List集合为树形结构的代码方法
这段代码定义了一个表示树形结构的 `Node` 类和一个用于构建树形结构的 `TreeController`。`Node` 类包含基本属性如 `id`、`pid`、`name` 和 `type`,以及子节点列表 `children`。`TreeController` 包含初始化节点列表并将其转换为树形结构的方法。通过过滤和分组操作实现树形结构的构建。详情可见:[代码示例链接1](http://www.zidongmutanji.com/zsjx/43551.html),[代码效果参考链接2](https://www.257342.com/sitemap/post.html)。
28 5
|
21天前
|
存储 Java 程序员
Java中的集合框架:从入门到精通
【8月更文挑战第30天】在Java的世界里,集合框架是一块基石,它不仅承载着数据的存储和操作,还体现了面向对象编程的精髓。本篇文章将带你遨游Java集合框架的海洋,从基础概念到高级应用,一步步揭示它的奥秘。你将学会如何选择合适的集合类型,掌握集合的遍历技巧,以及理解集合框架背后的设计哲学。让我们一起探索这个强大工具,解锁数据结构的新视角。
|
22天前
|
存储 算法 Java
Java中的集合框架深度解析云上守护:云计算与网络安全的协同进化
【8月更文挑战第29天】在Java的世界中,集合框架是数据结构的代言人。它不仅让数据存储变得优雅而高效,还为程序员提供了一套丰富的工具箱。本文将带你深入理解集合框架的设计哲学,探索其背后的原理,并分享一些实用的使用技巧。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇通往高效编程的大门。