集合, List接口, 数据结构介绍, ArrayList类, LinkedList类, 泛型

集合

  • 一个长度可变的容器
学习目标
  • 集合容器的创建
  • 集合中数据的赠删改查
  • 集合的遍历操作

image.png
image.png

Collection的使用

image.png

// 以多态的形式创建集合对象
Collection<String> c = new ArrayList<>();

c.add("张三");
c.add("李四");
c.add("王五");

// 判断集合中是否包含李四
System.out.println(c.contains("李四"));

// 根据元素做删除
boolean result = c.remove("李四");
System.out.println(result);

System.out.println(c.contains("李四"));

System.out.println(c);
System.out.println(c.isEmpty());
System.out.println(c.size());

// 清空集合所有元素
c.clear();

System.out.println(c);
System.out.println(c.isEmpty());
System.out.println(c.size());
注意事项
  • remove(), contains()底层依赖对象的equals方法

集合的通用遍历方式

迭代器

/*
    集合通用遍历方式 - 迭代器遍历
 */
public static void main(String[] args) {
    Collection<String> c = new ArrayList<>();

    c.add("张三");
    c.add("李四");
    c.add("王五");

    // 1. 获取迭代器
    Iterator<String> it = c.iterator();     // new Itr();

    // 2. 循环判断, 是否有元素可以取出
    while (it.hasNext()) {
        // 3. 使用迭代器获取元素
        String s = it.next();
        System.out.println(s);
    }
}
迭代器源码解析

image.png
hashNext(): 判断集合中是否还有元素
next(): 去除集合元素, 并将指针向后移动
注意:

  • 在循环过程中 next方法最好只调用一次

增强for循环

  • 简化迭代器的代码书写
  • 它是JDK5之后出现的,其内部原理就是一个lterator迭代器
  • 增强for循环是迭代器的语法糖
格式
for (元素的数据类型 变量名 : 数组或者集合) {
    
}

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

int[] arr = {11, 22, 33};
for (int num : arr) {
    System.out.println(num);
}

forEach方法

image.png

c.forEach(new Consumer<Student>() {
    @Override
    public void accept(Student stu) {
        System.out.println(stu);
    }
});

c.forEach(stu -> System.out.println(stu));

List接口

image.png

  • List因为支持索引, 所以多了很多索引操作的独特API

List的独特API

image.png

private static void method() {
    // 以多态形式创建对象
    List<String> list = new ArrayList<>();
    list.add("张三");
    list.add("李四");
    list.add("王五");

    System.out.println(list);

    list.remove(1);

    System.out.println(list);

    list.set(0, "张三丰");

    System.out.println(list);
}
注意
  • List存入Integer, 可以用索引删除, 也可以用元素删除, 但用元素删除时需要用Integer的手动装箱
private static void test() {
    List<Integer> list = new ArrayList<>();

    list.add(100);
    list.add(200);
    list.add(300);
    list.add(400);

    list.remove(Integer.valueOf(100));

    System.out.println(list);
}

List集合的遍历方式:

  1. 迭代器
  2. 增强for
  3. forEach方法
  4. 普通for循环, 因为有索引
  5. 使用List集合特有迭代器, ListIterator
/*
    List集合的遍历方式:

        1. 迭代器
        2. 增强for
        3. foreach方法
        4. 普通for循环, 因为有索引
        5. 使用List集合特有迭代器, ListIterator
 */
public static void main(String[] args) {
    List<Student> list = new ArrayList<>();

    list.add(new Student("张三", 23));
    list.add(new Student("李四", 24));
    list.add(new Student("王五", 25));

    // 1. 迭代器
    Iterator<Student> it = list.iterator();
    while (it.hasNext()) {
        System.out.println(it.next());
    }
    System.out.println("---------------------");

    // 2. 增强for
    for (Student student : list) {
        System.out.println(student);
    }
    System.out.println("---------------------");

    // 3. foreach方法
    list.forEach(s -> System.out.println(s));
    System.out.println("---------------------");

    // 4. 普通for
    for (int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i));
    }
    System.out.println("---------------------");

    // 5. 使用List集合特有迭代器, ListIterator
    ListIterator<Student> listIt = list.listIterator();
    while (listIt.hasNext()) {
        System.out.println(listIt.next());
    }

    System.out.println("----------------------");
    // 判断是否有前一个元素
    while (listIt.hasPrevious()) {
        // 取出前一个元素
        Student stu = listIt.previous();
        System.out.println(stu);
    }
}

并发修改异常

  • ConcurrentModificationException
public class ConcurrentModificationException extends RuntimeException
  • 当不允许这样修改时,检测到对象的并发修改的方法可能抛出此异常
  • 使用迭代器通历集合的过程中,调用了集合对象的添加,删除方法,就会出现此异常
  • 删除倒数第二个元素时不会报错

解决方案

  • 使用迭代器对象的添加\删除方法
    • 迭代过程中做删除:使用 iterator自带的 remove 方法
    • 迭代过程中做添加:使用 listIterator 自带的add方法

数据结构介绍

  • 数据结构是计算机底层存储,组织数据的方式,是指数据相互之间是以什么方式排列在一起的
  • 通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率

常见的数据结构

  • 队列
  • 数组
  • 链表
  • 二叉树
  • 二叉查找树
  • 平衡二叉树
  • 红黑树
  • 哈希表

数据结构 (数组)

  • 查询速度快: 查询数据通过地址值和索引定位,查询任意数据耗时相同
  • 增,删效率低: 新增或删除数据的时候,都有可能大批量的移动数组中其他的元素

数据结构(链表)

  • 链表中的结点是独立的对象,在内存中是不连续的,每个结点包含数据值和下一个结点的地址。
  • 链表查询慢,无论查询哪个数据都要从头开始找。
  • 链表增删相对快 (相对数组而言)

各种数据结构的特点和作用是什么样的

  • **栈:**后进先出,先进后出。
  • **队列:**先进先出,后进后出。
  • **数组:**内存连续区域,查询快,增删慢。
  • **链表:**元素是游离的,查询慢,首尾操作极快。

ArrayList

  • ArrayList底层是基于数组实现的,根据查询元素快,增删相对慢
public class ArrayListDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("张三");
    }
}

ArrayList长度可变原理

ArrayList源码.png
ArrayList源码解析

  1. 使用空参构造器创建的集合,在底层创建一个默认长度为0的数组
  2. 添加第一个元素时,底层会创建一个新的长度为10的数组
  3. 存满时,会扩容1.5倍

LinkedList

  • LinkedList底层基于双链表实现的,查询元素慢,增删首尾元素是非常快的

image.png

public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<>();

        list.add("a");
        list.add("b");
        list.add("c");

        System.out.println(list.get(1));
    }

    private static void method(LinkedList<String> list) {
        list.addFirst("a");
        list.addFirst("b");
        list.addFirst("c");
        list.addFirst("d");
        list.addLast("e");

        System.out.println(list);

        System.out.println(list.getFirst());
        System.out.println(list.getLast());

        list.removeFirst();
        list.removeLast();

        System.out.println(list);
    }
}

一个问题

  • LinkedList也有get方法,表面看起来是根据索引获取元素,实际上是?
Node<E> node(int index) {
    // assert isElementIndex(index);

    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

输入的index小于size的1/2时, LinkedList从头开始遍历查找, 大于size的1/2时, LinkedList从尾开始遍历查找

泛型

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

image.png

泛型的好处

  • 统一数据类型
  • 将运行期的错误提升到了编译期

**细节: **如果没有指定泛型, E 默认就是Object

/*
    泛型的好处:
        1. 统一数据类型
        2. 将运行期的错误提升到了编译期.

    细节: 如果没有指定泛型, E 默认就是Object
 */
public static void main(String[] args) {
    ArrayList list = new ArrayList();
    list.add("张三");
    list.add("李四");
    list.add("王五");
    list.add(new Random());

    Iterator it = list.iterator();
    while(it.hasNext()){
        Object o = it.next();
        String s = (String) o;
        System.out.println(s.length());
    }
}
注意事项
  • 泛型中只能便携引用数据类型

泛型的常见标识符

  • E : element 元素
  • T : Type 类型
  • K : Key 键
  • V : value 值

泛型类

  • 在创建对象的时候, 确定到具体的数据类型.

image.png

public class Demo2 {
    /*
        泛型的常见标识符 :

            E : element 元素
            T : Type 类型
            K : Key 键
            V : value 值

        泛型类: 在创建对象的时候, 确定到具体的数据类型.

     */
    public static void main(String[] args) {
        Student<Integer> stu = new Student<>();
    }
}

class Student<E> {
    private E e;

    public E getE() {
        return e;
    }

    public void setE(E e) {
        this.e = e;
    }

}

泛型方法

  1. 非静态: 方法中的泛型, 跟着类的泛型去匹配.

image.png

  1. 静态: 调用方法, 传入实际参数的时候

              - 注意: 静态方法中的泛型, 必须声明出自己独立的泛型
    

image.png

/*
    泛型方法:
        1. 非静态: 方法中的泛型, 跟着类的泛型去匹配.
        2. 静态: 调用方法, 传入实际参数的时候
                    - 注意: 静态方法中的泛型, 必须声明出自己独立的泛型
 */
public static void main(String[] args) {
    Integer[] arr1 = {11, 22, 33, 44, 55};
    Double[] arr2 = {11.1, 22.2, 33.3};
    String[] arr3 = {"张三", "李四", "王五"};

    printArray(arr1);
    printArray(arr2);
    printArray(arr3);
}

public static <T> void printArray(T[] arr) {
    System.out.print("[");
    for (int i = 0; i < arr.length - 1; i++) {
        System.out.print(arr[i] + ", ");
    }
    System.out.println(arr[arr.length - 1] + "]");
}

泛型接口

  • 类实现接口的时候,如果接口带有泛型,有两种操作方式
    1. 类实现接口的时候,直接确定类型
    2. 延续接口的泛型,等创建对象的时候再确定

image.png

 public static void main(String[] args) {

    }
}

interface Inter<E> {
    void add(E e);
}

class InterAImpl implements Inter<String> {
    @Override
    public void add(String s) {

    }
}

class InterBImpl<E> implements Inter<E> {
    @Override
    public void add(E e) {

    }
}

泛型通配符 (泛型限定)

  • ? : 任意类型
  • ? extends E : 可以传入的是E, 或者是E的子类
  • ? super E : 可以传入的是E, 或者是E的父类
public class Demo5 {
    /*
        泛型通配符

                ? : 任意类型

                ? extends E : 可以传入的是E, 或者是E的子类

                ? super E : 可以传入的是E, 或者是E的父类
     */
    public static void main(String[] args) {

        ArrayList<Coder> list1 = new ArrayList<>();
        list1.add(new Coder());

        ArrayList<Manager> list2 = new ArrayList<>();
        list2.add(new Manager());

        method(list1);
        method(list2);
    }

    public static void method(ArrayList<? extends Employee> list) {
        for (Employee employee : list) {
            employee.work();
        }
    }
}

abstract class Employee {
    private String name;
    private double salary;

    public Employee() {
    }

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public abstract void work();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String toString() {
        return "Employee{name = " + name + ", salary = " + salary + "}";
    }
}

class Coder extends Employee {
    @Override
    public void work() {
        System.out.println("程序员写代码...");
    }
}

class Manager extends Employee {
    @Override
    public void work() {
        System.out.println("项目经理分配任务...");
    }
}
  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值