🔥博客主页: 小扳_-CSDN博客
❤感谢大家点赞👍收藏⭐评论✍
本篇目录
1.0 动态数组说明
2.0 模拟实现动态数组的核心方法
2.1 动态数组-插入与扩容
2.2 动态数组-获取元素
2.3 动态数组-修改元素
2.4 动态数组-删除元素
2.5 动态数组-遍历元素(重点)
2.5.1 使用 forEach 循环元素
2.5.2 使用迭代器循环元素
2.5.3 使用 Stream 流来循环元素
2.6 补充关于拷贝的方法
3.0 对以上代码进行汇总整理升级
1.0 动态数组说明
在 Java 中,动态数组可以使用 ArrayList 类来实现。ArrayList 类是 Java 集合框架中的一个类,它可以动态地增加或减少元素的大小。与普通数组相比,ArrayList 具有动态增长和缩小的能力,可以根据需要自动调整数组的大小。
2.0 模拟实现动态数组的核心方法
该动态数组中的成员变量分别为:Object[] myArrayList 数组、int size 元素个数、int defaultSize 默认大小。在 ArrayList 类中,在未添加元素之前为空,因此,Object[] myArrayList = {};size 默认为0;当第一个元素添加进来的时候,defaultSize 默认为10。
具体代码如下:
public class ImitateArray<E> implements Iterable<E>{ private int defaultSize = 10; private Object[] myArraylist= {}; private int size = 0; //无参构造器 public ImitateArray() { }
2.1 动态数组-插入与扩容
add(element)
: 向动态数组的末尾添加一个元素。如果数组已满,则需要扩容。
具体代码如下:
public boolean add(E e){ if (size == 0){ myArraylist = new Object[defaultSize]; } //先判断是否需要扩容 if (isExpansion()) { expansion(); } myArraylist[size] = e; size++; return true; } //是否需要扩容 private boolean isExpansion(){ return size >= defaultSize; } //数组扩容 private boolean expansion(){ defaultSize = (int) (defaultSize * 1.5); Object[] temp = new Object[(int) (defaultSize)]; //for (int i = 0; i < myArraylist.length; i++) { // temp[i] = myArraylist[i]; //} System.arraycopy(myArraylist,0,temp,0,size); myArraylist = temp; System.out.println("扩容成功!"); return true; }
对以上代码进行分析:
在添加元素前,
第一,先判断是否首元素插入,如果是首元素,需要创建数组对象,默认大小为10。
第二,判断 size == defaultSize,如果是,就需要扩容了,数组扩容大小为原来的1.5倍,defaultSize += defaultSize >>> 1,扩容成功之后,需要将原数组中的元素拷贝回到新数组中,可以用的方法为 System.arraycopy(myArraylist,0,temp,0,size);
第三,添加完元素之后,需要进行 size++ 。
2.2 动态数组-获取元素
get(index)
: 获取指定索引处的元素。
具体代码如下:
public E get(int index){ if (index >= size || index < 0){ throw new RuntimeException("越界!!!"); } return (E)myArraylist[index]; }
对以上代码进行分析:
获取元素之前,先要判断是否越界访问数组。
2.3 动态数组-修改元素
set(index, element)
: 修改指定索引处的元素。
具体代码如下:
public E set(int index,E e){ if (index >= size || index < 0){ throw new RuntimeException("越界!!!"); } E temp = (E) myArraylist[index]; myArraylist[index] = e; return temp; }
同理,在修改元素之前先要判断是否为越界访问。
2.4 动态数组-删除元素
remove(index)
: 删除指定索引处的元素。如果删除后数组的空余空间过多,则需要缩容。
具体代码如下:
//根据索引删除数据 public boolean remove(int index){ if (index >= size || index < 0){ throw new RuntimeException("越界!!!"); } if (index == size - 1){ myArraylist[index] = null; }else { //1,2,3,4,5 //0,1,2,3,4 for (int i = index; i < size; i++) { myArraylist[i] = myArraylist[i + 1]; } } size--; return true; }
对以上代码进行分析:
先判断是否越界访问,再判断若要删除的元素为最后一个,则直接 null,接着 size--。其他情况需要缩容,myArraylist[i] = myArraylist[i + 1];
2.5 动态数组-遍历元素(重点)
介绍三种方式来遍历元素:
第一种,实现使用 forEach 循环元素
第二种,实现使用迭代器循环元素
第三种,实现使用 Stream 流来循环元素
2.5.1 使用 forEach 循环元素
具体代码如下:
public interface Consumer <E>{ void accept(E e); }
//实现forEach public void forEach(Consumer<E> consumer) { Object[] temp = new Object[size]; for (int i = 0; i < size; i++) { temp[i] = myArraylist[i]; } for (Object o : temp) { consumer.accept((E)o); } }
imitateArray.forEach(new Consumer<Integer>() { @Override public void accept(Integer integer) { System.out.print(integer+" "); } });
对以上代码进行分析:
先实现一个接口,然后用 fori 循环,将有效元素都拷贝到新的数组中,接着用 foreach 循环来对每个元素进行操作,具体由用户决定了。
2.5.2 使用迭代器循环元素
具体代码如下:
首先需要实现 Iterable 接口;
//重写迭代器 @Override public Iterator<E> iterator() { return new Iterator<E>() { int i = 0; @Override public boolean hasNext() { return i < size; } @Override public E next() { return (E) myArraylist[i++]; } }; }
for (Integer integer : imitateArray) { System.out.print(integer+" "); }
补充;大部分的集合都实现该迭代器,因此不是所有类都具有迭代器的。
2.5.3 使用 Stream 流来循环元素
具体代码如下:
//用流进行遍历 public Stream stream(){ //第一种比较晦涩难懂 //return Arrays.stream(Arrays.copyOf(myArraylist,size)).map(e->(E) e); //第二种比较好理解一点 Stream<Object> stream1 = Stream.of(Arrays.copyOf(myArraylist,size)); return stream1.map(e->(E) e); }
imitateArray.stream().forEach(s-> System.out.print(s+" "));
重点注意:在 stream 方法中,使用 Stream.of((E) myArraylist) 来创建一个流,但是这样会将整个数组对象作为一个元素添加到流中,而不是将数组中的元素逐个添加到流中。
因此,使用 map 方法来对流中的每个元素进行操作。在这里使用 lambda 表达式 (e -> (E) e) 来将每个元素 (e) 强制转换为 E 类型。这样就可以将流中的元素类型转换为 E 类型。
2.6 补充关于拷贝的方法
第一个,System.arraycopy(myArraylist,0,temp,0,size),用于一个或者两个数组,从 myArraylist 数组从第 0 个索引拷贝到 temp 数组中从第 0 个索引开始,一共要拷贝 size 个元素。
第二个,Arrays.copyof(int[] original, int newlength),用于从原来的数组拷贝到新数组的个数为 newlength 个。
第三个,Arrays.copyOfRange(int[] original, int from, int to) ,将指定数组的指定范围复制到新数组中。
3.0 对以上代码进行汇总整理升级
public interface Consumer <E>{ void accept(E e); }
模拟实现 ArrayList 的代码:
import java.util.Arrays; import java.util.Iterator; import java.util.stream.Stream; public class ImitateArray<E> implements Iterable<E>{ private int defaultSize = 10; private Object[] myArraylist= {}; private int size = 0; public ImitateArray() { } //添加元素 public boolean add(E e){ if (size == 0){ myArraylist = new Object[defaultSize]; } //先判断是否需要扩容 if (isExpansion()) { expansion(); } myArraylist[size] = e; size++; return true; } //根据索引来查询数据 public E get(int index){ if (index >= size || index < 0){ throw new RuntimeException("越界!!!"); } return (E)myArraylist[index]; } //根据索引删除数据 public boolean remove(int index){ if (index >= size || index < 0){ throw new RuntimeException("越界!!!"); } if (index == size - 1){ myArraylist[index] = null; }else { //1,2,3,4,5 //0,1,2,3,4 /* for (int i = index; i < size; i++) { myArraylist[i] = myArraylist[i + 1]; }*/ System.arraycopy(myArraylist,index + 1,myArraylist,index,size - index -1); } size--; return true; } //根据索引来更改数据 public E set(int index,E e){ if (index >= size || index < 0){ throw new RuntimeException("越界!!!"); } E temp = (E) myArraylist[index]; myArraylist[index] = e; return temp; } //数组长度 public int size(){ return size; } //实现forEach public void forEach(Consumer<E> consumer) { Object[] temp = new Object[size]; for (int i = 0; i < size; i++) { temp[i] = myArraylist[i]; } for (Object o : temp) { consumer.accept((E)o); } } //根据索引插入元素 public boolean insert(int index,E e){ if (index > size || index < 0){ throw new RuntimeException("越界!!!"); } if (index == size){ //直接调用 add 方法 add(e); } if (isExpansion()){ expansion(); } //Object[] temp = new Object[defaultSize]; /* for (int i = 0; i < index; i++) { temp[i] = myArraylist[i]; } temp[index] = e; for (int i = index; i < size ; i++) { temp[i+1] = myArraylist[i]; }*/ System.arraycopy(myArraylist,index ,myArraylist,index + 1,size - index); myArraylist[index] = e; //myArraylist = temp; size++; return true; } //是否需要扩容 private boolean isExpansion(){ return size >= defaultSize; } //数组扩容 private boolean expansion(){ defaultSize = (int) (defaultSize * 1.5); Object[] temp = new Object[(int) (defaultSize)]; /* for (int i = 0; i < myArraylist.length; i++) { temp[i] = myArraylist[i]; }*/ System.arraycopy(myArraylist,0,temp,0,size); myArraylist = temp; System.out.println("扩容成功!"); return true; } //重写 toString 方法 @Override public String toString() { Object[] temp = new Object[size]; for (int i = 0; i < size; i++) { temp[i] = myArraylist[i]; } return "ImitateArray{" + "myArraylist=" + Arrays.toString(temp) + '}'; } //重写迭代器 @Override public Iterator<E> iterator() { return new Iterator<E>() { int i = 0; @Override public boolean hasNext() { return i < size; } @Override public E next() { return (E) myArraylist[i++]; } }; } //用流进行遍历 public Stream stream(){ //第一种比较晦涩难懂 //return Arrays.stream(Arrays.copyOf(myArraylist,size)).map(e->(E) e); //第二种比较好理解一点 Stream<Object> stream1 = Stream.of(Arrays.copyOf(myArraylist,size)); return stream1.map(e->(E) e); } }
以下为测试类:
public class Text { public static void main(String[] args) { ImitateArray<Integer> imitateArray = new ImitateArray<>(); imitateArray.add(1); imitateArray.add(2); imitateArray.add(3); imitateArray.add(4); imitateArray.add(5); imitateArray.add(6); imitateArray.add(7); imitateArray.add(8); imitateArray.add(9); imitateArray.add(10); imitateArray.add(11); imitateArray.add(12); System.out.println(imitateArray); imitateArray.insert(11,11); imitateArray.insert(11,11); imitateArray.insert(11,11); imitateArray.insert(11,11); imitateArray.insert(11,11); imitateArray.insert(11,11); imitateArray.insert(11,11); imitateArray.insert(11,11); /* ArrayList<Integer> list = new ArrayList<>(); list.forEach(new java.util.function.Consumer<Integer>() { @Override public void accept(Integer integer) { } });*/ imitateArray.forEach(new Consumer<Integer>() { @Override public void accept(Integer integer) { System.out.print(integer+" "); } }); System.out.println(); for (Integer integer : imitateArray) { System.out.print(integer+" "); } System.out.println(); imitateArray.stream().forEach(s-> System.out.print(s+" ")); } }