CH2 数组类3 - 优化泛型

2-6 使用泛型

优化数组类 ---- 使用泛型
将上一节刚创建的只适用int型 Array类,优化成任意类型
java中泛型可以放置任意类(不包括基本类型8种),只能是类对象。
但基本类型可以使用他们的包装类

改变成泛型类的注意事项

  1. 更改类名为泛型类
    在class Array后面添加<> ,
    <>内部可以起名字Item Element等等
    根据习惯,起名,这个E是随便起的,E本质代表某个类型,是类,在具体使用时可以再声明
    所以类名变成public class Array {}

  2. 将类中的逻辑(方法和变量)修改成泛型
    变量
    private int[] data;→改成private E[] data;

    构造函数
    data = new int[capacity];→改成 data = new E[capacity];
    但java中不支持这种写法,泛型数组要换一种写法,要绕一个湾子,先new出一个object[]数组,然后将数组强制转换成泛型(E())
    data = new int[capacity];→改成data = (E[])new Object[capacity]

    方法中
    将方法接收参数中的 data数组和数组元素e 都改成泛型E
    方法体中的data和E也改成泛型E

    = =改成equals
    原本是int型变量比较相等使用两个= =
    但泛型比较是对象比较,使用equals
    不变的在前面 变量放在equals(3)里面
    == 两个等号 是值比较
    equals是引用比较 ==

  3. remove泛型方法中,每个数组元素存储的是对象的引用
    当经过方法中删除逻辑时,size-- ,可对象引用还是存在不用的元素中了。需要将删除的对象引用释放掉。在size–;后面加一句data[size]=null;手动释放掉不用的。
    当data[size]不用时,即使不被手动null,以后也会被别的取代。这种数据被叫做loitering objects 闲逛对象
    loitering objects != memory leak
    闲逛对象!=内存泄漏,但如果可以将loitering objects手动处理掉是最好的

  4. 当使用泛型Array时,要指定声明的类型
    Array arr = new Array(20);→改成 Array arr = new Array<>(20);

使用泛型Array

//定义一个Student类型 ,作为泛型测试
public class Student {
    //定义变量
    private String studentName;
    private int studentAge;
    //构造函数,当new Student对象时使用构造函数来初始化
    public Student (String studentName, int studentAge) {
        this.studentName = studentName;
        this.studentAge = studentAge;
    }
    //重新toString,打印对象时可以按照对象特点输出
    @Override
    public String toString () {
        return String.format("studeng : name = %s, age = %d \n",studentName,studentAge);
    }
}

public static void  main(String[] args) {
    Array<Student> arr = new Array<>();
    arr.addLast(new Student("zhang",10));
    arr.addLast(new Student("wang",22));
    arr.addLast(new Student("li",33));
    System.out.println(arr);

}

修改成泛型后的Array类

public class Array<E> {

    //创建一个数组
    private E[] data;
    //size代表数组有多少个有效的元素
    //size也指向了第一个没有元素的索引位置
    private int size;

    //构造函数,传入数组的容量capacity来构造Array
    public Array(int capacity) {
        data = (E[])new Object[capacity];
        size = 0;
    }

    //默认构造函数,当用户不知道(不传入capacity时调用)数组容量时,用无参构造函数创建一个10的数组
    public Array() {
        this(10); //这个参数的语义时capacity,时IDEA提供的
    }

    //用户传入静态数组,然后生成Array类
    public Array(E[] args) {
        data = args;
        size = args.length;
    }

    //获取数组有多少个元素
    public int getSize() {
        return size;
    }

    //获取数组的容量
    public int getCapactiy() {
        return data.length;
    }

    //返回数组是否为空
    public boolean isEmpty() {
        return size == 0;
    }


    //下面是一个方法,没写完整类
    //向数组最后位置添加一个元素,在添加之前,要看数组是否还有空余位置
//    public void addLast(int e) {
//        if (size == data.length) {
//            throw new IllegalArgumentException("AddLast failed. Array is Full.");//先抛个异常,以后再处理
//        } else {
//            data[size] = e;
//            size ++;
//        }
//    }


    //在第index个位置添加一个新元素
    public void add(int index, E e) {
        if (size == data.length) {
            throw new IllegalArgumentException("AddElement failed. Array is Full.");//先抛个异常,以后再处理
        } else if (index < 0 || index > size) {
            //index>size 代表不是紧密地在最后添加,会有跳过的地方
            throw new IllegalArgumentException("AddElement failed. Require index < 0 || index > size.");//先抛个异常,以后再处理
        } else {
            //index之后的元素依次向后挪动,然后将e放到poz处,size增加1
            //要被处理i的开始位置是size-1结束位置是index
            for (int i = size - 1; i >= index; i--) {
                data[i + 1] = data[i];
            }
            data[index] = e;
            size++;
        }
    }

        //因为上一个方法是可以应用到上上个方法的
        public void addLast(E e) {
            add(size,e);
        }

        //复用add方法
        public void addFirst(E e) {
            add(0,e);
        }

        //获取index索引位置的元素
        public E get (int index) {
            if (index < 0 || index >= size) {
                throw new IllegalArgumentException("AddElement failed. Require index < 0 || index >= size.");//先抛个异常,以后再处理
            } else {
                return data[index];
            }
        }



        //查找是否包含某个元素
        public boolean contains (E e) {
            for (int i = 0; i < size; i ++) {
                if (data[i].equals(e)) {
                    return true;
                }
            }
            return false;
        }

        //查找某个元素的索引
        public int find (E e) {
            for (int i = 0; i < size; i ++) {
                if (data[i].equals(e)) {
                    return i;
                }
            }
            return -1;
        }
        //查找某个元素e的所有索引
        public void findAll (E e) {
            StringBuilder ret;
            for (int i = 0; i < size; i ++) {
                if (data[i].equals(e)) {
                    remove(i);
                }
            }
        }
        //更新index索引位置的元素
        public void set (int index,E e) {
            if (index < 0 || index >= size) {
                throw new IllegalArgumentException("AddElement failed. Require index < 0 || index >= size.");//先抛个异常,以后再处理
            } else {
                data[index] = e;
            }
        }

    //删除索引为index的某个元素,并且返回该元素的值
    public E remove (int index) {
        E ret = data[index];
        if (index < 0 || index > size) {
            //index>size 代表不是紧密地在最后添加,会有跳过的地方
            throw new IllegalArgumentException("AddElement failed. Require index < 0 || index > size.");//先抛个异常,以后再处理
        } else {
            //index之后的元素依次向前挪动,size减1
            //要被处理i的开始位置是size-1结束位置是index
            for (int i = index; i < size -1 ; i ++) {
                data[i] = data[i + 1];
            }
            data[size] = null;
            size --;          
        }
        return ret;
    }
    //从数组中删除第一个元素,复用remove
    public E removeFirst (int index) {
        return remove(0);
    }
    //从数组中删除最后一个元素,复用remove
    public E removeLast (int index) {
        return remove(size - 1);
    }
    //从数组中删除元素e(e存在的情况下) 复用find 和 remove
    public boolean removeElement (E e) {
        int index = find(e);
        if (index != -1) {
            remove(index);
            return true;
        } else {
            return false;
        }
    }
    //从数组中删除所有元素e
    public void removeAllElement (E e) {
        for (int i = 0; i < size; i ++) {
            if (data[i].equals(e)) {
                remove(i);
            }
        }
    }
    @Override
    public String toString () {
        StringBuilder res = new StringBuilder();
        res.append(String.format("Array: size = %d, capacity = %d \n",size,data.length));//先打印数组有多少个内容和总容量
        res.append('[');//然后追究第一个左边的【
        for (int i = 0; i < size; i ++) {//从第一个打印,打印到index=size-1(即最后一个内容)
            res.append(data[i]);
            if(i != size -1) {//如果不是最后一个内容,则后面加的,逗号
                res.append(", ");
            }
            res.append(']');//如果是最后一个则追加 】
        }
        return res.toString();
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值