简单重写ArrayList个别方法

首先简单回顾一下ArrayList
特点:在内存中分配连续的空间,只存储数据,不存储地址信息,位置就隐含地址。
底层结构:一个长度可以动态增长的数组
优点:1.节省存储空间,因为分配给数据的存储单元,全都用来存放节点的数据,节点之间的逻辑关系并没有占用额外的空间
2.索引查询效率高,每一个节点对应一个序号,该序号可以通过计算公式得到节点地址(通俗来说 一个长度为5的数组 首节点的地址为100 ,那么一个节点占用4个字节,第4个节点的地址即为100+4x4=116)
缺点:1.增加删除效率低,需要一个一个的位移元素
2.必须提前分配固定数量的空间 ,如果存储数据少了就造成空间的浪费
3.按照内容查询效率低 因为需要一个一个比较

通过无参构造方法创建对象时 JDK7默认给定长度为10 ,JDK8默认给的长度为0,添加元素时在给长度 10

长度不够时每次扩容50% 扩容原理:当空间不足时会创建一个新的数组 默认长度是之前长度的2倍,然后把原数组的内容拷贝到新的数组中 在把地址指向原数组
好了,废话不多说上代码了(***如果代码有问题的话,请留言!!!***)
先创建一个模拟需要实现的接口

  /**
     * 模拟list实现接口
     */
    public interface List {
        // 返回线性表的大小,即数据元素的个数。
        public int size();
        // 返回线性表中序号为 i 的数据元素 根据下标获取元素
        public Object get(int i);
        // 如果线性表为空返回 true,否则返回 false。判断是否为空
        public boolean isEmpty();
        // 判断线性表是否包含数据元素 e 判断集合中是否包含某元素
        public boolean contains(Object e);
        // 返回数据元素 e 在线性表中的序号 返回指定元素的下标
        public int indexOf(Object e);
        // 将数据元素 e 插入到线性表中 i 号位置 插入到指定下标的位置
        public void add(int i, Object e);
        // 将数据元素 e 插入到线性表末尾 添加元素
        public void add(Object e);
        // 将数据元素 e 插入到元素 obj 之前 将指定元素插入到标记元素之前
        public boolean addBefore(Object obj, Object e);
        // 将数据元素 e 插入到元素 obj 之后 将指定元素插入到标记元素之后
        public boolean addAfter(Object obj, Object e);
        // 删除线性表中序号为 i 的元素,并返回之 删除指定下标的元素
        public Object remove(int i);
        // 删除线性表中第一个与 e 相同的元素 删除第一个元素为e 的数据
        public boolean remove(Object e);
        // 替换线性表中序号为 i 的数据元素为 e,返回原数据元素 替换下标中的元素为指定元素
        public Object replace(int i, Object e);
        public Iterator iterator(); //实现迭代器
    
    }

创建迭代器接口

public interface Iterator<T> {

    boolean hasNext();

    T next();

}

实现ArratList接口中的常用方法

/**
 * 实现ArrayList 相关功能
 */
public class ArrayList implements List {

    private transient Object[] elementData; //ArrayList底层是一个长度可以动态增长的数组

    private int size = 0; //集合中元素的个数,不是数组分配了多少个空间

    public ArrayList(){
        //this(10);//JDK7的原理
        elementData=new Object[10];
    }

    public ArrayList(int initialCapacity){
        if(initialCapacity<0){
            throw new IllegalArgumentException("输入的参数不能小于0: "+initialCapacity);
        }
        elementData=new Object[initialCapacity];
    }



    /**
     * 获取数组长度
     * @return
     */
    @Override
    public int size() {
        return size;
    }

    /**
     * 获取指定下标的元素值
     * @param i 指定下标
     * @return
     */
    @Override
    public Object get(int i) {
        if(i<0||i>=size){
            throw new RuntimeException("数组索引越界异常:"+i);
        }
        return elementData[i];
    }

    /**
     * 判断数组是否为空
     * @return
     */
    @Override
    public boolean isEmpty() {
        return size==0;
    }

    /**
     * 判断数组中是否包含某元素
     * @param e 指定元素
     * @return
     */
    @Override
    public boolean contains(Object e) {
        return indexOf(e)!=1;
    }

    /**
     * 根据指定元素 返回该元素在数组中的下标
     * @param e
     * @return
     */
    @Override
    public int indexOf(Object e) {
        int index=-1;//表示不存在
        for (int i=0;i<size;i++){
            if(elementData[i].equals(e)){
                index=i;
                break;
            }
        }

        return index;
    }

    /**
     * 添加元素到指定的下标处
     * @param i
     * @param e
     */
    @Override
    public void add(int i, Object e) {
        //如果数组长度满了 扩充
        if (size==elementData.length){
            elementData= Arrays.copyOf(elementData,size*2);
        }
        //后移后面的元素
        for(int index = size-1; index >=i; index-- ){
            elementData[index+1] = elementData[index];
        }
        //添加元素
        elementData[i]=e;
        //数组长度自增
        size++;

    }

    /**
     * 添加元素到数组末尾
     * @param e
     */
    @Override
    public void add(Object e) {
        //如果数组长度满了需要扩容
        if(size==elementData.length){
//            //创建一个新的数组 数组的长度是原数组的长度的2倍
//            Object[] newArray=new Object[size*2];
//            //把原数组中的元素拷贝到新数组中
//            for (int i = 0; i <size; i++) {
//                newArray[i]=elementData[i];
//            }
//            //把新数组指定给原数组
//            elementData=newArray;
            elementData= Arrays.copyOf(elementData,size*2);//优化上面数据
        }
        //添加元素到数组末尾
        elementData[size]=e;
        //数组长度自增
        size++;

    }

    /**
     * 添加元素到数组某个元素之前
     * @param obj
     * @param e
     * @return
     */
    @Override
    public boolean addBefore(Object obj, Object e) {
        return false;
    }

    /**
     * 添加元素到标记元素之后
     * @param obj
     * @param e
     * @return
     */
    @Override
    public boolean addAfter(Object obj, Object e) {
        return false;
    }

    /**
     * 根据指定下标删除指定元素
     * @param i
     * @return
     */
    @Override
    public Object remove(int i) {
        return null;
    }

    /**
     * 根据元素值删除数组中第一个值为e的元素
     * @param e
     * @return
     */
    @Override
    public boolean remove(Object e) {
        return false;
    }

    /**
     * 根据指定的下标替换为指定的元素
     * @param i
     * @param e
     * @return
     */
    @Override
    public Object replace(int i, Object e) {
        return null;
    }

    /**
     * 实现迭代器
     * @return
     */
    @Override
    public Iterator iterator() {
        return new Itr();
    }

    /**
     * 重写toStirng
     * @return
     */
    @Override
    public String toString() {
        StringBuilder stringBuilder=new StringBuilder("[");
        for (int i=0;i<=size-1;i++){
            stringBuilder.append(elementData[i]+",");
        }
        if(size>0){
            stringBuilder.deleteCharAt(stringBuilder.length()-1);
        }
        stringBuilder.append("]");
        return stringBuilder.toString();
    }
    //使用内部类,可以直接访问外部类的成员变量
    private class Itr<T> implements Iterator<T> {
        int cursor =0;//默认值是0,用来指向当前元素,默认指向第0个
        @Override
        public boolean hasNext() {
            return cursor<size;
        }

        @Override
        public T next() {
            int i = cursor;
            if(i>=size){
                throw new NoSuchElementException("没有这个元素了,cursor:"+i);
            }
            cursor++;

            return (T)elementData[i];
        }
    }

}

测试方法

public class Test {
    public static void main(String[] args) {

        List list = new ArrayList();
        //向末尾添加元素
        list.add("11111");
        list.add("aaaaa");
        list.add("bbbbb");
        list.add("33333");
        list.add("22222");
        list.add(3, "AAAAA");
        //进行各种操作验证添加
        System.out.println(list.get(3));
        System.out.println(list.size());
        System.out.println(list.isEmpty());
        System.out.println(list.contains("11111"));
        System.out.println(list.indexOf("22222"));
        System.out.println(list.toString());
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String elem = it.next();
            System.out.println(elem);
        }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ArrayList实现了Serializable接口,这意味着ArrayList类可以将其对象序列化成字节流,以便于将其存储到文件或在网络上传输。 writeObject方法是ObjectOutputStream类的一个方法,它将Java对象写入输出流中以进行序列化。当ArrayList被序列化时,writeObject方法将被调用以将ArrayList对象写入输出流中。这个方法将遍历ArrayList对象并将其元素写入输出流中。由于ArrayList的元素可以是任何Java对象,因此这些对象也需要实现Serializable接口才能被序列化。在反序列化时,readObject方法将被调用以从输入流中读取数据并重新构造ArrayList对象及其元素。 因此,ArrayList重写writeObject方法是为了控制序列化ArrayList对象时的行为,例如序列化特定的属性,以及为序列化ArrayList的元素提供额外的安全检查。 ### 回答2: ArrayList重写writeObject方法的原因是因为在默认情况下,ArrayList的元素会使用序列化对象的方式进行存储,即将每个元素逐个写入输出流中。但是ArrayList本身不是实现了Serializable接口的类,所以在序列化时会抛出NotSerializableException异常。 为了解决这个问题,ArrayList重写了writeObject方法,实现了自己的序列化方式。在writeObject方法中,ArrayList会将其内部的元素转换为一个数组,然后将该数组进行序列化存储。这样就避免了直接序列化ArrayList本身的问题。 通过重写writeObject方法ArrayList能够在序列化和反序列化的过程中实现对元素的正确处理,确保ArrayList对象能够被正确地序列化和反序列化。这样,即使ArrayList本身不是一个可序列化的类,也能够正常地进行序列化和反序列化操作。 ### 回答3: ArrayList重写writeObject方法的原因主要有两个方面: 首先,ArrayList类是实现了Serializable接口的,意味着它可以被序列化成字节序列,以便在网络上传输或者保存到磁盘中等。而writeObject方法是在序列化过程中被调用的方法,它的作用是将对象的状态转换成字节序列的形式。ArrayList重写writeObject方法主要是为了自定义ArrayList对象的序列化过程。默认情况下,ArrayList对象会按照元素的顺序依次将元素序列化,但是在某些情况下,我们可能希望以其他方式将ArrayList对象转换成字节序列。通过重写writeObject方法,我们可以自定义ArrayList的序列化方式,例如只序列化部分元素或者特定条件下序列化元素等。 其次,ArrayList类是一个动态数组,它可以根据需要自动扩容和收缩。在默认的序列化过程中,writeObject方法会将ArrayList的容量也一同进行序列化,这就意味着在反序列化时需要还原ArrayList的容量设置。然而,在某些情况下,我们可能不希望容量信息也被序列化,因为容量信息并不代表实际元素的数量,它只是ArrayList内部用于优化性能的一个指示值。通过重写writeObject方法,我们可以忽略容量信息的序列化,从而简化反序列化的过程。 总之,ArrayList重写writeObject方法主要是为了自定义序列化过程,包括对元素的序列化顺序和容量信息的处理。这样可以更灵活地控制ArrayList对象在序列化和反序列化过程中的行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值