項目優(yōu)化和List集合
1、項目優(yōu)化
1.1 分析當前情況
問題
????數(shù)據(jù)存儲是數(shù)組形式,數(shù)據(jù)類型明確。復(fù)用度較低枕荞。
需求
????Student操作使用的代碼,StudentManager想要操作考慮一個復(fù)用度問題搞动。不管更換什么數(shù)據(jù)類型躏精, 都是可以直接使用。
解決問題
????1. 泛型
????2. 數(shù)組不能使用泛型鹦肿,但是這個數(shù)組又需要保存各式各樣的數(shù)據(jù)
????????Object
1.2 使用泛型和Object優(yōu)化項目
package com.qfedu.student.system.util;
import com.qfedu.student.system.myexception.IllegalCapacityException;
import com.qfedu.student.system.myexception.OverflowMaxArraySizeException;
/**
* 自定義數(shù)據(jù)存儲工具矗烛,MyList用于存儲代碼中操作的數(shù)據(jù)
*
* @author Anonymous
*
* @param <E> 使用泛型滿足更多的情況
*/
public class MyList<E> {
????/**
????* 保存數(shù)據(jù)的底層Object數(shù)組,可以保存任意數(shù)據(jù)類型箩溃,但是在操作方法是會
????* 對操作的數(shù)據(jù)類型瞭吃,通過泛型進行約束操作
????*/
????private Object[] elementData = null;
????/**
????* DEFAULT_CAPACITY 默認容量碌嘀,這里是一個帶有名字的常量
????*/
????private static final int DEFAULT_CAPACITY = 10;
????/**
????* 數(shù)組最大容量,是int類型最大值 - 8?
????*/
????private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
????/**
????* 當前底層Object數(shù)組中有效元素個數(shù)
????*/
????private int size = 0;
????/**
????* 無參數(shù)構(gòu)造方法歪架,使用DEFAULT_CAPACITY約束初始化容量
????*/
????public MyList() {
????????elementData = new Object[DEFAULT_CAPACITY];
????}
????/**
????* 提供給用戶可以指定初始化容量的操作方法
????*
????* @param initCapacity 用戶指定的初始化容量股冗,但是必須在合理范圍以內(nèi)
????* @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];
????}
????/**
????* 添加方法,添加在創(chuàng)建MyList對象是約束的具體數(shù)據(jù)類型
????*
????* @param e 通過泛型約束的具體數(shù)據(jù)類型
????* @return 添加成功返回true, 否則返回false
????* @throws OverflowMaxArraySizeException
????*/
????public boolean add(E e) throws OverflowMaxArraySizeException {
????????if (size == elementData.length) {
????????????// 添加操作是一個元素和蚪,最小容量要求就是在原本的數(shù)組容量之上 + 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;
????????// 有效元素個數(shù) - 1
????????size -= 1;
????????return true;
????}
????/**
????* 根據(jù)指定元素攒霹,找出對應(yīng)的下標位置怯疤,沒有找到返回-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 指定的下標位置,約束在合理范圍以內(nèi)
* @param e 泛型約束的指定數(shù)據(jù)類型辅髓,保證數(shù)據(jù)類型一致化
* @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底層數(shù)組中保存有效元素個數(shù)是多少個
????*
????* @return 返回當前MyList底層數(shù)組中有效元素個數(shù)
????*/
????public int size() {
????????return size;
????}
????/**
????* 判斷當前MyList中是否為空
????*
????* @return 如果是空返回true洛口,否則返回false
????*/
????public boolean isEmpty() {
????????return 0 == size;
????}
????/**
????* 判斷指定元素是否在MyList底層數(shù)組中存在
????*
????* @param obj 用戶指定的元素
????* @return 存在返回true矫付,不存在返回false
????*/
????public boolean contains(Object obj) {
????????return indexOf(obj) > -1;
????}
????/**
????* 根據(jù)指定下標位置,獲取對應(yīng)的元素
????*
????* @param index 指定下標位置
????* @return 對應(yīng)的元素第焰,如果不存在买优,返回null
????*/
????public E get(int index) {
????????return index > -1 && index < size ? (E) elementData[index] : null;
????}
????/**
????* 類內(nèi)私有化方法,用于在添加元素過程中挺举,出現(xiàn)當前底層數(shù)組容量不足的情況下 對底層數(shù)組進行擴容操作杀赢,滿足使用要求
????*
????* @param minCapacity 添加操作要求的最小容量
????* @throws OverflowMaxArraySizeException 數(shù)組容量超出最大范圍
????*/
????private void grow(int minCapacity) throws OverflowMaxArraySizeException {
????????// 1. 獲取原數(shù)組容量
????????int oldCapacity = elementData.length;
????????// 2. 計算得到新數(shù)組容量,新數(shù)組容量大約是原數(shù)組容量的1.5倍
????????// >> 1 右移一位 該操作是二進制操作 等價于 / 2 效率略高
????????int newCapacity = oldCapacity + (oldCapacity >> 1);
???????// 3. 判斷新數(shù)組容量是否滿足最小容量要求
???????if (minCapacity > newCapacity) {
???????????newCapacity = minCapacity;
????????}
????????// 4. 判斷當前容量是否超出了MAX_ARRAY_SIZE
???????if (newCapacity > MAX_ARRAY_SIZE) {
????????????throw new OverflowMaxArraySizeException("Overflow MAX_ARRAY_SIZE");
????????}
????????// 5. 創(chuàng)建新數(shù)組
????????Object[] temp = new Object[newCapacity];
????????// 6. 數(shù)據(jù)拷貝
????????for (int i = 0; i < oldCapacity; i++) {
????????????temp[i] = elementData[i];
????????}
????????// 7. 使用allStus保存新數(shù)組首地址
????????elementData = temp;
????}
}
2湘纵、List接口
2.1 List接口概述
List接口特征:
????1. 數(shù)據(jù)存儲可重復(fù)脂崔。
????2. 有序,添加順序和保存順序一致梧喷。
--| ArrayList<E>
????可變長數(shù)組
--| LinkedList<E>
????雙向鏈表
--| Vector<E>
????線程安全的可變長數(shù)組
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接口【特有方法】,在指定下標位置弯囊,添加另一個集合中所有內(nèi)容
刪
????E remove(int index);
????????List接口【特有方法】取视,獲取指定下標位置的元素硝皂。
????boolean remove(Object obj);
????????List接口繼承Collection接口方法。刪除集合中的指定元素
????boolean removeAll(Collection<?> c);
????????List接口繼承Collection接口方法作谭。刪除當前集合中和參數(shù)集合重復(fù)元素
????boolean retainAll(Collection<?> c);
????????List接口繼承Collection接口方法稽物。保留當前集合中和參數(shù)集合重復(fù)元素
????clear();
????????List接口繼承Collection接口方法。清空整個集合中的所有元素
改
????E set(int index, E e);
????????List接口【特有方法】折欠,使用指定元素替代指定下標的元素贝或,返回值是被替換的元素
查
????int size();
????????List接口繼承Collection接口方法。獲取集合中有效元素個數(shù)
????boolean isEmpty();
????????List接口繼承Collection接口方法锐秦。判斷當前集合是否為空
????boolean contains(Object obj);
????????List接口繼承Collection接口方法咪奖。判斷指定元素是否包含在當前集合中
????boolean containsAll(Collection<?> c);
????????List接口繼承Collection接口方法。判斷參數(shù)集合是不是當前集合在子集合
????Object[] toArray();
????????List接口繼承Collection接口方法酱床。獲取當前集合中所有元素Object數(shù)組
????E get(int index);
????????List接口【特有方法】羊赵。獲取指定下標對應(yīng)的元素
????List<E> subList(int fromIndex, int toIndex);
????????List接口【特有方法】。獲取當前集合指定子集合扇谣,從fromIndex開始昧捷,到toIndex結(jié)束。fromIndex <= 范圍 < toIndex
????int indexOf(Object obj);
????????List接口【特有方法】罐寨。獲取指定元素在集合中第一次出現(xiàn)位置
????int lastIndexOf(Object obj);
????????List接口【特有方法】靡挥。獲取指定元素在集合中最后一次出現(xiàn)的位置
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接口的
????????* 實現(xiàn)類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表達式和函數(shù)式接口 【后期知識點】
????????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接口的
????????* 實現(xiàn)類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表達式和函數(shù)式接口 【后期知識點】
????????list.removeIf((str) -> str.length() > 4);
????????System.out.println(list);
????}
}
3. ArrayList【重點】
3.1 ArrayList概述
ArrayList是在Java中集合非常重要的一個組裝饿悬,基于數(shù)組完成的數(shù)據(jù)結(jié)構(gòu)【鬯可變長數(shù)組操作=铺瘛!蝎宇!
底層保存數(shù)據(jù)的是一個Object類型數(shù)組弟劲。
ArrayList使用的方法都是List接口中的方法,有兩個需要了解的成員方法:
????ensureCapacity();
????????判斷方法姥芥,用于確定當前底層數(shù)組的容量是否滿足當前操作的需求兔乞。
????trimToSize();
????????節(jié)省空間,將底層數(shù)組的容量縮容至有效元素個數(shù)
需要掌握的是關(guān)于ArrayList效率相關(guān)的問題。和細節(jié)問題
3.2 細節(jié)問題
1. DEFAULT_CAPACITY
????默認容量 private static final int DEFAULT_CAPACITY = 10;
????在調(diào)用ArrayList無參數(shù)構(gòu)造方法是庸追,才會使用DEFAULT_CAPACITY霍骄,作為底層Object數(shù)組的初始化容量。如果用戶指定調(diào)用的是帶有初始化底層Object數(shù)組容量的構(gòu)造方法淡溯,會根據(jù)用戶指定的容量創(chuàng)建對一個ArrayList集合读整。】
2. MAX_ARRAY_SIZE ==> Integer.MAX_VALUE - 8;
????int[] arr = new int[10];
????arr.length 是什么??? 數(shù)組容量
????這里是一個方法還是屬性??? 屬性
????屬性是不是成員變量??? 是
????成員變量是否需要占用內(nèi)存??? 需要
????new數(shù)組占用的空間什么地方??? 堆區(qū)
????arr.length 屬性是不是也在堆區(qū)??? 是
????為什么 - 8???
????因為在數(shù)組中存在很多屬性咱娶,length只是眾多屬性中的一個米间,在創(chuàng)建數(shù)組使用的過程中,需要留有內(nèi)存空間用于保存數(shù)組中屬性膘侮。
3.3 效率問題
ArrayList特征:
????增刪慢
????????增加慢
????????????1. 數(shù)組當前容量無法滿足添加操作屈糊,需要進行g(shù)row擴容方法執(zhí)行,在擴容方法中琼了,存在數(shù)組創(chuàng)建逻锐,數(shù)組數(shù)據(jù)拷貝。非常浪費時間雕薪,而且浪費內(nèi)存昧诱。
????????????2. 數(shù)組在添加數(shù)據(jù)的過程中,存在在指定位置添加元素蹦哼,從指定位置開始鳄哭,之后的元素整體向后移動要糊。
????????刪除慢
????????????1. 刪除數(shù)據(jù)之后纲熏,從刪除位置開始,之后的元素整體向前移動锄俄,移動過程非常浪費時間
????????????2. 刪除操作會導(dǎo)致數(shù)據(jù)空間的浪費局劲,內(nèi)存的浪費
????查詢快
????????ArrayList底層是一個數(shù)組結(jié)構(gòu),在查詢操作的過程中奶赠,是按照數(shù)組+下標的方式來操作對應(yīng)的元素鱼填,數(shù)組+下標方式可以直接獲取對應(yīng)的空間首地址,CPU訪問效率極高毅戈。
3.4 【補充知識點苹丸,內(nèi)存地址】
內(nèi)存地址概念:
????[計算機原理]
????計算機中為了更好的使用內(nèi)存,操作程序苇经,完成代碼赘理。將內(nèi)存按照最小單位,進行編號處理扇单。
????最小單位: 字節(jié) byte
????從編號為0內(nèi)存開始商模,到內(nèi)存的最大值。地址的展示方式是十六進制。
3.5 【補充知識點 內(nèi)存地址對于CPU有什么關(guān)系】
代碼實際運行:
????CPU就是根據(jù)內(nèi)存地址施流,可以直達內(nèi)存所在區(qū)域响疚,執(zhí)行對應(yīng)代碼。精準而優(yōu)雅瞪醋,速度非撤拊危快!L苏隆杏糙!
3.6 【補充知識點 數(shù)組空間地址關(guān)系】
3.7【補充知識點 null到底是什么】
null 是計算機中非常特殊的一塊內(nèi)存。該內(nèi)存編號 0x0000 0000
該內(nèi)存受到系統(tǒng)保護
????不只是電腦蚓土,包括手機宏侍,iPad,智能設(shè)備蜀漆,只要存在計算機基本結(jié)構(gòu)的設(shè)備上都存在null 編號為0x0內(nèi)存谅河。大小一個字節(jié)該內(nèi)存不能讀取任何數(shù)據(jù),也不能寫入任何數(shù)據(jù)确丢。一旦操作绷耍,程序直接被系統(tǒng)殺死
????Kill -9
????一般用于引用數(shù)據(jù)類型的初始化,利用開發(fā)中關(guān)于null的異常鲜侥,輔助找出代碼中的錯誤褂始。
????NullPointerException.