week06_day05_自己实现ArrayList

总结昨天知识点:
总结:

List的子类

ArrayList
	特性:
		底层数据结构是数组, 增删慢, 查找快
		不同步, 线程不安全, 效率高
		存储null元素
	API:
		void ensureCapacity(int minCapacity)
		void trimToSize() 			
		
Vector
	特性:
		底层数据结构是数组, 增删慢, 查找快
		同步, 线程安全, 效率比较低
		存储null元素
		JDK1.0就已经有了
	API:
		
LinkedList
	特性:
		底层数据结构是链表, 增删快, 查找慢
		不同步, 线程不安全, 效率高
		存储null元素
		实现了Deque接口,可以用来当作栈、队列和双端队列
	注意事项:如果要使用栈, 推荐使用Deque接口, 而不是Stack类。

JDK5特性:
a. 静态导入
导入到方法级别, 并且只能导入静态的成员
作用:导入另外一个类的静态成员,就好像这些静态成员定义在本类中一样
b. 泛型
泛型的好处
泛型类
泛型方法
泛型的接口
泛型通配符
?, ? extends E, ? super E

Collection是一个跟接口吗? 不是,它还继承自Iterable接口
在这里插入图片描述
····························································································································································································································

泛型擦除也就是泛型被诟病的一个原因,因为在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

Iterator是一个迭代器,是一个工具。用来迭代的
Iterable表示一种能力,比如Collection是可以迭代的

这部分代码见下一篇文章。

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

作业:
1.LeetCode之合并两个有序数组
2.LeetCode之合并两个有序链表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-玫瑰少年-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值