java后端开发day32--集合进阶(二)ArrayList&LinkedList&泛型&通配符&二叉树

(以下内容全部来自上述课程)

1.ArrayList集合

  1. 利用空参创建的集合,在底层创建一个默认长度为0的数组。

  2. **添加第一个元素时,**底层会创建一个新的长度为10的数组。

  3. 存满时,会扩容1.5倍

  4. 如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准

源码分析

简述(口述太难,建议去听课):

  1. 最开始分两种情况:添加元素扩容到10没满(一) & 添加元素扩容到10但还是超出了(二)

  2. 第一种:先进行扩容到10的操作,由grow通过改变size+1(箭头往后移一位)执行:开始扩容,

    这里又分两种情况:初始为0只需要默认扩容到10(一) & 原本已经扩容到10需要继续进行1.5倍扩容(二)。

    这里是第一种情况,所以执行扩容到10的else语句(看图),到此grow执行完毕。执行后箭头后移指向添加好的元素。

  3. 第二种:前部分和第一种一样,到扩容的时候,因为超出需要扩容的10(一次直接超出或者多次添加超出是一样的,反正就是超了),所以执行if语句(看图),调用右下角的方法:得到最终的容量(至少和默认的容量作比较,因为两者之间的数值可以大于小于等于)返回(这就是实际长度,因为超出的根本没有规律,只能填多少加多少视情况而定),然后返回右上的方法,同时把老数组的元素复制到了新的数组,最后和第一种一样。

2.LinkedList集合

底层数据结构是双链表,查询慢,增删快,但是如果操作的是首尾元素,速度也是极快的。

LinkedList本身多了很多直接操作首尾元素的特有API。(了解)

1.LinkedList源码分析

2.迭代器源码分析

3.泛型

可以在编译阶段约束操作的数据类型,并进行检查。

格式:<数据类型>

注意:泛型只能支持引用数据类型。

如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型。

此时可以往集合添加任意的数据类型。

带来一个坏处:我们在获取数据的时候,无法使用他的特有行为。

此时推出了泛型,可以在添加数据的时候就把类型进行统一。

而且我们在获取数据的时候,也省得强转了,非常方便。

1.好处

  • 统一数据类型。
  • 把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确认下来。

扩展:Java中的泛型是伪泛型。

先检查添加的是否是String,但添加后会统一转为Object,使用的时候再统一转为String。

2.细节

  1. 泛型不能写基本数据类型。
  2. 指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型。
  3. 如果不写泛型,类型默认是Object。

3.定义

1.泛型类

当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类。

2.泛型方法

方法中形参类型不确定时

  1. 可以使用类名后面定义的泛型 所有方法都能用
  2. 在方法申明上定义自己的泛型 只有本方法能用

格式:

3.泛型接口

如何使用一个带泛型的接口?

  1. 实现类给出具体类型
  2. 实现类延续泛型,创建对象时再确定
4.通配符

泛型不具备继承性,但是数据具备继承性。

泛型里面写的是什么类型,那么只能传递什么类型的数据。

泛型的通配符:?

?也表示不确定的类型

他可以进行类型的限定

?extends E:表示可以传递E或者E所有的子类类型

?super E:表示可以传递E或者E所有的父类类型

应用场景:

  1. 如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口。
  2. 如果类型不确定,但是能知道以后只能传递某个继承体系中 的,就可以使用泛型的通配符
5.实例

Test:

java 复制代码
package fanxing;

import java.util.ArrayList;

public class Test1 {
    /*
    * 需求:
    *   定义一个继承结构:
    *                      动物
    *                |                  |
    *                猫                 狗
    *            |           |       |         |
    *          波斯猫       狸花猫     泰迪      哈士奇
    *
    * 属性:名字,年龄
    * 行为:吃东西
    *      波斯猫方法体打印:一只叫做XXX的,X岁的波斯猫,正在吃小饼干
    *      狸花猫方法体打印:一只叫做XXX的,X岁的狸花猫,正在吃鱼
    *      泰迪方法体打印:一只叫做XXX的,X岁的泰迪,正在吃骨头,边吃边蹭
    *      哈士奇方法体打印:一只叫做XXX的,X岁的哈士奇,正在吃骨头,边吃边拆家*

    测试类中定义一个方法用于饲养动物
    * public static void keepPet(ArrayList<???> list){
    *               //遍历集合,调用动物的eat方法
    * }/
     要求1:该方法能养所有品种的猫,但是不能养狗
     要求2:该方法能养所有品种的狗,但是不能养猫
     要求3:该方法能养所有品种的动物,但是不能传递其他类型*/

    public static void main(String[] args) {
        //创建集合对象
        ArrayList<PersianCat> list1 = new ArrayList<>();
        ArrayList<LiHuaCat> list2 = new ArrayList<>();
        ArrayList<TeddyDog> list3 = new ArrayList<>();
        ArrayList<HuskyDog> list4 = new ArrayList<>();

        keepPet1(list1);
        keepPet2(list3);
        keepPet3(list4);



    }
    //要求1:该方法能养所有品种的猫,但是不能养狗
    public static void keepPet1(ArrayList<? extends Cat> list){
        //遍历集合,调用动物的eat方法
        for (int i = 0; i < list.size(); i++) {
            Cat c = list.get(i);
            c.eat();
        }
    }
    //要求2:该方法能养所有品种的狗,但是不能养猫
    public static void keepPet2(ArrayList<? extends Dog> list){
        //遍历集合,调用动物的eat方法
        for (int i = 0; i < list.size(); i++) {
            Dog d = list.get(i);
            d.eat();
        }
    }
    //要求3:该方法能养所有品种的动物,但是不能传递其他类型
    public static void keepPet3(ArrayList<? extends Animal> list){
        //遍历集合,调用动物的eat方法
        for (int i = 0; i < list.size(); i++) {
            Animal a = list.get(i);
            a.eat();
        }
    }
}

Animal:

java 复制代码
package fanxing;

public abstract class Animal {
    private String name ;
    private int age;

    public Animal() {
    }

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public abstract void eat();

    public String toString() {
        return "Animal{name = " + name + ", age = " + age + "}";
    }
}

Cat:

java 复制代码
package fanxing;

public abstract class Cat extends Animal{
    //1.继承抽象类,重写里面所有的抽象方法
    //2.本身Cat也是一个抽象的,让Cat的子类再重写方法

    //此时采取第二个处理方案
    //因为猫的两个子类中eat的方法体还是不一样的。
}

Dog:

java 复制代码
package fanxing;

public abstract class Dog extends Animal{

}

PersianCat:

java 复制代码
package fanxing;

public class PersianCat extends Cat{
    @Override
    public void eat(){
        System.out.println("一只叫做"+getName()+"的,"+getAge()+"岁的波斯猫,正在吃小饼干");
    }
}

LiHuaCat:

java 复制代码
package fanxing;

public class LiHuaCat extends Cat{
    @Override
    public void eat(){
        System.out.println("一只叫做"+getName()+"的,"+getAge()+"岁的狸花猫,正在吃鱼");
    }
}

TeddyDog:

java 复制代码
package fanxing;

public class TeddyDog extends Dog{
    @Override
    public void eat(){
        System.out.println("一只叫做"+getName()+"的,"+getAge()+"岁的泰迪,正在吃骨头,边吃边蹭");
    }
}

HuskyDog:

java 复制代码
package fanxing;

public class HuskyDog extends Dog{
    @Override
    public void eat() {
        System.out.println("一只叫做"+getName()+"的,"+getAge()+"岁的哈士奇,正在吃骨头,边吃边拆家");
    }
}

4.数据结构

1.树




(有印象就行)

高度:父节点为0,依次往下每1层深度加1.

1.二叉查找树

1.添加节点:

小的存左边,大的存右边,一样的不存

2.弊端

添加节点容易失衡 (左短右长)

所以引入了平衡二叉树

2.遍历方式(二叉树)

建议去B站上找技巧听,考试的时候很好用。

1.前序遍历

从根节点开始,然后按照当前节点,左子节点,右子节点的顺序进行遍历。

2.中序遍历(重要)

从根节点开始,然后按照左子节点,当前节点,右子节点的顺序进行遍历。

3.后序遍历

从根节点开始,然后按照左子节点,右子节点,当前节点的顺序进行遍历。

4.层序遍历

从根节点开始一层一层遍历。

3.平衡二叉树

规则:任意节点 左右子树高度差不超过1.

4.树的演变

5.平衡二叉树旋转机制

规则1:左旋

规则2:右旋

触发时机:当添加一个节点之后,该树不再是一颗平衡二叉树。

1.左旋

确定支点:从添加的节点开始,不断的往父节点找不平衡(左右子树高度差为2)的节点。

旋转前:

旋转后:

复杂一点的:

旋转前:

旋转后:

2.右旋

上述请对称理解。

还是建议去听课,动图更好理解。

3.需要旋转的四种情况

左左:当根节点左子树的左子树 有节点插入,导致二叉树不平衡。--------一次右旋

左右:当根节点左子树的右子树 有节点插入,导致二叉树不平衡。--------局部左旋,整体右旋

右右:当根节点右子树的右子树 有节点插入,导致二叉树不平衡。--------一次左旋

右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡。--------局部右旋,整体左旋

相关推荐
修炼成精1 小时前
C#实现的一个简单的软件保护方案
java·开发语言·c#
乌云暮年2 小时前
算法刷题整理合集(四)
java·开发语言·算法·dfs·bfs
代码代码快快显灵2 小时前
SpringSecurity——如何获取当前登录用户的信息
java·开发语言·springsecurity
Luo_LA2 小时前
【排序算法对比】快速排序、归并排序、堆排序
java·算法·排序算法
果冻kk2 小时前
【Java集合夜话】第1篇:拨开迷雾,探寻集合框架的精妙设计
java·开发语言
佩奇的技术笔记2 小时前
高性能Java并发编程:线程池与异步编程最佳实践
java·性能优化
上官美丽2 小时前
Spring中的循环依赖问题是什么?
java·ide·spring boot
shangxianjiao2 小时前
nacos安装,服务注册,服务发现,远程调用3个方法
java·nacos·springboot
软件开发随心记3 小时前
EasyExcel动态拆分非固定列Excel表格
java·excel