欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

week06_day05_自己实现ArrayList

程序员文章站 2022-05-09 13:54:25
...

Collection是一个跟接口吗? 不是,它还继承自Iterable接口
week06_day05_自己实现ArrayList

泛型擦除也就是泛型被诟病的一个原因,因为在jvm执行的时候,它里面根本就没有泛型的信息。

package com.cskaoyan.jdk5;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/*
泛型擦除:编译器在编译的过程中,会把泛型信息"擦除"。
	我们代码中写的--->编译器编译后的
    E --> Object
    ? extends Animal --> Animal
    ? super Animal --> Object
 */
public class GenericDemo1 {
    
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("hello");
        list.add("world");
        list.add("java");
        for(Iterator<String> it = list.iterator(); it.hasNext(); ) {
            String s = it.next();
            System.out.println(s);
        }
    }
}

下面看一个题目:

package com.cskaoyan.jdk5;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * @author shihao
 * @create 2020-05-15 15:35
 * <p>
 * 如何向List<String>中添加一个int类型的整数
 */
public class GenericDemo02 {

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        ArrayList<String> list = new ArrayList<>();
        list.add("hello");
        list.add("world");

        Class<? extends ArrayList> c1 = list.getClass();
        //查看ArrayList中的add方法,boolean add(E e) ,其参数类型是: E
        //那泛型E被擦除后会变成什么? Object
        Method addMethod = c1.getMethod("add", Object.class);
        //invoke()中第一个参数表示要在哪个对象上调用,第二个参数表示add方法中的形参
        addMethod.invoke(list, 1);

        System.out.println(list);

        //如何获取这个整数
        //1.用Object获取,然后强转
        Object o = list.get(2);
        int k = (int) o;
        System.out.println(k);

        //2.反射

    }
}

反射的前提是先要获取字节码文件对象,由于泛型擦除,字节码文件对象里不会有泛型信息。
既然没有,String就起不到限制了,所以就可以利用反射机制向List中插入一个整数。

··············································································································································································································

ArrayList中的
T[ ] toArray(T[ ] a)
按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。

package com.cskaoyan.jdk5;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/*
<T> T[] toArray(T[] a)
如果数组a能够容纳集合中的元素, 那么这个方法会把元素填充到数组a中。
如果数组a不能够容纳集合中的元素, 那么就会新创建一个数组, 并把集合的元素填充到新数组中。
 */
public class GenericDemo3 {
    
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("hello");
        list.add("world");
        list.add("java");

        // String[] strs = new String[3];
        // String[] strs = new String[4];
        /*String[] strs = new String[2];
        System.out.println(Arrays.toString(strs));

        String[] arr = list.toArray(strs);
        System.out.println(Arrays.toString(arr));
        System.out.println(Arrays.toString(strs));
        System.out.println(arr == strs);*/

        //一般我们这样使用这个方法
        String[] arr = new String[list.size()];
        list.toArray(arr);
        System.out.println(Arrays.toString(arr));
    }
}

String[] arr = list.toArray(strs)
如果strs空间够用,arr和strs指向同一地址,即arr = strs为true
不够用,不会传入到strs中,arr == strs 为false

·················································································································································································································

增强for循环概述
简化数组和Collection集合的遍历

格式:
for(元素数据类型 变量 : 数组或者Collection集合) {
使用变量即可,该变量就是元素
}

好处:简化遍历

注意事项:增强for的目标要判断是否为null

本质:foreach对数组进行特殊处理, 会用迭代器遍历其它类型的对象。
问题:什么对象可以使用foreach循环?
数组和实现了Iterable接口的对象。

public class ForeachDemo1 {

    public static void main(String[] args) {
        String[] strs = {"刘亦菲", "王语嫣", "花木兰"};
        for (int i = 0; i < strs.length; i++) {
            System.out.println(strs[i]);
        }

        for(String s : strs) {
            System.out.println(s);
        }

        System.out.println("----------------------");
        List<String> list = new ArrayList<>();
        list.add("赵灵儿");
        list.add("白秀珠");
        list.add("铁手");

        for(Iterator<String> it = list.iterator(); it.hasNext(); ) {
            String s = it.next();
            System.out.println(s);
        }

        for(String s : list) {
            // System.out.println(s);
            //ConcurrentModificationException  并发修改异常
            if ("赵灵儿".equals(s)) list.remove(s);
        }
    }
}

foreach底层实现还是和以上代码一样

public interface Iterable 实现这个接口的对象,允许使用foreach循环。

·················································································································································································································

可变参数概述
定义方法的时候不知道该定义多少个参数,我们就可以使用可变长参数。

格式
修饰符 返回值类型 方法名(数据类型… 变量名){}
注意:
这里的变量其实是一个数组
可变长参数只能位于最后

底层就是一个数组,完全可以把可变长参数看成一个数组。
但是我们代码的可读性更高了。

public class VariableDemo1 {
    /*public int add(int a, int b) {
        return a + b;
    }

    public int add(int a, int b, int c) {
        return a + b + c;
    }*/
    // 如何求任意个整数之和呢?

    /*public static int add(int[] arr) {
        int sum = 0;
        for(int i : arr) sum += i;
        return sum;
    }*/

    public static int add(int... arr) {
        int sum = 0;
        for(int i : arr) sum += i;
        return sum;
    }


    public static void main(String[] args) {
        // int[] arr = {1, 2, 3, 4, 5};
        // int sum = add(arr);
        int a = 1;
        int b = 2;
        int c = 3;
        int sum = add(1, 2, 3);
        sum = add(a, b, c);
        System.out.println(sum);
    }
}

Arrays工具类中的一个方法
public static List asList(T… a)

集合 --> 数组
T[ ] toArray(T[ ] a)
数组 --> 集合
static List asList(T… a) 视图技术 (Arrays类中)

public class VariableDemo3 {

    public static void main(String[] args) {
        String[] arr = {"hello", "world", "java"};
        List<String> list = Arrays.asList(arr);
        // System.out.println(list);
        
        //不支持增加操作
        // list.add("collection"); // UnsupportedOperationException
        // System.out.println(list);

        //不支持删除操作
        // list.remove(1); //UnsupportedOperationException
        // System.out.println(list);

        //支持更改操作
        list.set(2, "JAVA");
        System.out.println(list);
        //修改后原数组中的数据也会改变
        System.out.println(Arrays.toString(arr));
    }
}

jdk5中的新特性其实就是把一些机械化的东西交给编译器去做,而程序员不需要关心这些事情

·················································································································································································································

数据结构

数据结构是相互之间存在一种或多种特定关系的数据元素的集合。

公式:数据结构=数据+结构

数据:用类型表示

结构:在任何问题中,数据元素都不是孤立存在的,它们之间都存在着某种关系,这种数据元素相互之间的关系称为结构。

元素之间,通常有以下四种基本结构:

集合:结构中的数据元素之间除了同属于一个集合的关系之外,别无其他关系。这里的集合和数学中集合的概念是一致的。
哈希表就属于集合
线性结构:结构中的数据元素之间存在一个对一个的关系。
树形结构:结构中的数据元素之间存在一个对多个的关系。
图或网状结构:结构中的数据元素之间,存在多个对多个的关系。

前面分类中定义的关系,描述的是数据元素间的逻辑关系,因此又称为逻辑结构

但是仅仅知道数据元素间的逻辑关系是不够的,因为我们得实现自己的数据结构。
因此,我们得关注数据结构在计算机底层是如何表示的?

数据结构在计算机中的表示,称为数据的物理结构,又称为存储结构或者映像。

数据的表示很简单。

结构的表示可以分为两种:顺序存储结构 (顺序映像) 和 链式存储结构 (非顺序映像)。

顺序映像:借助元素在存储器中的相对位置来表示数据元素之间的逻辑关系。(数组)

非顺序映像:借助指示元素存储地址的”指针”,来表示数据元素的逻辑关系。(链表)

·················································································································································································································

线性表:n个数据元素的有序序列。

首先,线性表中元素的个数是有限的。
其次,线性表中元素是有序的。

那这个”序”指的是什么呢?

如果以ai表示数据元素,则线性表可以记为 {a1, … , ai-1, ai, ai+1, … , an}
表中, ai-1在 ai 之前,同时ai+1 在 ai 之后,我们称ai-1是ai的直接前驱,ai+1是ai的直接后继。
除表头和表尾元素外,其它元素都有唯一前驱和唯一后继,其唯一前驱或唯一后继确定了该元素在线性表中的位置。
因此,线性表中,每个数据元素都有一个确定的位序,这个确定的位序我们称之为索引。
表头元素有唯一后继,无前驱,表尾元素有唯一前驱,无后继。

实现:
顺序映像 (ArrayList)
非顺序映像 (LinkedList)

·················································································································································································································
我们自己实现一个ArrayList