Java——List和ArrayList源代码

1. List

1.1 List集合接口的特征

特征:
	1. 有序:添加顺序和存储顺序一致。
	2. 可重复:相同元素可以同时添加。

List<E>接口下的实现类存在一定的下标操作机制:
	1. AllayList<E>底层数组形式操作,可以通过下标直接访问。
	2. LinkedList<E>底层是一个双向链表结构,下标-->计数器

1.2 特定的方法

	//增加方法:
		add(E, e);
			//list接口下,当前方法是添加元素到集合的末尾——尾插法
		addAll(Collection<? extends E>c);
			//list接口下,当前方法是添加另一个集合到当前集合末尾
			//要求添加的集合中保存的元素和当前集合保存元素一致,或者说是当前集合保存元素的子类
		add(int index, E e);
			//在指定的下标位置,添加指定元素
		addAll(int index, Collection<? extends E>c);
			//在指定的下标位置,添加指定的集合,集合要求同上一个addAll方法。
	//删除方法
		void clear();
			//清空整个集合
		remove(Object obj);
			//删除集合中的指定元素
		removeAll(Collection<?>c);
			//删除两个集合的交集
		retainAll(Collection<?>c);
			//保留两个集合的交集
		E remove(int index);
			//删除集合中指定下标的元素,返回值是被删除的元素。
	//更改方法
		E set(int index, E e);
			//使用指定元素替换指定下标index的元素,返回值是被替换掉的元素。
	//查询方法
		int size();
			//有效元素个数
		boolean isEmpty();
			//判断当前集合是否为空
		boolean contains(Object obj);
		boolean containsAll(Collection<?>c);
		int indexOf(Object obj);
			//找出指定元素在集合中的第一次出现位置
		int lastIndexOf(Object obj);
			//找出指定元素在集合中最后一次出现位置
		E get(int index);
			//获取指定下标的元素
		List<E> subList(int fromIndex, int endIndex);
			//获取当前集合的子集合

2. ArrayLIst可变长数组

2.1 特征

	数组形式的操作方式,查询效率高但是删除、增加效率低。
	数组:
		object类型数组

2.2 方法

	方法:
		ArrayList使用的方法基本上都是从List接口中遵从实现的方法。
		特征:
			ensureCapacity(int minCapatity)
				判断当前容量是否足够。
			trimToSize();
				判断整个数组容量-->size有效元素个数

2.3 自定义实现的ArrayList

在类内定义成员变量及构造方法:

/**
	 * 准备一个底层数组,用于存储数据内容
	 */
	private Object[] elements;
	
	/**
	 * 初始化默认容量
	 */
	private static final int DEFAULT_CAPACITY = 10;
	
	/**
	 * 最大数组容量, -8是为了腾出一定的空间,保存数组的必要内容
	 */
	private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
	
	/**
	 * 当前底层数组中保存的有效元素个数
	 */
	private int size = 0;
	
	/**
	 * 无参数构造方法,但是需要提供给用户一个初始化容量来保存必要的数据
	 */
	public MyArrayList() {
		elements = new Object[DEFAULT_CAPACITY];
	}

保存元素的容量的初始化:

/**
	 * 用户指定保存元素容量的初始化过程,要求用户指定的容量范围是有效的
	 * 
	 * @param initCapacity 用户指定的初始化容量,但是不能小于等于0 ,不能大于
	 * 						MAX_ARRAY_SIZE
	 */
	public MyArrayList(int initCapacity) {
		// 用户传入参数的合法性判断过程
		if (initCapacity < 0 || initCapacity > MAX_ARRAY_SIZE) {
			// 抛出异常
			// IllegalArgumentException 是一个RuntimeException运行时异常的子类
			// 不需要强制声明抛出异常
			throw new IllegalArgumentException("IllegalArgumentException : " + initCapacity);
		}
		
		elements = new Object[initCapacity];
	}
  1. 增加方法:
/**
	 * 尾插法 在集合末尾添加元素
	 * 
	 * @param e 指定元素
	 * @return 添加成功返回true,失败返回false
	 */
	public boolean add(E e) {
		return this.add(size, e);
	}
	/**
	 * 在指定下标位置添加元素
	 * 
	 * @param index 指定的下标
	 * @param e	指定元素
	 * @return 添加成功返回true,失败返回false
	 */
	public boolean add(int index, E e) {
		if (index < 0 || index > size) {
			throw new ArrayIndexOutOfBoundsException("下标越界!");
		}
		
		for(int i = size; i > index; i--) {
			elements[i] = elements[i - 1];
		}
		elements[index] = e;
		size += 1;
		return true;
	}
	/**
	 * 添加集合在此集合的末尾
	 * 
	 * @param list 自定义ArrayList,要求存储元素和当前集合一致,或者是其子类
	 * @return 添加成功返回true,失败返回false
	 */
	public boolean addAll(MyArrayList<? extends E> list) {
		
		return this.addAll(size, list);
	}
	/**
	 * 在指定下标位置添加集合
	 * 
	 * @param index 指定下标
	 * @param list 自定义ArrayList,要求存储元素和当前集合一致,或者是其子类
	 * @return 添加成功返回true,失败返回false
	 */
	public boolean addAll(int index, MyArrayList<? extends E> list) {
		Object[] array = list.toArray();
		int newSize = array.length;

		ensureCapacity(size + newSize);

		for (int i = 0; i < newSize; i++) {
			elements[i + size] = array[i];
		}

		size += newSize;
		return true;
	}
  1. 删除方法:
/**
	 * 删除下标元素
	 * 
	 * @param index 指定的下标范围
	 * @return 删除成功返回对应元素,失败返回null
	 */
	public E remove(int index) {
		if (-1 == index) {
			return null;
		}
		
		E e = get(index);
		
		for (int i = index; i < size - 1; i++) {
			elements[i] = elements[i + 1];
		}
		
		// 原本最后一个有效元素位置上的内容赋值为null
		elements[size - 1] = null;
		size -= 1;
		
		return e;
	}
  1. 查询方法:
/**
	 * 查询指定元素在集合中的第一次出现下标位置
	 * @param obj 指定的元素
	 * @return 返回值大于等于0表示找到元素,否则返回-1
	 */
	public int indexOf(Object obj) {
		int index = -1;

		for (int i = 0; i < size; i++) {
			// equals 判断对象是否一致地方的方法
			if (obj.equals(elements[i])) {
				index = i;
				break;
			}
		}
		
		return index;
	}
	
	/**
	 * 查询指定元素在集合中的最后一次出现下标位置
	 * 
	 * @param obj 指定的元素
	 * @return 返回值大于等于0表示找到元素,否则返回-1
	 */
	public int lastIndexOf(Object obj) {
		int index = -1;

		for (int i = size - 1; i >= 0; i--) {
			// equals 判断对象是否一致地方的方法
			if (obj.equals(elements[i])) {
				index = i;
				break;
			}
		}
		
		return index;
	}
  1. 更改方法:
/**
	 * 替换指定下标的元素
	 * 
	 * @param index 指定下标元素,但是必须在有效范围以内
	 * @param e 符合泛型约束的对应数据类型
	 * @return 被替换的元素
	 */
	public E set(int index ,E e) {
		if (index < 0 || index >= size) {
			throw new ArrayIndexOutOfBoundsException(index);
		}
		
		E temp = get(index);
		elements[index] = e;
		
		return temp;
	}
  1. 获取指定下标元素方法:
/**
	 * 获取集合中指定下标的元素
	 * 
	 * @param index 指定下标的范围,但是不能超出有效下标范围
	 * @return 返回对应的元素
	 */
	@SuppressWarnings("unchecked")
	public E get(int index) {
		if (index < 0 || index > size) {
			throw new ArrayIndexOutOfBoundsException(index);
		}
		
		return (E) elements[index];
	}
  1. 判断指定下标元素是否存在方法:
/**
	 * 判断指定元素是否存在 
	 * 
	 * @param obj 指定元素
	 * @return 存在返回true,不存在返回false
	 */
	public boolean contains(Object obj) {
		return indexOf(obj) > -1; 
	}
	public boolean containsAll(MyArrayList<? extends E> list) {
		// 判断list是否有内容 已经当前list对应的地址是不是null
		if (null == list || list.isEmpty()) {
					throw new NullPointerException();
		}

		// 1. 计数器 找出list参数集合中下标为0的元素在集合中出现的位置次数
		int count = 0;
				
		boolean flag = true;
				
		// 2. 存储list参数集合中下班未0的元素出现的位置
		int[] indexArr = new int[this.size];
				
		for (int i = 0; i < this.size; i++) {
			// 在当前集合中下标为i的元素和list参数集合中下标为0的元素比较
			if (this.get(i).equals(list.get(0))) {
					indexArr[count] = i;
					count += 1;
			}
		}
				
		// 4. 判断是否存list.get(0)的元素
		if (0 == count) {
			return false;
		}
				
		// 5. 进入循环,开始匹配,从找到的所有list[0]匹配
		for (int i = 0; i < count; i++) {
			// 6. 遍历操作当前集合
			// 从当前集合中对应查询位置 + 1开始,循环次数是list.size() - 1
			for (int j = indexArr[i] + 1; j < indexArr[i] + list.size(); j++) {
						
				// list从下标1开始获取元素
				int index = 1;
				if (!this.get(j).equals(list.get(index++))) {
					flag = false;
					break;
				}
						
				flag = true;
			}
					
					
			if (flag) {
				break;
			}
					
		}
				
		return flag;
	}
  1. 判断集合是否为空方法:
/**
	 * 判断集合是否是空的
	 * 
	 * @return 如果为空,返回true, 否则返回false
 	 */
	public boolean isEmpty() {
		return size == 0;
	}
  1. 判断集合中有效元素个数方法:
/**
	 * 获取当前集合中有效元素个数
	 * 
	 * @return 有效元素个数
	 */
    public int size() {
    	return size;
    }
  1. 数组容量判断以及数组扩容方法:
/**
	 * 每一次添加元素,都需要进行容量判断,如果满足可以进行添加操作
	 * 不满足需要制定grow方法
	 * 
	 * @param minCapacity 要求的最小容量
	 */
	private void ensureCapacity(int minCapacity) {
		if (minCapacity > elements.length) {
			// 完成一个底层数组的扩容方法
			grow(minCapacity);
		}
	}
	/**
	 * 底层数组的扩容方法,原理是创建新数组,移植数据,保存新数组地址
	 * 
	 * @param minCapacity 要求的最小容量
	 */
	private void grow(int minCapacity) {
		// 1. 获取原数组容量
		int oldCapacity = elements.length;
		
		// 2. 计算得到新数组容量
		int newCapacity = oldCapacity + (oldCapacity >> 1);
		
		// 3. 判断新数组容量是否满足要求
		if (newCapacity < minCapacity) {
			newCapacity = minCapacity;
		}
		// 新数组容量是大于允许的最大数组容量
		if (newCapacity > MAX_ARRAY_SIZE) {
			// 二次判断minCapacity是否小于MAX_ARRAY_SIZE
			if (minCapacity < MAX_ARRAY_SIZE) {
				// 最小要求是不大于MAX_ARRAY_SIZE,代码可以运行
				newCapacity = minCapacity;
			} else {
				throw new OutOfMemoryError("Overflow MAX_ARRAY_SIZE");
			}
		}
		
		/*
		 * 4. 使用数组工具类方法完成操作
		 * Arrays.copyOf(源数据数组,可以是任意类型,采用泛型约束, 指定的新数组容量);
		 * 		a. 根据指定的新数组容量创建对应泛型数据类型的新数组
		 *      b. 从源数据数组中拷贝内容到新数组中
		 *      c. 返回新数组首地址
		 */
		elements = Arrays.copyOf(elements, newCapacity);
	}
发布了5 篇原创文章 · 获赞 4 · 访问量 154

猜你喜欢

转载自blog.csdn.net/qq_41424681/article/details/104443028