Java集合框架

65 篇文章 0 订阅

集合框架介绍
在这里插入图片描述
在这里插入图片描述
说明:对于以上的框架图有如下几点说明

1.所有集合类都位于java.util包下。Java的集合类主要由两个接口派生而出:Collection和Map,Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类。
2. 集合接口:6个接口(短虚线表示),表示不同集合类型,是集合框架的基础。
3. 抽象类:5个抽象类(长虚线表示),对集合接口的部分实现。可扩展为自定义集合类。
4. 实现类:8个实现类(实线表示),对接口的具体实现。
5. Collection 接口是一组允许重复的对象。
6. Set 接口继承 Collection,集合元素不重复。
7. List 接口继承 Collection,允许重复,维护元素插入顺序。
8. Map接口是键-值对象,与Collection接口没有什么关系。
9.Set、List和Map可以看做集合的三大类:
List集合是有序集合,集合中的元素可以重复,访问集合中的元素可以根据元素的索引来访问。
Set集合是无序集合,集合中的元素不可以重复,访问集合中的元素只能根据元素本身来访问(也是集合里元素不允许重复的原因)。
Map集合中保存Key-value对形式的元素,访问时只能根据每项元素的key来访问其value。

纯手写List框架
List集合代表一个有序集合,集合中每个元素都有其对应的顺序索引。List集合允许使用重复元素,可以通过索引来访问指定位置的集合元素。

List接口继承于Collection接口,它可以定义一个允许重复的有序集合。因为List中的元素是有序的,所以我们可以通过使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。

List接口为Collection直接接口。List所代表的是有序的Collection,即它用某种特定的插入顺序来维护元素顺序。用户可以对列表中每个元素的插入位置进行精确地控制,同时可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。实现List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。

ArrayList底层实现原理

  1. Arraylist底层基于数组实现

    private Object[] elementData;

  2. Arraylist底层默认数组初始化大小为10个object数组

    public ExtArraylist() throws Exception {
    this(10);
    }
    public ExtArraylist(int initialCapacity) throws Exception {
    	if (initialCapacity < 0) {
    	throw new IllegalArgumentException("初始容量不能小于0 " + initialCapacity);
    }
    elementData = new Object[initialCapacity];
    }
    
  3. 添加元素后大于当前数组的长度,则进行扩容,将数组的长度增加原来数组的一半。
    // 增大数组空间

    private void grow(int minCapacity) {
    	// overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); // 在原来容量的基础上加上
    												// oldCapacity/2
    if (newCapacity - minCapacity < 0)
    	newCapacity = minCapacity; // 最少保证容量和minCapacity一样
    if (newCapacity - MAX_ARRAY_SIZE > 0)
    	newCapacity = hugeCapacity(minCapacity); // 最多不能超过最大容量
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
    }
    

Vector底层实现原理
Vector是线程安全的,但是性能比ArrayList要低。
ArrayList,Vector主要区别为以下几点:
(1):Vector是线程安全的,源码中有很多的synchronized可以看出,而ArrayList不是。导致Vector效率无法和ArrayList相比;
(2):ArrayList和Vector都采用线性连续存储空间,当存储空间不足的时候,ArrayList默认增加为原来的50%,Vector默认增加为原来的一倍;
(3):Vector可以设置capacityIncrement,而ArrayList不可以,从字面理解就是capacity容量,Increment增加,容量增长的参数。

 private void grow(int minCapacity) {  
        // overflow-conscious code  
        int oldCapacity = elementData.length;  
        int newCapacity = oldCapacity + (oldCapacity >> 1); //扩充的空间增加原来的50%(即是原来的1.5倍)  
        if (newCapacity - minCapacity < 0) //如果容器扩容之后还是不够,那么干脆直接将minCapacity设为容器的大小  
            newCapacity = minCapacity;  
        if (newCapacity - MAX_ARRAY_SIZE > 0) //如果扩充的容器太大了的话,那么就执行hugeCapacity  
            newCapacity = hugeCapacity(minCapacity);  
        // minCapacity is usually close to size, so this is a win:  
        elementData = Arrays.copyOf(elementData, newCapacity);  
    }  

/**
* 自定List接口<br>
 * 
 * 
 * @param <E>
 */
public interface ExtList<E> {
public void add(E object);

public void add(int index, E object);

public Object remove(int index);

public boolean remove(E object);

public int getSize();

public Object get(int index);
}



public class ExtArrayList<E> implements ExtList<E> {

// 保存ArrayList中数据的数组
private transient Object[] elementData;
// ArrayList实际数量
private int size;

public ExtArrayList() {
	// 默认初始容量为10
	this(10);
}

public ExtArrayList(int initialCapacity) {
	if (initialCapacity < 0) {
		throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
	}
	// 初始化数组容量
	elementData = new Object[initialCapacity];
}

// 添加方法实现
public void add(Object object) {
	ensureExplicitCapacity(size + 1);
	elementData[size++] = object;
}

public void add(int index, Object object) {
	rangeCheck(index);
	ensureExplicitCapacity(size + 1);
	System.arraycopy(elementData, index, elementData, index + 1, size - index);
	elementData[index] = object;
	size++;
}

public void ensureExplicitCapacity(int minCapacity) {
	// 如果存入的数据,超出了默认数组初始容量 就开始实现扩容
	if (size == elementData.length) {
		// 获取原来数组的长度 2
		int oldCapacity = elementData.length;
		// oldCapacity >> 1 理解成 oldCapacity/2 新数组的长度是原来长度1.5倍
		int newCapacity = oldCapacity + (oldCapacity >> 1); // 3
		if (newCapacity < minCapacity) {
			// 最小容量比新容量要小的,则采用初始容量minCapacity
			newCapacity = minCapacity;
		}
		// System.out.println("oldCapacity:" + oldCapacity + ",newCapacity:"
		// + newCapacity);
		elementData = Arrays.copyOf(elementData, newCapacity);
	}
}
// public void add(Object object) {
// elementData[size++] = object;
// // 如果存入的数据,超出了默认数组初始容量 就开始实现扩容
// if (size == elementData.length) {
// // 新的数组容量
// int newCapacity = 2 * size;
// // 实现数组扩容
// Object[] newObjct = new Object[newCapacity];
// for (int i = 0; i < elementData.length; i++) {
// newObjct[i] = elementData[i];
// }
// elementData = newObjct;
// }
// }

// 获取数据
public Object get(int index) {
	rangeCheck(index);
	return elementData[index];
}

public Object remove(int index) {
	Object object = get(index);
	int numMoved = elementData.length - index - 1;
	if (numMoved > 0)
		System.arraycopy(elementData, index + 1, elementData, index, numMoved);
	elementData[--size] = null;
	return object;
}

public boolean remove(E object) {
	for (int i = 0; i < elementData.length; i++) {
		Object element = elementData[i];
		if (element.equals(object)) {
			remove(i);
			return true;
		}
	}
	return false;
}

private void rangeCheck(int index) {
	if (index >= size) {
		throw new IndexOutOfBoundsException("数组越界啦!");
	}
}

public int getSize() {
	return size;
	}

}

Java运算符

<<      :   左移运算符,num << 1,相当于num乘以2

>>      :     右移运算符,num >> 1,相当于num除以2

>>>    :     无符号右移,忽略符号位,空位都以0补齐

数组拷贝
Arrays.copyOf功能是实现数组的复制,返回复制后的数组。参数是被复制的数组和复制的长度
System.arraycopy System.arraycopy方法:如果是数组比较大,那么使用System.arraycopy会比较有优势,因为其使用的是内存复制,省去了大量的数组寻址访问等时间
复制指定源数组src到目标数组dest。复制从src的srcPos索引开始,复制的个数是length,复制到dest的索引从destPos开始。

src:源数组; srcPos:源数组要复制的起始位置;
dest:目的数组; destPos:目的数组放置的起始位置; length:复制的长度。
注意:src and dest都必须是同类型或者可以进行转换类型的数组.
有趣的是这个函数可以实现自己到自己复制,比如:

int[] fun ={0,1,2,3,4,5,6}; 
System.arraycopy(fun,0,fun,3,3);

则结果为:{0,1,2,0,1,2,6};
实现过程是这样的,先生成一个长度为length的临时数组,将fun数组中srcPos
到srcPos+length-1之间的数据拷贝到临时数组中,再执行System.arraycopy(临时数组,0,fun,3,3).

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值