zoukankan      html  css  js  c++  java
  • 0515项目优化和List集合

    0515项目优化和List集合

    1. 项目优化

    1.1 分析当前情况
    问题
    	数据存储是数组形式,数据类型明确。复用度较低。
    
    需求
    	Student操作使用的代码,StudentManager想要操作考虑一个复用度问题。不管更换什么数据类型, 都是可以直接使用。
    
    解决问题
    	1. 泛型
    	2. 数组不能使用泛型,但是这个数组又需要保存各式各样的数据
    		Object
    
    1.2 使用泛型和Object优化项目
    package com.qfedu.student.system.util;
    
    import com.qfedu.student.system.myexception.IllegalCapacityException;
    import com.qfedu.student.system.myexception.OverflowMaxArraySizeException;
    
    /**
     * 自定义数据存储工具,MyList用于存储代码中操作的数据
     * 
     * @author Anonymous
     *
     * @param <E> 使用泛型满足更多的情况
     */
    public class MyList<E> {
    
    	/**
    	 * 保存数据的底层Object数组,可以保存任意数据类型,但是在操作方法是会
    	 * 对操作的数据类型,通过泛型进行约束操作
    	 */
    	private Object[] elementData = null;
    	
    	/**
    	 * DEFAULT_CAPACITY 默认容量,这里是一个带有名字的常量
    	 */
    	private static final int DEFAULT_CAPACITY = 10;
    
    	/**
    	 * 数组最大容量,是int类型最大值 - 8 -8等我给你讲
    	 */
    	private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
    	/**
    	 * 当前底层Object数组中有效元素个数
    	 */
    	private int size = 0;
    	
    	/**
    	 * 无参数构造方法,使用DEFAULT_CAPACITY约束初始化容量
    	 */
    	public MyList() {
    		elementData = new Object[DEFAULT_CAPACITY];
    	}
    	
    	/**
    	 * 提供给用户可以指定初始化容量的操作方法
    	 * 
    	 * @param initCapacity 用户指定的初始化容量,但是必须在合理范围以内
    	 * @throws IllegalCapacityException 用户指定的初始化容量超出范围
    	 */
    	public MyList(int initCapacity) throws IllegalCapacityException {
    		if (initCapacity < 0 || initCapacity > MAX_ARRAY_SIZE) {
    			throw new IllegalCapacityException("Input Parameter is Invalid!");
    		}
    		
    		elementData = new Object[initCapacity];
    	}
    	
    	/**
    	 * 添加方法,添加在创建MyList对象是约束的具体数据类型
    	 * 
    	 * @param e 通过泛型约束的具体数据类型
    	 * @return 添加成功返回true, 否则返回false
    	 * @throws OverflowMaxArraySizeException 
    	 */
    	public boolean add(E e) throws OverflowMaxArraySizeException {
    		
    		if (size == elementData.length) {
    			// 添加操作是一个元素,最小容量要求就是在原本的数组容量之上 + 1
    			grow(size + 1);
    		}
    		
    		elementData[size] = e;
    		size += 1;
    		
    		return true;
    	}
    	
    	/**
    	 * 删除保存在MyList中的指定元素
    	 * 
    	 * @param obj 用户指定的元素
    	 * @return 删除成功返回true,否则返回false
    	 */
    	public boolean remove(Object obj) {
    		int index = indexOf(obj);
    		
    		return remove(index);
    	}
    
    	/**
    	 * 删除指定下标的的元素
    	 * 
    	 * @param index 用户指定的下标位置
    	 * @return 删除成功返回true,否则返回false
    	 */
    	public boolean remove(int index) {
    		if (index < 0 || index >= size) {
    			return false;
    		}
    		
    		for (int i = index; i < size - 1; i++) {
    			elementData[i] = elementData[i + 1];
    		}
    
    		// 原本最后一个有效元素位置赋值为null
    		elementData[size - 1] = null;
    
    		// 有效元素个数 - 1
    		size -= 1;
    
    		return true;
    	}
    	
    	/**
    	 * 根据指定元素,找出对应的下标位置,没有找到返回-1
    	 * 
    	 * @param obj 用户传入的元素
    	 * @return 找到元素返回值大于等于0,没有找到返回-1
    	 */
    	public int indexOf(Object obj) {
    		int index = -1;
    		
    		for (int i = 0; i < size; i++) {
    			if (obj.equals(elementData[i])) {
    				index = i;
    				break;
    			}
    		}
    		
    		return index;
    	}
    	
    	/**
    	 * 替换修改方法,使用指定元素替换指定下标的元素
    	 * 
    	 * @param index 指定的下标位置,约束在合理范围以内
    	 * @param e 泛型约束的指定数据类型,保证数据类型一致化
    	 * @return 被替换掉的元素。如果没有被替换的元素,返回null
    	 */
    	public E set(int index, E e) {
    		if (index < 0 || index >= size) {
    			return null;
    		}	
    		
    		// 取出原本的元素
    		E temp = (E) elementData[index];
    		
    		elementData[index] = e;
    		
    		return temp;
    	}
    	
    	/**
    	 * 返回当前MyList底层数组中保存有效元素个数是多少个
    	 * 
    	 * @return 返回当前MyList底层数组中有效元素个数
    	 */
    	public int size() {
    		return size;
    	}
    	
    	/**
    	 * 判断当前MyList中是否为空
    	 * 
    	 * @return 如果是空返回true,否则返回false
    	 */
    	public boolean isEmpty() {
    		return 0 == size;
    	}
    	
    	/**
    	 * 判断指定元素是否在MyList底层数组中存在
    	 * 
    	 * @param obj 用户指定的元素
    	 * @return 存在返回true,不存在返回false
    	 */
    	public boolean contains(Object obj) {
    		return indexOf(obj) > -1;
    	}
    	
    	/**
    	 * 根据指定下标位置,获取对应的元素
    	 * 
    	 * @param index 指定下标位置
    	 * @return 对应的元素,如果不存在,返回null
    	 */
    	public E get(int index) {
    		return index > -1 && index < size ? (E) elementData[index] : null;
    	}
    	/**
    	 * 类内私有化方法,用于在添加元素过程中,出现当前底层数组容量不足的情况下 对底层数组进行扩容操作,满足使用要求
    	 * 
    	 * @param minCapacity 添加操作要求的最小容量
    	 * @throws OverflowMaxArraySizeException 数组容量超出最大范围
    	 */
    	private void grow(int minCapacity) throws OverflowMaxArraySizeException {
    		// 1. 获取原数组容量
    		int oldCapacity = elementData.length;
    
    		// 2. 计算得到新数组容量,新数组容量大约是原数组容量的1.5倍
    		// >> 1 右移一位 该操作是二进制操作 等价于 / 2 效率略高
    		int newCapacity = oldCapacity + (oldCapacity >> 1);
    
    		// 3. 判断新数组容量是否满足最小容量要求
    		if (minCapacity > newCapacity) {
    			newCapacity = minCapacity;
    		}
    
    		// 4. 判断当前容量是否超出了MAX_ARRAY_SIZE
    		if (newCapacity > MAX_ARRAY_SIZE) {
    			throw new OverflowMaxArraySizeException("Overflow MAX_ARRAY_SIZE");
    		}
    
    		// 5. 创建新数组
    		Object[] temp = new Object[newCapacity];
    
    		// 6. 数据拷贝
    		for (int i = 0; i < oldCapacity; i++) {
    			temp[i] = elementData[i];
    		}
    
    		// 7. 使用allStus保存新数组首地址
    		elementData = temp;
    	}
    }
    

    2. List接口

    2.1 List接口概述
    List接口特征:
    	1. 数据存储可重复。
    	2. 有序,添加顺序和保存顺序一致。
    	
    --| ArrayList<E> 
    	可变长数组
    --| LinkedList<E>
    	双向链表
    --| Vector<E>
    	线程安全的可变长数组
    
    2.2 List常用方法
    增
    	boolean add(E e);	
    		List接口继承Collection接口 add方法,使用操作和Collection一致,并且这
    		里采用的添加方式是【尾插法】
    		
    	boolean add(int index, E e);
    		List接口【特有方法】,在指定位置,添加指定元素。
    		
    	boolean addAll(Collection<? extends E> c);
    		List接口继承Collection接口 addAll方法,使用操作和Collection一致,并
    		且这里采用的添加方式是【尾插法】
    		
    	boolean addAll(int index, Collection<? extends E> c);
    		List接口【特有方法】,在指定下标位置,添加另一个集合中所有内容
    删
    	E remove(int index);
    		List接口【特有方法】,获取指定下标位置的元素。
    	
    	boolean remove(Object obj);
    		List接口继承Collection接口方法。删除集合中的指定元素
    		
    	boolean removeAll(Collection<?> c);
    		List接口继承Collection接口方法。删除当前集合中和参数集合重复元素
    		
    	boolean retainAll(Collection<?> c);
    		List接口继承Collection接口方法。保留当前集合中和参数集合重复元素
    		
    	clear();
    		List接口继承Collection接口方法。清空整个集合中的所有元素
    
    改
    	E set(int index, E e);
    		List接口【特有方法】,使用指定元素替代指定下标的元素,返回值是被替换的元
    		素
    查	
    	int size();
    		List接口继承Collection接口方法。获取集合中有效元素个数
    	
    	boolean isEmpty();
    		List接口继承Collection接口方法。判断当前集合是否为空
    	
    	boolean contains(Object obj);
    		List接口继承Collection接口方法。判断指定元素是否包含在当前集合中
    	
    	boolean containsAll(Collection<?> c);
    		List接口继承Collection接口方法。判断参数集合是不是当前集合在子集合
    	
    	Object[] toArray();
    		List接口继承Collection接口方法。获取当前集合中所有元素Object数组
    	
    	E get(int index);
    		List接口【特有方法】。获取指定下标对应的元素
    	
    	List<E> subList(int fromIndex, int toIndex);
    		List接口【特有方法】。获取当前集合指定子集合,从fromIndex开始,到
    		toIndex结束。fromIndex <= 范围 < toIndex
    	
    	int indexOf(Object obj);
    		List接口【特有方法】。获取指定元素在集合中第一次出现位置
    	
    	int lastIndexOf(Object obj);
    		List接口【特有方法】。获取指定元素在集合中最后一次出现的位置
    
    2.3 List接口常用方法演示
    package com.qfedu.a_list;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Demo1 {
    	public static void main(String[] args) {
    		/*
    		 * List<E>是一个接口,没有自己的类对象,这里使用List接口的
    		 * 实现类ArrayList来演示代码。
    		 */
    		List<String> list = new ArrayList<String>();
    		
    		/*
    		 * 添加方法演示
    		 */
    		list.add("浓郁咖啡摩卡");
    		list.add("浓郁咖啡拿铁");
    		list.add("焦糖玛奇朵");
    		list.add("摩卡可可碎星冰乐");
    		list.add("可可卡布奇诺");
    		
    		System.out.println(list);
    		
    		list.add(3, "美式咖啡");
    		
    		System.out.println(list);
    		
    		List<String> list2 = new ArrayList<String>();
    		
    		list2.add("肥宅快乐水");
    		list2.add("芬达");
    		list2.add("雪碧");
    		list2.add("冰峰");
    		
    		list.addAll(4, list2);
    		
    		System.out.println(list);
    		
    		/*
    		 * 删除方法
    		 */
    		String remove = list.remove(1);
    		System.out.println(remove);
    		System.out.println(list);
    		
    		// 条件过滤,这里使用了JDK1.8 新特征 Lambda表达式和函数式接口 【后期知识点】
    		list.removeIf((str) -> str.length() > 4);
    		System.out.println(list);
    	}
    }
    
    package com.qfedu.a_list;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Demo1 {
    	public static void main(String[] args) {
    		/*
    		 * List<E>是一个接口,没有自己的类对象,这里使用List接口的
    		 * 实现类ArrayList来演示代码。
    		 */
    		List<String> list = new ArrayList<String>();
    		
    		/*
    		 * 添加方法演示
    		 */
    		list.add("浓郁咖啡摩卡");
    		list.add("浓郁咖啡拿铁");
    		list.add("焦糖玛奇朵");
    		list.add("摩卡可可碎星冰乐");
    		list.add("可可卡布奇诺");
    		
    		System.out.println(list);
    		
    		list.add(3, "美式咖啡");
    		
    		System.out.println(list);
    		
    		List<String> list2 = new ArrayList<String>();
    		
    		list2.add("肥宅快乐水");
    		list2.add("芬达");
    		list2.add("雪碧");
    		list2.add("冰峰");
    		
    		list.addAll(4, list2);
    		
    		System.out.println(list);
    		
    		/*
    		 * 删除方法
    		 */
    		String remove = list.remove(1);
    		System.out.println(remove);
    		System.out.println(list);
    		
    		// 条件过滤,这里使用了JDK1.8 新特征 Lambda表达式和函数式接口 【后期知识点】
    		list.removeIf((str) -> str.length() > 4);
    		System.out.println(list);
    	}
    }
    
    
    阿里巴巴笔试题
    1.已知有20个String对象,请将他们插入ArrayList
    2.int[1,2,3,4,5] 转换成Integer[]
    

    3. ArrayList【重点】

    3.1 ArrayList概述
    	ArrayList是在Java中集合非常重要的一个组装,基于数组完成的数据结构。可变长数组操作!!!
    	底层保存数据的是一个Object类型数组。
    	ArrayList使用的方法都是List接口中的方法,有两个需要了解的成员方法:
    		ensureCapacity();
    			判断方法,用于确定当前底层数组的容量是否满足当前操作的需求。
    		trimToSize();
    			节省空间,将底层数组的容量缩容至有效元素个数
    	
    	需要掌握的是关于ArrayList效率相关的问题。和细节问题
    
    3.2 细节问题
    1. DEFAULT_CAPACITY
    	默认容量 private static final int DEFAULT_CAPACITY = 10;
    	在调用ArrayList无参数构造方法是,才会使用DEFAULT_CAPACITY,作为底层Object数组的初始化容量。如果用户指定调用的是带有初始化底层Object数组容量的构造方法,会根据用户指定的容量创建对一个ArrayList集合。】
    	
    2. MAX_ARRAY_SIZE ==> Integer.MAX_VALUE - 8;
    	int[] arr = new int[10];
    	
    	arr.length 是什么??? 数组容量
    	这里是一个方法还是属性??? 属性
    	属性是不是成员变量??? 是
    	成员变量是否需要占用内存??? 需要
    	
    	new数组占用的空间什么地方??? 堆区
    	arr.length 属性是不是也在堆区??? 是
    	
    	为什么 - 8???
    		因为在数组中存在很多属性,length只是众多属性中的一个,在创建数组使用的过
    		程中,需要留有内存空间用于保存数组中属性。
    	
    	我买的房子
    		109.32 
    		公摊 之后 87.22
    		套内面积是实际使用面积 69
    
    3.3 效率问题
    ArrayList特征:
    	增删慢
    		增加慢
    			1. 数组当前容量无法满足添加操作,需要进行grow扩容方法执行,在扩容方
    			法中,存在数组创建,数组数据拷贝。非常浪费时间,而且浪费内存。
    			2. 数组在添加数据的过程中,存在在指定位置添加元素,从指定位置开始,
    			之后的元素整体向后移动。
    			
    		删除慢
    			1. 删除数据之后,从删除位置开始,之后的元素整体向前移动,移动过程非
    			常浪费时间
    			2. 删除操作会导致数据空间的浪费,内存的浪费
    		
    	查询快
    		ArrayList底层是一个数组结构,在查询操作的过程中,是按照数组+下标的方式
    		来操作对应的元素,数组+下标方式可以直接获取对应的空间首地址,CPU访问效率
    		极高。
    
    3.4 【补充知识点,内存地址】
    内存地址概念:
    	[计算机原理]
    	计算机中为了更好的使用内存,操作程序,完成代码。将内存按照最小单位,进行编号处理。
    	最小单位: 字节 byte
    	从编号为0内存开始,到内存的最大值。地址的展示方式是十六进制。
    
    生活案例。
    	郑州银屏路115号 
    	航海中路60号 这些编号有木有唯一性??? 
    		这些编号具有唯一性,精确定位,精确指向!!!
    	
    	在软件开发中就是采用类似于生活中小区,工厂编号模式,在一条路中对每一个单位进行编号处理。
    	
    	以32G内存为例
    		0x0 ~ 0x7 FFFF FFFF
    
    3.5 【补充知识点 内存地址对于CPU有什么关系】
    生活案例:
    	快递小哥,可以根据地址直接高效送快递到你家。根据地址来处理快递。
    	航海中路60号,这是唯一地址!!!
    	
    	快递小哥我们可以看做是CPU,快递上地址,就是内存地址,具有唯一性!!!
    
    代码实际运行:
    	CPU就是根据内存地址,可以直达内存所在区域,执行对应代码。精准而优雅,速度非常快!!!
    
    3.6 【补充知识点 数组空间地址关系】

    3.7【补充知识点 null到底是什么】
    null 是计算机中非常特殊的一块内存。该内存编号 0x0000 0000 
    
    该内存受到系统保护
    	不只是电脑,包括手机,iPad,智能设备,只要存在计算机基本结构的设备上都存在null 编号为0x0内存。大小一个字节
    	该内存不能读取任何数据,也不能写入任何数据。一旦操作,程序直接被系统杀死
    	Kill -9
    	
    	一般用于引用数据类型的初始化,利用开发中关于null的异常,辅助找出代码中的错误。
    	NullPointerException.
    
  • 相关阅读:
    深入理解vue路由的使用
    mac异常删除管理员账户恢复操作
    springMVC前后端分离开发模式下支持跨域请求
    npm 更新镜像安装Appium
    npm升级所有可更新包
    new AppiumDriver<>(new URL(url), capabilities) 报错 java.lang.NoSuchMethodError: com.google.common.base.Throwables.throwIfUnchecked(Ljava/lang/Throwable;)V
    Jmeter命令行运行实例讲解
    shodan会员命令版
    AS-REPRoasting
    Password Spraying/密码喷洒
  • 原文地址:https://www.cnblogs.com/raising/p/12898113.html
Copyright © 2011-2022 走看看