java中的集合

到今天为止已经学完了所有的集合了,也是时候总结一下了,这段时间赶课有点紧,也没来得及更新博客,今天就总结一下java中常用的集合。

一. 集合的引入

在学习集合之前,一直在使用的“容器”是数组,数组是用于存储一组相同的数据类型的容器。

好处: 可以将大量的变量存储在容器中,不需要单独的命名,用一个整体的数组名字+元素在容器中的相对位置来对容器中的所有的元素进行操作。如 int b = a[1], double d = d[0]……

但是当我们需要存储一个对象中的数据,例如 小明:男,23岁等内容,普通的数组已经无法满足这个需求,因为数组适用于存储一组相同的数据类型的容器。

此时,我们就用到了对象类型的数组

顾名思义,在对象类型的数组中,存储的都是应用数据类型,数组中的每个元素都是某个对象的地址。

但是数组也有自己的弊端:

  1. 无法继续添加新的元素,容量已经确定。
  2. 无法删除容器中的元素,只能修改已有的元素值(指的是没有删除方法,只能通过覆盖删除)。
  3. 功能太少

解决方法:

  1. 定义某个引用类型,包含一个数组的成员变量,成员变量私有,不让外界直接访问。
  2. 提供公共的访问方式,定义操作数组的各种方法。
  3. 添加功能:若数组已经满了,就申请新的数组,将原数组拷贝到新的数组中。
  4. 删除功能:将删除的位置,使用后面的元素覆盖,并且元素个数减一,计数器减一。
  5. 是否包含功能:在方法中对数组进行遍历,比较判断是否包含。

根据上述的需求,我们来实现一下这个类。

public class MyCollection {

private Object[] o = new Object[10];// 定义一个Object类型的数组,因为Object是所有类的父类,可以存储任意类型的数据。
private int count = 0;// 元素计数器。

// 添加元素的方法
public void add(Object obj) {
	if (o.length - 1 == count) {//当数组的长度-1和数组中元素个数相同时数组扩容。
		Object[] newo = new Object[count * 2];//创建一个新的数组,数组长度是现有元素个数的两倍。
		for (int i = 0; i < o.length; i++) {
			newo[i] = o[i];//循环将老的数组中的内容复制给新的数组。
		}
		o = newo;//将老的数组的引用指向新的数组(也就是赋值)。
	}
	o[count] = obj;
	count++;
}

// 删除元素的方法
public void remove(int index) {
	for (int i = index; i < count; i++) {
		o[i] = o[i + 1];// 将后面的元素往前面挪,覆盖要删除的元素。
	}

	count--;// 删除元素后,元素总个数减一。
}

// 获取元素的方法
public Object get(int index) {

	return o[index];// 获取数组元素的方法

}
//判断是否存在某个元素的方法
public boolean exist(Object obj) {
	for(int i = 0; i < count; i++) {
		if(o[i].equals(obj)) {
			return true;
		}
	}
	return false;
	
}

// 返回这个容器元素占用的长度。
public int length() {
	return count;
}
//返回这个容器的总长度
public int size() {
	return o.length;
	}
}

在将来使用中,使用者可以直接调用这些方法,就不需要知道方法的实现方式,操作起来非常方便,这就是集合。

二.集合与数组的比较

相同点

  1. 都是容器
  2. 都是为了方便操作大量的数据,为了避免给大量变量起名字,都可以通过操作容器的有规律的简单的数据(索引),来操作没规律的复杂的数据(元素)。

不同点

  1. 存储的内容不同
    数组:即可以存储基本的类型,也可以存储引用类型的。
    集合:仅可以存储引用类型,(存储进去的基本数据类型都变成了包装类来存储)。
  2. 存储的数量不同
    数组:固定大小,无法扩容。
    集合:可以根据数据的多少扩容。
  3. 支持的功能不同
    数据:只支持修改。
    集合:支持增删改查,各种判断。

三.集合的体系结构

  1. 集合由于存储了大量的元素,根据元素和元素的关系,有不同的存储逻辑,有了不哦他能过的集合接口。
  2. 同一种逻辑关系,在内存中有不同的实现方式,又有不同的实现类,形成了一个集合的实现类。
  3. 分类:
    单列集合:每个元素都是单独的个体。
    双列集合:成对出现的集合元素。

在这里插入图片描述

四.Collection

Collection是单列集合的顶层接口,定义了单列集合中应该拥有的方法,但不能创建对象,需要实现类来测试Collection中的方法

常用的方法:

1. add(Object obj)                     //添加
2. remove(Object obj)  			       //删除
3.clear()                              //清空集合
4.size()      	                       //元素个数
5.isEmpty()                            //判空
6.contain()                            //判断是否存在该对象

Collection中带all的方法

  1. 说明,都是用于和另外一个集合做运算的。

  2. 罗列:

     addAll(Collection c)
     将参数集合中的所有元素都添加到调用者的集合中。
     removeAll(Collection c)
     将参数集合中的所有元素在调用者集合中删除。
     containsAll(Collection c)
     判断参数集合中的所有元素是否都存在与调用者集合中。
     retainAll(Collection c)
     将参数集合中的所有元素,都从调用者集合中删除,调用者集合中,只保留也存在于参数集合中的那些元素
    

五.集合的遍历
第一种遍历方式:转为Object [] 数组
方法:Object[] toArray();
通过从集合转为数组,通过遍历数组间接的遍历集合。

第二种方法: 迭代器

迭代器:在java中,在集合中用于一个一个遍历元素的对象,用于帮助我们遍历当前集合对象的。

迭代器的获取:
Collection接口中,定义了一个获取迭代器对象的方法

Iterator iterator();

迭代器的使用:

  1. Iterator接口,用于定义迭代器对象应该具有什么功能。
  2. iterator方法返回的不是接口,而是Iterator接口的实现类对象。
  3. 接口中有3个方法:
    hasNext()
    判断是否有下一个元素
    next()
    获取下一个元素
    remove()
    删除迭代器当前正在迭代的元素

代码示例:

	public class Test3 {
	public static void main(String[] args) {
	Collection c = new ArrayList(); //接口不能创建对象,要使用实现类。
	c.add("abc");
	c.add("xyz");
	c.add(123);
	
	//获取迭代器对象:
	Iterator it = c.iterator();
	
	//使用迭代器中的方法进行遍历集合
	
	while(it.hasNext()) {
		System.out.println(it.next());
	}
	
	}

	/*
 	* 打印结果: 
 	* abc 
 	* xyz 
	 * 123
	 */
	}

迭代器的注意事项:

  1. 虽然多次调用的都是next方法,但是每次获取的内容不相同的(因为迭代器在调用next方法时,会移动迭代器的位置,到下一个元素)。
  2. 两个方法的比较: 1、hashNext不会移动迭代器 2、next会将迭代器移动到下一个元素的位置。
  3. 一定不要只判断一次hasNext,调用多次next方法。

代码示例:

public class Test3 {
//多次调用next方法:
	public static void main(String[] args) {
		Collection c = new ArrayList();
		c.add(new Person(23, "zhangsan"));
		c.add(new Person(24, "lisi"));
		c.add(new Person(25, "wangwu"));
		Iterator it = c.iterator();
		while (it.hasNext()) {
			it.next();
			System.out.println(((Person)it.next()).getName() + "  " + ((Person)it.next()).getAge());

		}

	}
/*
 * 打印结果:lisi  25
 */

}

五.List接口

概述:
是Collection集合中的有序的子接口,用于定义那些具有顺序,元素具有位置的集合应该拥有的功能
特点:

  1. 有索引(给每个元素有了一个位置的标记)。
  2. 有序(有先后顺序)。
  3. 可以重复

特有方法:

	1、add(int index, Object obj)
 	 	在指定索引上,添加元素
 	2、remove(int index)
 	 	删除指定索引上的元素
 	3、set(int index, Object obj)
 	 	将索引为index的位置,修改为obj值
 	4、get(int index)
 	 	获取索引为index的值

List的遍历:
List和Collection不同,List中的每个元素都具有自己的位置,因此可以通过索引来遍历List集合。

  • 1.索引遍历
public static void printList(List list) {
		for (int i = 0; i < list.size(); i++) {
			Object obj = list.get(i);
			System.out.println(obj);
		}
	}
  • 2.迭代器遍历:

List也是Collection的一个子接口,自然也可以使用迭代器遍历

public class Test3 {
	public static void main(String[] args) {
		List list = new ArrayList();
		list.add("a");
		list.add("b");
		list.add("c");
		list.add("d");
		list.add("e");
		Iterator it = list.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}

	}

注意事项:
在使用迭代器遍历集合的同时,使用了集合对象对集合元素进行增删,会导致并发修改异常。

public class Test3 {
	public static void main(String[] args) {
		List list = new ArrayList();
		list.add("a");
		list.add("b");
		list.add("c");
		list.add("d");
		list.add("x");
		Iterator it = list.iterator();
		while (it.hasNext()) {
			Object obj = it.next();
			if (obj.equals("x")) {
				list.add("java");
			}
		}
		System.out.println(list);
	}
}

在这里插入图片描述

Concurrent Modification Exception 
	并发	   修改	       异常

解决方法:(只能针对List解决)
1、集合遍历,集合增删:只能针对List解决。
集合遍历:List的特有遍历方式。
集合增删:add、remove
2、迭代器遍历,迭代器增删:只能针对List解决。
迭代器遍历:获取迭代器,使用迭代器的hashNext和next方法遍历即可。
迭代器删除:迭代器中有一个remove,可以删除当前迭代的元素。
迭代器增加:迭代器中没有增加的方法,只能获取一个特殊的迭代器。

  • 3.列表迭代器

1.ListIterator:List接口特有的迭代器所实现的接口。
2.列表迭代器的获取:
在List集合中,有一个特有方法,listIterator()
3.使用:

		add(Object obj)
 	 	 	在当迭代的位置,添加元素
 	 	hasPrevious()
 	 	 	判断是否有上一个元素
 	 	previous()
 	 	 	获取上一个元素
 	 	set(Object obj)
 	 	 	将当前迭代的位置,替换为obj元素

代码示例:

public class Test3 {
	public static void main(String[] args) {
		List list = new ArrayList();
		list.add("a");
		list.add("b");
		list.add("c");
		list.add("d");
		list.add("x");
		ListIterator it = list.listIterator();//ListIterator 
		System.out.println(it.next());
		System.out.println(it.previous());//读取上一个
		System.out.println(list);
		it.set("it.set");//特有的set方法
		System.out.println(list);

	}
}

在这里插入图片描述

六.List的实现类

1.List是一个接口,在接口中定义了有序集合的应该具有的功能
2.如果要实现这个接口,有不同的方式(定义一个表格、通过物理位置、通过记录下一个元素),根据不同的实现方式,就有不同的实现类
3.实现类:

 	Vector 	 	 	    已经过时的类,jdk1.0,线程安全,速度太慢,顺序存储,数组实现
 	Arraylist 	 	 	线程不安全,顺序存储,数组实现,查询修改快,增删慢
 	LinkedList 	 	    线程不安全,链式存储,节点实现,查询修改慢,增删快

Vector已经过时就不在这里说了,直接从ArrayList开始。

ArrayList:

1、使用最频繁的一个单列集合
2、线程不安全,顺序存储,数组实现,查询修改快,增删慢
3、没有特有的方法,使用List接口中的方法
4、顺序存储、数组实现的特点。

ArrayList的特点:

  1. 数组都是连续存储的,都挨在一起。
  2. 数组中每个元素分配的空间大小都是相同的。
  3. 可以计算出要访问的索引的内存地址。
  4. 可以通过一次寻址直接找到要访问的元素。
  5. 无论数组有多大,无论要访问的索引有多大,访问的代价都是相同的,与访问的集合的规模无关。
  6. 综上,查询的速度非常快。
    在这里插入图片描述
    代码示例:
import java.util.ArrayList;

public class Demo09_ArrayList {

	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		list.add("a");
		list.add("b");
		list.add("c");
		
		System.out.println(list.get(1));
		
		list.add(0, "x");
		
		System.out.println(list);
	}
}

ArrayList的缺点:

  1. 所有元素都挨在一起,所以无法直接删除元素。
  2. 添加元素时,只能把后面的元素都向后移动一个位置,给新的元素腾出位置才能添加元素。
  3. 由于集合中可能存储很多的元素,添加或删除一个元素的代价就需要移动很多很多的元素。
  4. 代价和集合的规模有关, 集合的规模越大,代价就越大,增删的速度就越慢。

LinkedList

线程不安全,链式存储,节点实现,查询修改慢,增删快

在这里插入图片描述

LinkedList的特点:

使用节点实现,每个元素都是一个节点,节点中分为 两个数据域,分别存储前后节点的地址,和数据域,用来存储数据

LinkedList的优势:

  1. 增删元素时,只需要修改前后两个节点的记录地址的部分,其余的节点都不需要动。
  2. 和集合的规模无关。
  3. 综上,增删速度非常快

代码示例:

import java.util.LinkedList;

public class Demo10_LinkedList {
	public static void main(String[] args) {
		LinkedList list = new LinkedList();
		list.add("zhangsan");
		list.add("lisi");
		list.add("wangwu");
		list.add("zhaoliu");
		list.add("zhouqi");
		list.add("guoba");
		list.add("hejiu");
		list.add("chishi");
		
		System.out.println(list.get(5));
		list.add(0, "xiaoer");
		System.out.println(list);
	}
}

LinkedList的缺点:

  1. 查找指定元素时需要根据前一个节点来获取后一个节点的地址,根据这个地址在去寻找下一个元素的节点,在获取下一个元素的地址,知道寻找到指定的元素。
  2. 寻址次数非常多,寻址的次数和集合的规模有关,集合元素越多寻址的次数就越多,效率越低。

LinkedList的特有方法
1.由于在LinkedList中,维护和记录了整个集合的头部和尾部的节点地址,操作头部和尾部特别容易,代价非常低,提供了大量操作头部和尾部的方法
2.罗列:

	addFirst(Object obj)
 	addLast(Object obj)
 	removeFirst()
 	removeLast()
 	getFirst()
 	getLast()

这次就先到这里,在Set集合的时候需要用到泛型的知识,下次会把详细的写一下,再来看Set集合。

最后谢谢大家看到这里喜欢请点个赞

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值