Java学习进程7
·
动态数组及泛型
动态数组
固定数组存在长度一旦初始化就无法修改的缺陷,新增、插入元素会受容量限制,因此需要手动封装动态数组,基于原生定长数组实现自动扩容、增删改查功能。
动态数组的方法
- 末尾添加数据:数组长度 + 1,原数组全部元素复制,末尾存放新数据
- 指定位置插入:插入位置前元素不变,插入位置存放新元素,后面元素统一后移一位
- 删除指定位置数据:删除位置之后的元素统一向前覆盖一位,数组长度 - 1
- 删除指定数据(使用布尔类型):遍历找到第一个匹配下标,调用按下标删除方法
- 删除所有相同数据:循环执行单次数据删除,直到不存在目标元素
example
自定义动态数组 ArrList 完整实现代码
package com.yw.oop0627;
/**
* @author YAN
* @date 2026/6/27 17:36
* @description 动态数组
*/
public class ArrList {
//初始数组
private int [] arr = new int[0];
//末尾添加数据
public void add(int data){
//扩容原数组
int [] nArr = new int [arr.length+1];
nArr[arr.length] = data;
//拷贝原数组数据到新数组
for(int i = 0; i < arr.length; i++){
nArr[i] = arr[i];
}
//更新对象头
arr = nArr;
}
//插入数据
public void insert(int index, int data){
int [] newArr = new int [arr.length+1];
//复制插入位置之前的数据
for(int i = 0; i < index; i++){
newArr[i] = arr[i];
}
//插入目标数据
newArr[index] = data;
//复制插入位置之后的数据
for(int i = index; i < arr.length; i++){
newArr[i + 1] = arr[i];
}
arr = newArr;
}
//删除指定位置数据,返回被删除的数据
public int remove(int index){
//保存要删除的元素
int delNum = arr[index];
int[] newArr = new int[arr.length - 1];
//复制删除位置前数据
for (int i = 0; i < index; i++) {
newArr[i] = arr[i];
}
//删除位置后数据向前移动
for (int i = index; i < newArr.length; i++) {
newArr[i] = arr[i + 1];
}
arr = newArr;
return delNum;
}
//删除指定数据(使用布尔类型)
public boolean removes(int data){
for (int i = 0; i < arr.length; i++) {
if(arr[i] == data){
remove(i);
return true;
}
}
return false;
}
//删除所有相同数据
public boolean removeAll(int data){
boolean flag = false;
//循环删除,直到没有目标数据
while(removes(data)){
flag = true;
}
return false;
}
//获取数据
public int get(int index){
//判断index是否合法
return arr[index];
}
//长度
public int size(){
return arr.length;
}
public static void main(String[] args){
//测试
ArrList list = new ArrList();
list.add(1);
list.add(2);
list.add(3);
for(int i = 0; i < list.size(); i++){
System.out.print(list.get(i) + " ");
}
System.out.println("\n插入元素5到下标1位置:");
list.insert(1,5);
for(int i=0;i<list.size();i++){
System.out.print(list.get(i)+" ");
}
System.out.println("\n删除下标2位置元素:"+list.remove(2));
for(int i=0;i<list.size();i++){
System.out.print(list.get(i)+" ");
}
}
}
动态数组的局限性
由于底层依然使用固定长度的 int 数组存储数据,因此只能添加整形数据,怎么怎么优化动态数组,让其能添加任何类型?
可使用object的数组
局限性:不同类型数据都混在一起
解决:使用泛型
规避耗时问题:减少拷贝次数,对原数组进行2倍扩容
example
package com.yw.oop0702;
/**
* @author YAN
* @date 2026/7/2 18:50
* @description
*/
public class ArrList<E> {
//初始数组
private Object[] arr;
private static int len = 10; //动态数组的默认初始长度
private int size = 0; //记录有效数据个数
//构造方法初始化数组长度
public ArrList(int len){
arr = new Object[len];
}
//设置长度
public ArrList(){
//构造方法相互调用:this(参数,,);
this(len);
}
//末尾添加数据
public void add(E e){
//判断是否需要扩容
if(size == arr.length){
//对原数组2倍扩容
Object[] nArr = new Object[arr.length*2];
//拷贝愿数组数据到新数组
for(int i=0;i<arr.length;i++){
nArr[i] = arr[i];
}
//更新对象头
arr = nArr;
}
arr[size] = e;
size++;
}
//插入数据
public void insert(int index,E e){
//优先扩容
if (size == arr.length) {
Object[] nArr = new Object[arr.length*2];
//拷贝愿数组数据到新数组
for(int i=0;i<arr.length;i++){
nArr[i] = arr[i];
}
//更新对象头
arr = nArr;
}
//后移元素
for (int i = size; i > index; i--) {
arr[i] = arr[i - 1];
}
arr[index] = e;
size++;
}
//删除指定位置数据,返回被删除的数据
public E remove(int index){
//把要删除位置的元素提前存起来
E deleteElement = (E) arr[index]; //使用当前的泛型符号
//元素前移覆盖
for (int i = index; i < size - 1; i++) {
arr[i] = arr[i + 1];
}
//最后的位置为空
arr[size - 1] = null;
//有效元素个数-1
size--;
//返回最开始保存的、被删除的元素
return deleteElement;
}
//删除指定数据
public boolean removes(E e){
for (int i = 0;i < size; i++) {
if (arr[i].equals(e)) {
remove(i);
return true;
}
}
return false;
}
//删除所有相同
public boolean removeAll(E e){
for (int i = size - 1; i >= 0; i--) {
if (arr[i].equals(e)) {
remove(i);
return true;
}
}
return false;
}
//获取数据
public E get(int index){
//判断index是否合法
return (E)arr[index];
}
//长度
public int size(){
return size;
}
public static void main(String[] args) {
//测试
ArrList<Integer> list = new ArrList<>();
long start = System.currentTimeMillis();
for(int i=0;i<100000;i++){
list.add(i);
}
long end = System.currentTimeMillis();
System.out.println("耗时:"+(end-start));
//测试插入
list.insert(0, 999);
//测试删除
list.remove(0);
//测试删除指定元素
list.removes(50000);
System.out.println("当前有效元素个数:" + list.size());
}
}
关于基本类型的对应包装类
基本数据类型 -> 包装类(java.lang 包下)
byte -> Byte
short -> Short
int -> Integer
long -> Long
float -> Float
double -> Double
char -> Character
boolean -> Boolean
关于Java内置动态数组ArrayList扩容机制
- 底层原理
ArrayList 底层基于 Object [] 数组实现,属于动态数组。
// 默认初始容量:10
private static final int DEFAULT_CAPACITY = 10;
// 空数组常量(懒加载:无参构造初始化时不创建长度为10的数组,先赋值空数组,第一次add才初始化容量10)
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 底层存储数组
transient Object[] elementData;
// 集合中实际存储的有效元素个数
private int size;
- 三种构造方法
- 无参构造
public ArrayList() {
// 初始化空数组,懒加载,首次添加元素才扩容到10
elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
- 指定初始容量构造
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
}
}
- 集合参数构造:把其他集合转为 ArrayList
泛型<>
作用:把添加的数据形参化,限制相同类型的数据才能被添加到同一个集合对象
注:确定泛型的数据类型时必须是引用类型
常用泛型符号:
E T K V…(任意大写字母即可,E更为常用)
更多推荐


所有评论(0)