ArrayList
public class ArrayList<E> {
//数组大小
private int size=0;
//元素数组
private E[] elements;
//常量
private static final int DEFAULT_CAPACITY=10;
private static final int ELEMENT_NOT_FOUND=-1;
public ArrayList(int capacity){
capacity= Math.max(capacity, DEFAULT_CAPACITY);
elements = (E[]) new Object[capacity];
}
public ArrayList(){
this(DEFAULT_CAPACITY);
}
/**
* 返回动态数组大小
* @return
*/
public int size(){
return size;
}
/**
* 是否为空
* @return
*/
public boolean isEmpty(){
return size==0;
}
/**
* 是否包含element元素
* @param element
* @return
*/
public boolean contains(E element){
return indexOf(element)!=ELEMENT_NOT_FOUND;
}
/**
* 返回element元素(可以为空)在动态数组中的索引,不存在则返回-1
* @param element
* @return
*/
public int indexOf(E element){
//对null讨论,防止空指针异常
if(element==null){
for (int i = 0; i < size; i++)
if(elements[i]==null)return i;
}
for(int i=0;i<size;i++)
if(element.equals(elements[i]))return i;//调用element的equals方法
return ELEMENT_NOT_FOUND;
}
/**
* 清空所有元素
*/
public void clear(){
//清空存储的所有对象的地址,等待JVM进行垃圾回收
for (int i = 0; i < size; i++) {
elements[i]=null;
}
size=0;
}
/**
* 将element插入到数组末端
* @param element
*/
public void add(E element){
add(size,element);
}
/**
* 将element插入到索引index位置
* @param index
* @param element
*/
public void add(int index,E element){
//可以传入空值
rangeCheckForAdd(index);
ensureCapacity(size+1);//确保有size+1的存储空间
//使用arraycopy更快
//System.arraycopy(elements,index,elements,index+1,size-index);
for(int i=size-1;i>=index;i--)
elements[i+1]=elements[i];
elements[index]=element;
size++;
}
/**
* 删除索引为index处的元素
* @param index
* @return 被删除的元素
*/
public E remove(int index){
rangeCheck(index);
//保存被删除元素
E old=elements[index];
for(int i=index+1;i<size;i++)
elements[i-1]=elements[i];
//将最后一个对象的地址清空
elements[--size]=null;
return old;
}
/**
* 获取索引为index处的元素
* @param index
* @return
*/
public E get(int index){
rangeCheck(index);
return elements[index];
}
/**
* 将index处的元素修改为element
* @param index
* @param element
* @return 被替换的元素
*/
public E set(int index,E element){
rangeCheck(index);
E old=elements[index];
elements[index]=element;
return old;
}
/**
* 打印格式为size:x [e1, e1, .., en]
* @return
*/
@Override
public String toString() {
//使用StringBuilder进行字符串的拼接更加高效
StringBuilder sb=new StringBuilder();
sb.append("size:").append(size).append(" [");
for(int i=0;i<size;i++){
if(i!=0)
sb.append(", ");
sb.append(elements[i]);
}
sb.append("]");
return sb.toString();
}
/**
* 抛出索引越界异常
* @param index
*/
private void throwException(int index){
throw new IndexOutOfBoundsException("index:"+index+" , size:"+size);
}
/**
* 判断索引的合理性
* @param index
*/
private void rangeCheck(int index){
if(index<0||index>=size)
throwException(index);
}
//为Add方法检查索引合理性
private void rangeCheckForAdd(int index){
if(index<0||index>size)//对于Add方法可以在size处添加元素
throwException(index);
}
//检查容量是否足够
private void ensureCapacity(int capacity){
if(capacity<elements.length)return;
int oldCapacity=elements.length;
int newCapacity=oldCapacity+(oldCapacity>>1);//新建数组,扩容1.5倍
E[] newElements=(E[]) new Object[newCapacity];
for(int i=0;i<size;i++)//复制数据,可用arraycopy
newElements[i]=elements[i];
elements=newElements;//将新数组地址赋给记录原数组的变量elements
System.out.println(oldCapacity+"扩容为"+newCapacity);
}
}
新建Student类,重写equals、hashCode方法
import java.rmi.StubNotFoundException;
public class Student {
private String name;
private int id;
public Student() {
}
public Student(String name, int id) {
setName(name);
setId(id);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
if(id<0)
throw new IllegalArgumentException("id不能小于0");
else
this.id = id;
}
@Override
public boolean equals(Object obj) {
if(this==obj)return true;
if(obj.getClass()!=Student.class||null==obj)return false;
Student stu=(Student) obj;
if(id!=stu.getId())return false;
return name!=null?name.equals(stu.getName()):stu.getName()==null;
}
@Override
public int hashCode() {
int result=name!=null?name.hashCode():0;
result=result*31+id;
return result;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("对象被回收");
}
}
测试类
public class ArrayTest {
public static void main(String[] args) {
ArrayList<Student> list=new ArrayList<>();
list.add(new Student("James1",1));
list.add(new Student("James2",2));
list.add(list.size(),new Student("Jack",3));
list.add(null);
System.out.println(list);
Student James2=new Student("James2",2);
int index=list.indexOf(James2);
System.out.println(index);
//查找空值索引
System.out.println(list.indexOf(null));
list.clear();
//提醒JVM进行垃圾回收
System.gc();
}
}
缩容
如果内存使用比较紧张,动态数组有比较多的剩余空间,可以考虑进行缩容操作。
此时需要修改remove方法:
/**
* 删除索引为index处的元素
* @param index
* @return 被删除的元素
*/
public E remove(int index){
rangeCheck(index);
//保存被删除元素
E old=elements[index];
for(int i=index+1;i<size;i++)
elements[i-1]=elements[i];
//将最后一个对象的地址清空
elements[--size]=null;
trim();//缩容操作
return old;
}
private void trim(){
int oldCapacit=elements.length;
int newCapacity=oldCapacit >>1;
if(size>newCapacity||newCapacity<DEFAULT_CAPACITY)return;
//当数据量小于容量的1/2,缩容1/2
E[] newElements=(E[]) new Object[newCapacity];
for(int i=0;i<size;i++)
newElements[i]=elements[i];
elements=newElements;
System.out.println(oldCapacit+"缩容为"+newCapacity);
}
此外当进行clear()清空操作后,也可以进行缩容:
/**
* 清空所有元素
*/
public void clear(){
//清空存储的所有对象的地址,等待JVM进行垃圾回收
for (int i = 0; i < size; i++) {
elements[i]=null;
}
size=0;
//当数组被使用后情况且内存大小大于默认容量,缩容
if(elements!=null&&elements.length>DEFAULT_CAPACITY)
elements= (E[]) new Object[DEFAULT_CAPACITY];
}
测试代码:
public class ArrayList2Test {
public static void main(String[] args) {
ArrayList2<Integer> arrayList2=new ArrayList2<>();
for(int i=0;i<30;i++)
arrayList2.add(i);
System.out.println(arrayList2);
for(int i=0;i<25;i++)
arrayList2.remove(0);
System.out.println(arrayList2);
}
}

本文介绍了如何实现一个自定义的ArrayList类,包括初始化、增删改查等基本操作,并实现了动态扩容和缩容功能。在Student类中重写了equals和hashCode方法以支持对象的正确比较。测试类展示了ArrayList的使用,包括添加、查找和删除元素,以及清空后的缩容操作。
2885

被折叠的 条评论
为什么被折叠?



