集合(常用类库里面最重要的一部分)

集合(重点,常用类库里面最重要的一部分)

类集设置的目的(重点)

​ 普通的对象数组的最大问题在于数组中的元素个数是固定的,不能动态的扩充大小,所以最早的时候可以通过链表实现一个动态对象数组。但是这样做毕竟太复杂了,所以在 Java 中为了方便用户操作各个数据结构,所以引入了类集的概念,有时候就可以把类集称为 java 对数据结构的实现。
​ 在整个类集中的,这个概念是从 JDK 1.2(Java 2)之后才正式引入的,最早也提供了很多的操作类,但是并没有完整的提出类集的完整概念。
​ 类集中最大的几个操作接口:Collection、Map、Iterator,这三个接口为以后要使用的最重点的接口。
​ 所有的类集操作的接口或类都在 java.util

Collection集合

1.1 集合概述

集合:集合是java中提供的一种容器,可以用来存储多个数据。 集合和数组既然都是容器,它们有啥区别呢?

  • 数组的长度是固定的。

    集合的长度是可变的。

  • 数组中存储的是同一类型的元素,可以存储基本数据类型值。

    集合存储的都是对象。而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eD6BumN8-1627353516617)(D:\typora\Typora\picture\image-20210720011807233.png)]

1.2 Collection 常用功能

Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法, 这些方法可用于操作所有的单列集合。方法如下:

public boolean add(E e) : 把给定的对象添加到当前集合中 。 

public void clear() :清空集合中所有的元素。 

public boolean remove(E e) : 把给定的对象在当前集合中删除。 

public boolean contains(E e) : 判断当前集合中是否包含给定的对象。 

public boolean isEmpty() : 判断当前集合是否为空。 

public int size() : 返回集合中元素的个数。 

public Object[] toArray() : 把集合中的元素,存储到数组中。

Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,它有两个重要的子接口,分别是 java.util.Listjava.util.Set 。其中,

List 的特点是:元素有序、元素可重复,允许多个Null元素对象,

Set 的特点是:元素无序,而且不可重复,无索引,最多允许有一个Null元素对象

List 接口的主要实现类有 java.util.ArrayListjava.util.LinkedList

Set 接口的主要实现类有 java.util.HashSet 和 java.util.TreeSet

List集合

List接口介绍

java.util.List 接口继承自 Collection 接口,是单列集合的一个重要分支,习惯性地会将实现了 List 接口的对象称为List集合。在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素。另外,List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。

List接口特点

  1. 它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就 是按照11、22、33的顺序完成的)。
  2. 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道 理)。
  3. 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。

List 子接口的定义:

public interface List<E> extends Collection<E>

List接口中常用方法

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

public void add(int index, E element) : 将指定的元素,添加到该集合中的指定位置上。
    
public E get(int index) :返回集合中指定位置的元素。
    
public E remove(int index) : 移除列表中指定位置的元素, 返回的是被移除的元素。
    
public E set(int index, E element) :用指定元素替换集合中指定位置的元素,返回值的更新前的元素。

List的子类

ArrayList集合

java.util.ArrayList 集合数据存储的结构是数组结构元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以 ArrayList 是最常用的集合。

许多程序员开发时非常随意地使用ArrayList完成任何需求,并不严谨,这种用法是不提倡的。

ArrayList 是 List 接口的子类,此类的定义如下:

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable

例:增加及取得元素

public class ArrayListDemo01 {
    public static void main(String[] args) {
        List<String> all = new ArrayList<String>(); // 实例化List对象,并指定泛型类型
        all.add("hello "); // 增加内容,此方法从Collection接口继承而来
        all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的
        all.add("world"); // 增加内容,此方法从Collection接口继承而来
        System.out.println(all); // 打印all对象调用toString()方法
    }
}

​ 以上的操作向集合中增加了三个元素,其中在指定位置增加的操作是 List 接口单独定义的。随后进行输出的时候, 实际上调用的是 toString()方法完成输出的。

​ 可以发现,此时的对象数组并没有长度的限制,长度可以任意长,只要是内存够大就行。

例:1、使用 remove()方法删除若干个元素,并且使用循环的方式输出。

2、根据指定位置取的内容的方法,只有 List 接口才有定义,其他的任何接口都没有任何的定义。

public class ArrayListDemo02 {
    public static void main(String[] args) {
        List<String> all = new ArrayList<String>(); // 实例化List对象,并指定泛型类型
        all.add("hello "); // 增加内容,此方法从Collection接口继承而来
        all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的
        all.add("world"); // 增加内容,此方法从Collection接口继承而来
        all.remove(1); // 根据索引删除内容,此方法是List接口单独定义的
        all.remove("world");// 删除指定的对象
        System.out.print("集合中的内容是:");
        for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来
        	System.out.print(all.get(x) + "、"); // 此方法是List接口单独定义的
        }
    }
}

对于删除元素的操作,后面还会有更加清楚的讲解,此处只是简单的理解一下元素删除 的基本操作即可。具体的原理可以暂时不进行深入掌握。

Vector(重点)

与 ArrayList 一样,Vector 本身也属于 List 接口的子类,此类的定义如下:

public class Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable

此类与 ArrayList 类一样,都是 AbstractList 的子类。所以,此时的操作只要是 List 接口的子类就都按照 List 进行操作。

public class VectorDemo01 {
    public static void main(String[] args) {
        List<String> all = new Vector<String>(); // 实例化List对象,并指定泛型类型
        all.add("hello "); // 增加内容,此方法从Collection接口继承而来
        all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的
        all.add("world"); // 增加内容,此方法从Collection接口继承而来
        all.remove(1); // 根据索引删除内容,此方法是List接口单独定义的
        all.remove("world");// 删除指定的对象
        System.out.print("集合中的内容是:");
        for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来
        	System.out.print(all.get(x) + "、"); // 此方法是List接口单独定义的
        }
    }
}

​ 以上的操作结果与使用 ArrayList 本身并没有任何的区别。因为操作的时候是以接口为操作的标准。

​ 但是 Vector 属于 Java 元老级的操作类,是最早的提供了动态对象数组的操作类,在 JDK 1.0 的时候就已经推出了此类的使用,只是后来在 JDK 1.2 之后引入了 Java 类集合框架。但是为了照顾很多已经习惯于使用 Vector 的用户,所以在 JDK 1.2 之后将 Vector 类进行了升级了,让其多实现了一个 List 接口,这样才将这个类继续保留了下来。

Vector 类和 ArrayList 类的区别(重点)

这两个类虽然都是 List 接口的子类,但是使用起来有如下的区别,为了方便大家笔试,列出此内容:

No.区别点ArrayListVector
1时间是新的类,是在 JDK 1.2 之后推出的是旧的类是在 JDK 1.0 的时候就定义的
2性能性能较高,是采用了异步处理性能较低,是采用了同步处理
3输出支持 Iterator、ListIterator 输出除了支持 Iterator、ListIterator 输出,还支持 Enumeration 输出

LinkedList集合

java.util.LinkedList 集合数据存储的结构是链表结构方便元素添加、删除的集合

LinkedList是一个双向链表

此类的使用几率是非常低的,但是此类的定义如下:

public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, Serializable

此类继承了 AbstractList,所以是 List 的子类。但是此类也是 Queue 接口的子类,Queue 接口定义了如下的方法:

No.方法名称类型描述
1public boolean add(E e)普通增加元素,如果有容量限制,并且已满,则抛出异常
2public E element()普通取得,但是不删除当前元素,如果对列为空则抛出异常
3boolean offer(E e)普通添加,如果有容量限制,并且已满,只是无法添加, 但不抛出异常,返回 false
4E peek()普通取得头元素,但是不删除,如果队列为空,则返回 null
5E poll()普通取得头元素,但是删除, 如果队列为空,则返回 null
6E remove()普通删除当前元素, 如果对列为空则抛出异常

实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。这些方法我们作为了解即可:

public void addFirst(E e) :将指定元素插入此列表的开头。
public void addLast(E e) :将指定元素添加到此列表的结尾。
public E getFirst() :返回此列表的第一个元素。
public E getLast() :返回此列表的最后一个元素。
public E removeFirst() :移除并返回此列表的第一个元素。
public E removeLast() :移除并返回此列表的最后一个元素。
public E pop() :从此列表所表示的堆栈处弹出一个元素。
public void push(E e) :将元素推入此列表所表示的堆栈。
public boolean isEmpty() :如果列表不包含元素,则返回true

LinkedList是List的子类,List中的方法LinkedList都是可以使用,这里就不做详细介绍,我们只需要了解LinkedList的特有方法即可。在开发时,LinkedList集合也可以作为堆栈,队列的结构使用。(了解即可)

例:验证 LinkedList 子类

public class TestDemo {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<String>();
        queue.add("A");
        queue.add("B");
        queue.add("C");
        int len=queue.size();//把queue的大小先取出来,否则每循环一次,移除一个元素,就少一个元素,那么queue.size()在变小,就不能循环queue.size()次了。
        for (int x = 0; x <len; x++) {
        	System.out.println(queue.poll());
        }
        System.out.println(queue);
    }
}

Iterator迭代器(重点

Iterator 属于迭代输出,基本的操作原理:是不断的判断是否有下一个元素,有的话,则直接输出。

此接口定义如下:

public interface Iterator<E>

要想使用此接口,则必须使用 Collection 接口,在 Collection 接口中规定了一个 iterator()方法,可以用于为 Iterator 接口进行实例化操作。

通过 Collection 接口为其进行实例化之后,一定要记住,Iterator 中的操作指针是在第一条元素之上,当调用 next()方 法的时候,获取当前指针指向的值并向下移动,使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M5aCvVrg-1627353516621)(D:\typora\Typora\picture\image-20210721031158309.png)]

Iterator接口

在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,JDK专门提供了一个接口java.util.Iterator 。 Iterator 接口也是Java集合中的一员,但它与 Collection 、 Map 接口有所 不同, Collection 接口与 Map 接口主要用于存储元素,而 Iterator 主要用于迭代访问(即遍历) Collection 中的元素,因此 Iterator 对象也被称为迭代器

想要遍历Collection集合,那么就要获取该集合迭代器完成迭代操作,下面介绍一下获取迭代器的方法:

public Iterator iterator() : 获取集合对应的迭代器,用来遍历集合中的元素的

迭代的概念:

迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就再取出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。

Iterator接口的常用方法如下:

public E next() :返回迭代的下一个元素。
public boolean hasNext() :如果仍有元素可以迭代,则返回 truevoid remove() : 删除当前内容

Iterator 输出

public class IteratorDemo01 {
	public static void main(String[] args) {
		Collection<String> all = new ArrayList<String>();
		all.add("A");
		all.add("B");
		all.add("C");
		all.add("D");
		all.add("E");
		Iterator<String> iter = all.iterator();
		while (iter.hasNext()) {// 判断是否有下一个元素
			String str = iter.next(); // 取出当前元素
			System.out.print(str + "、");
		}
	}
}

以上的操作是 Iterator 接口使用最多的形式,也是一个标准的输出形式。

但是在使用 Iterator 输出的时候有一点必须注意,在进行迭代输出的时候如果要想删除当前元素,则只能使用 Iterator 接口中的 remove()方法,而不能使用集合中的 remove()方法。否则将出现未知的错误。

public class IteratorDemo02 {
	public static void main(String[] args) {
		Collection<String> all = new ArrayList<String>();
    	all.add("A");
		all.add("B");
		all.add("C");
		all.add("D");
		all.add("E");
		Iterator<String> iter = all.iterator();
		while (iter.hasNext()) {// 判断是否有下一个元素
			String str = iter.next(); // 取出当前元素
			if (str.equals("C")) {
				iter.remove(str); // all.remove(str)是错误的,调用了集合中的删除
			} else {
				System.out.print(str + "、");
			}
		}
	}
}
/**
 *iter.next();必须先指向这个元素才能删除
 *iter.remove();
 */

​ 从实际的开发角度看,元素的删除操作出现的几率是很小的,基本上可以忽略,即:集合中很少有删除元素 的操作。

​ Iterator 接口本身可以完成输出的功能,但是此接口只能进行由前向后的单向输出。如果要想进行双向输出,则必须 使用其子接口 —— ListIterator。

迭代器的实现原理

我们在之前案例已经完成了Iterator遍历集合的整个过程。当遍历集合时,首先通过调用t集合的 iterator()方法获得迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素,如果存在, 则调用next()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。

ListIterator(理解)

ListIterator 是可以进行双向输出的迭代接口,此接口定义如下:

public interface ListIterator<E> extends Iterator<E>

此接口是 Iterator 的子接口,此接口中定义了以下的操作方法:

No.方法名称类型描述
1void add(E e)普通增加元素
2boolean hasPrevious()普通判断是否有前一个元素
3E previous()普通取出前一个元素
4void set(E e)普通修改元素的内容
5int previousIndex()普通前一个索引位置
6int nextIndex()普通下一个索引位置

但是如果要想使用 ListIterator 接口,则必须依靠 List 接口进行实例化。

List 接口中定义了以下的方法:ListIterator listIterator()

使用 ListIterator 输出

public class ListIteratorDemo01 {
	public static void main(String[] args) {
		List<String> all = new ArrayList<String>();
			all.add("A");
			all.add("B");
			all.add("C");
			all.add("D");
			all.add("E");
			ListIterator<String> iter = all.listIterator();
			System.out.print("从前向后输出:");
			while (iter.hasNext()) {
				System.out.print(iter.next() + "、");
			}
			System.out.print("\n从后向前输出:");
			while (iter.hasPrevious()) {
				System.out.print(iter.previous() + "、");
			}
	}
}

此处有一点需要注意的是,如果要想进行由后向前的输出,则首先必须先进行由前向后的输出。

但是,此接口一般使用较少

废弃的接口:Enumeration(了解)

​ Enumeration 是一个非常古老的输出接口,其也是一个元老级的输出接口,最早的动态数组使用 Vector 完成,那么只 要是使用了 Vector 则就必须使用 Enumeration 进行输出

此接口定义如下:

public interface Enumeration<E>

在 JDK 1.5 之后,此接口实际上也已经加入了泛型操作。此接口常用方法如下:

No.方法名称类型描述
1boolean hasMoreElements()普通判断是否有下一个元素
2E nextElement()普通取出当前元素

​ 但是,与 Iterator 不同的是,如果要想使用 Enumeration 输出的话,则还必须使用 Vector 类完成,在类中定义了如下 方法:public Enumeration elements()

验证 Enumeration 接口

public class EnumerationDemo01 {
	public static void main(String[] args) {
		Vector<String> v = new Vector<String>();
        v.add("A");
        v.add("B");
        v.add("C");
        Enumeration<String> enu = v.elements();
        while (enu.hasMoreElements()) {
			System.out.println(enu.nextElement());
		}
	}
}

需要注意的是,在大部分的情况下,此接口都不再使用了,但是对于一些古老的类库,本身依然要使用此接口进行 操作,所以此接口一定要掌握。

增强for循环(forEach)

增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。

格式:

for(元素的数据类型 变量名 : Collection集合or数组名){
	//写操作代码
}

==*==它用于遍历Collection和数组。通常只进行遍历元素,不要在遍历的过程中对集合元素进行增删操作。

遍历数组

public class Demo {
	public static void main(String[] args) {
		int[] arr = {3,5,6,87};
		//使用增强for遍历数组
		for(int a : arr){//a代表数组中的每个元素
			System.out.println(a);
		}
	}
}

遍历集合

public class NBFor {
	public static void main(String[] args) {
		Collection<String> coll = new ArrayList<String>();
		coll.add("锄禾日当午");
		coll.add("汗滴禾下土");
		coll.add("谁知盘中餐");
		coll.add("粒粒皆辛苦");
		//使用增强for遍历
		for(String s :coll){//接收变量s代表 代表被遍历到的集合元素
			System.out.println(s);
		}
	}
}

增强for循环必须有被遍历的目标。目标只能是Collection或者是数组。增强for仅仅作为遍历操作出现。内部使用了迭代器。

在使用 foreach 输出的时候一定要注意的是,里面的操作泛型要指定具体的类型,这样在输出的时候才会更加有针对性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值