栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【巩固基础】集合框架:Collection,list

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【巩固基础】集合框架:Collection,list

集合分类

左侧由Collection而来的集合类属于存储很多单个数据
右侧由map而来的则存储键值对

Collection

collection为list和set的父接口,他要求了这些集合类应该实现哪些内容
集合层次结构中的根界面 。 集合表示一组被称为其元素的对象。 一些集合允许重复元素,而其他集合不允许。 有些被命令和其他无序。 JDK不提供此接口的任何直接实现:它提供了更具体的子接口的实现,如Set和List 。 该界面通常用于传递集合,并在需要最大的通用性的情况下对其进行操作。

常用方法


boolean add(E e) 增加元素
clear() 从此集合中删除所有元素
remove(object o) 从该集合中删除指定元素的单个实例
iterator() 返回此集合中的元素的迭代器。
size() 返回此集合中的元素数。
contains(object o) 如果此集合包含指定的元素,则返回 true 。
equals(object o) 将指定的对象与此集合进行比较以获得相等性。
isEmpty() 如果此集合不包含元素,则返回 true 。

list

list继承了Collection接口并在原接口上做了增强

list常用方法


boolean add(E e) 将指定的元素追加到此列表的末尾(可选操作)。
void add(int index, E element) 将指定的元素插入此列表中的指定位置(可选操作)。
E get(int index) 返回此列表中指定位置的元素。
set(int index, E element) 用指定的元素(可选操作)替换此列表中指定位置的元素。
boolean remove(Object o) 从列表中删除指定元素的第一个出现(如果存在)(可选操作)。
E remove(int index) 删除该列表中指定位置的元素(可选操作)。

可以注意到最后两个remove的操作都只传递一个参数
那么我们使用list.remove(2)时究竟是删除索引为2的参数还是内容为2的参数呢
使用如下程序进行测试:

    public static void main(String[] args) {
        List list=new ArrayList();
        list.add(12);
        list.add(99);
        list.add(69);
        list.add(2);
        list.remove(2);
        System.out.println(list);
    }

结果:

[12, 99, 2]

由此得知是删除了索引为2的数据
那么我们想删除2这个数据呢

    public static void main(String[] args) {
        List list=new ArrayList();
        list.add(12);
        list.add(99);
        list.add(69);
        list.add(2);
        list.remove(new Integer(2));
        System.out.println(list);
    }

我们是需要这样操作即可
追究其原因,是因为Collection中存储的对象是包装类,而2是基本数据类型,所以只需要将2变为包装类就可以删除2这个数据了
但这点不适用于add时,因为add会进行自动装箱操作而调用remove时则不会进行自动装箱

arrayList

arraylist本质为一个数组以及一个int的组合

1.7源码 构造方法

在1.7中构造器默认开辟10个长度的数组以供使用

add方法 add(E e)
// 添加元素
	public boolean add(E e) {
		// 扩容
		ensureCapacityInternal(size + 1);
		//将数组第size位置添加为该元素,并扩充size
		elementData[size++] = e;
		//返回真
		return true;
	}

其他代码都很好理解,主要是第一句ensureCapacityInternal是个什么函数呢,我们点击去看一下

ensureCapacityInternal(int minCapacity)


这里可以看见此函数做出了一个判断
如果目前长度不够用了,就调用grow函数并将其需要的最小容量传过去
那么grow里又写了什么呢,继续点进去看一下

grow


分析一下
这个函数第一步先预估了一下新数组的长度
使newcapacity等于了旧数组的1.5倍
下一步判断,如果新的长度仍不能满足要求
使新长度等于最低的长度要求
关于下一步目前没有安装1.7版本的JDK所以没能理解
最后一步
arraycopyOf(T[] original, int newLength) 复制指定的数组,用空值截断或填充(如有必要),以便复制具有指定的长度。
创建新的数组并将原存放数据的数组指定回去

1.8源码 构造方法

这里与jdk1.7版本中有较大差异

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
	public ArrayList() {
		//将主要用于存储数据的数组指向了一个空数组
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

将容量的初始化交给了别的函数比如add
个人理解是为了减少空间的浪费

add(E e)
// 添加元素
	public boolean add(E e) {
		// 扩容
		ensureCapacityInternal(size + 1);
		//将数组第size位置添加为该元素,并扩充size
		elementData[size++] = e;
		//返回真
		return true;
	}

截止目前 add操作和1.7中几乎一样,下一步开始变的不太一样

ensureCapacityInternal(int minCapacity)
private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

这里又调用了两个未知的函数
我们先选择calculateCapacity点进去看一下

calculateCapacity(Object[] elementData, int minCapacity)
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //当前数据数组是否为原空数组
        //如果是则将 最小需要值与DEFAULT_CAPACITY比较得到较大的一个将其返回
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //若不为空则返回最小的需要值
        return minCapacity;
    }

我们再看会上一层,它将本层函数得到的值传给了ensureExplicitCapacity()

ensureExplicitCapacity(int minCapacity)

此函数则和jdk1.7中的ensureCapacityInternal(int minCapacity)一致

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)//比较传来的参数和现在存储数据数组的长度
            grow(minCapacity);//扩容
    }
grow(int minCapacity)
	private void grow(int minCapacity) {
		// overflow-conscious code
		int oldCapacity = elementData.length;
		//旧的容量为当前数组长度
		int newCapacity = oldCapacity + (oldCapacity >> 1);
		//新的容量为当前数组长度的1.5倍
		if (newCapacity - minCapacity < 0)
		//判断当前的容量是否不足于需要的最小容量
			newCapacity = minCapacity;
			//如果不足,则新容量为当前需要的最小容量
		if (newCapacity - MAX_ARRAY_SIZE > 0)
		//判断现在的新容量是否大于int的最大容量-8
			newCapacity = hugeCapacity(minCapacity);
			//如果大于,则进去hugeCapacity方法返回新的容量
		elementData = Arrays.copyOf(elementData, newCapacity);
		//按照最新容量复制数组,实现扩容
	}

分析一下
这个函数第一步先预估了一下新数组的长度
使newcapacity等于了旧数组的1.5倍
下一步判断,如果新的长度仍不能满足要求
使新长度等于最低的长度要求
下一步 判断现在的新容量是否大于int的最大容量-8
//如果大于,则进去hugeCapacity方法返回新的容量
最后一步
arraycopyOf(T[] original, int newLength) 复制指定的数组,用空值截断或填充(如有必要),以便复制具有指定的长度。
创建新的数组并将原存放数据的数组指定回去

hugeCapacity(int minCapacity)
 private static int hugeCapacity(int minCapacity) {
		if (minCapacity < 0) 
		// 如果当前需要的最小容量小于0
			throw new OutOfMemoryError();
			//抛出内存溢出的错误
		return (minCapacity > MAX_ARRAY_SIZE) ?
		//返回当前最小容量与MAX_ARRAY_SIZE谁大
			Integer.MAX_VALUE :
			//最小容量大,返回Integer.MAX_VALUE ,即2147483647
			MAX_ARRAY_SIZE;
			//否则返回MAX_ARRAY_SIZE,即2147483639
	}

vector

同样实现了list接口,且底层同样是采用数组扩容机制,源码也与arraylist接近,不过扩容机制更为激进
区别:
vector是线程安全的,效率低
arraylist则是不安全的,效率高

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/727133.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号