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更快。

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

相关文章
|
12天前
|
Java 大数据 API
Java Stream API:现代集合处理与函数式编程
Java Stream API:现代集合处理与函数式编程
174 100
|
12天前
|
Java API 数据处理
Java Stream API:现代集合处理新方式
Java Stream API:现代集合处理新方式
174 101
|
25天前
|
算法 Java
50道java集合面试题
50道 java 集合面试题
|
4月前
|
存储 安全 Java
常见 JAVA 集合面试题整理 自用版持续更新
这是一份详尽的Java集合面试题总结,涵盖ArrayList与LinkedList、HashMap与HashTable、HashSet与TreeSet的区别,以及ConcurrentHashMap的实现原理。内容从底层数据结构、性能特点到应用场景逐一剖析,并提供代码示例便于理解。此外,还介绍了如何遍历HashMap和HashTable。无论是初学者还是进阶开发者,都能从中受益。代码资源可从[链接](https://pan.quark.cn/s/14fcf913bae6)获取。
212 3
|
3月前
|
Oracle Java 关系型数据库
掌握Java Stream API:高效集合处理的利器
掌握Java Stream API:高效集合处理的利器
342 80
|
3月前
|
安全 Java API
Java 8 Stream API:高效集合处理的利器
Java 8 Stream API:高效集合处理的利器
233 83
|
16天前
|
存储 Java Go
对比Java学习Go——函数、集合和OOP
Go语言的函数支持声明与调用,具备多返回值、命名返回值等特性,结合`func`关键字与类型后置语法,使函数定义简洁直观。函数可作为一等公民传递、赋值或作为参数,支持匿名函数与闭包。Go通过组合与接口实现面向对象编程,结构体定义数据,方法定义行为,接口实现多态,体现了Go语言的简洁与高效设计。
|
2月前
|
存储 缓存 安全
Java集合框架(二):Set接口与哈希表原理
本文深入解析Java中Set集合的工作原理及其实现机制,涵盖HashSet、LinkedHashSet和TreeSet三大实现类。从Set接口的特性出发,对比List理解去重机制,并详解哈希表原理、hashCode与equals方法的作用。进一步剖析HashSet的底层HashMap实现、LinkedHashSet的双向链表维护顺序特性,以及TreeSet基于红黑树的排序功能。文章还包含性能对比、自定义对象去重、集合运算实战和线程安全方案,帮助读者全面掌握Set的应用与选择策略。
150 23
|
2月前
|
存储 缓存 安全
Java集合框架(三):Map体系与ConcurrentHashMap
本文深入解析Java中Map接口体系及其实现类,包括HashMap、ConcurrentHashMap等的工作原理与线程安全机制。内容涵盖哈希冲突解决、扩容策略、并发优化,以及不同Map实现的适用场景,助你掌握高并发编程核心技巧。
|
2月前
|
安全 Java 开发者
Java集合框架:详解Deque接口的栈操作方法全集
理解和掌握这些方法对于实现像浏览器后退功能这样的栈操作来说至关重要,它们能够帮助开发者编写既高效又稳定的应用程序。此外,在多线程环境中想保证线程安全,可以考虑使用ConcurrentLinkedDeque,它是Deque的线程安全版本,尽管它并未直接实现栈操作的方法,但是Deque的接口方法可以相对应地使用。
121 12