【JavaSE 第十五天】

【JavaSE 第十五天】

一、 异常

异常的知识点不好理解,主要目的记住使用格式。

1. try…catch 异常处理

try catch的异常处理的格式写法

try{
    被检测的代码
    可能发生异常的代码
}catch(异常类的类名  变量名){
    异常的处理方式:写什么都可以
    定义变量,创建对象,调用方法,循环,判断...
    只要写了catch,异常就被处理掉了
}

测试:

	public static void main(String[] args) {
        int[] arr = {1};
        // try  catch异常处理,将可能发生异常的代码写入 try  catch 之中 
        try {
            int i = getNum(arr);
            System.out.println("i = " + i);
        }catch (Exception ex){
            System.out.println("异常被处理掉");
        }
        // 加上 try...catch 之后其中的异常就会被处理,使得之后的语句可以继续执行
        System.out.println("异常之后的的代码");
    }

    public static int getNum(int[] arr){
        return arr[1] + 10;
    }

try…catch 异常处理,处理机制

① arr[1] 索引不存在,不能计算,JVM 检测到索引的问题,JVM 创建了一个对象
② new ArrayIndexOutOfBoundsException(1) 将索引 1 传入
③ try 检测到有异常对象,异常对象继续抛出,抛到 catch 中
④ catch 捕获异常,相当于进行了 Exception ex = new ArrayIndexOutOfBoundsException(1) (Exception 是父类,ArrayIndexOutOfBoundsException 是子类,体现了多态性)
⑤ 异常被处理掉(异常是由 catch 处理的,没有再次返回到 JVM 中),继续向下执行代码

Throwable 类的,异常信息的处理方法的测试

    public static void main(String[] args) {
        int[] arr = {1};
        // try  catch异常处理,将可能发生异常的代码写入 try  catch 之中
        try {
            int i = getNum(arr);
            System.out.println("i = " + i);
        }catch (Exception ex){
            // Throwable 类的,异常信息的处理方法
            String message=ex.getMessage();
            System.out.println("message = " + message); // message = 1  这里的 1 就是越界异常的下标
            String str=ex.toString();
            System.out.println("str = " + str); // str = java.lang.ArrayIndexOutOfBoundsException: 1
            /**
             *  控制台输出:出现问题的异常类的类,错误的原因,发生问题的的代码行数
             *  java.lang.ArrayIndexOutOfBoundsException: 1
             * 	at com.xxxxxxx.object.ExceptionTest.getNum(ExceptionTest.java:23)
             * 	at com.xxxxxxx.object.ExceptionTest.main(ExceptionTest.java:8)
             */
            ex.printStackTrace();
        }
        // 加上 try...catch 之后其中的异常就会被处理,使得之后的语句可以继续执行
        System.out.println("异常之后的的代码");
    }

    public static int getNum(int[] arr){
        return arr[1] + 10;
    }

2. 多 catch 并行处理

异常处理的代码中:try 可以跟随多个 catch

好处:不同的异常,可以区别对待,分开处理

    public static void main(String[] args) {
        /**
         *   myException 中出现2个异常
         *   写2个 catch 分别捕获异常
         */
        try {
            myException(0); // 传递一是 处理空指针异常 传递零是 处理越界异常
        }catch (NullPointerException ex){
            System.out.println("处理空指针异常");
        }catch (ArrayIndexOutOfBoundsException ex){
            System.out.println("处理越界异常");
        }
    }
    /**
     *  多 catch 并行处理
     *  Exception 顶级父类
     *    Exception的子类: ①NullPointerException
     *          		   ②IndexOutOfBoundsException
     * 							②的子类: ArrayIndexOutOfBoundsException
     */
    public static void myException(int i){
        /**
         *  定义方法,目的是引发异常
         *  传递参数:对参数进行判断
         */
        if(i==0){
            // 引发空指针异常
            String s=null;
            int len=s.length();
        }else{
            // 引发越界异常
            int[] arr={};
            int a=arr[0];
        }
    }

多个catch处理异常的时候,写法特别注意:如果 catch 中的异常类没有继承关系,先写后写没有区别。 catch 中的异常类有继承关系时,父类写在最下面(如果父类写在上面,由于多态性,子类就无法捕获异常,成为多余的代码)

3. throw 和 throws 关键字的使用

  • throw 关键字:只能写在方法内部,关键字的后面跟随对象的创建
  • throws 关键字:只能写在方法的定义上,关键字后面跟随异常类名
    (内部有问题就用 throw,但是外界不知道该问题,对外声明暴露问题就需要 throws)
    /**
     *  throw 和 throws 关键字的使用
     */
    public static void main(String[] args) throws Exception {
        /**
         *  getArea() 调用方法,方法上有异常
         *  只能处理,否则就会编译失败
         *  两种处理方式:
         *   1.在 main 方法上加 throws 异常没有处理,交给了 JVM 处理
         *   2.try...catch 处理
         */																		// 2.try...catch 处理,可以这样写
        int area=getArea(-10);													// try {
        // 但是当传递 -10 时,仍是可以计算但是违反了实际,所以要在方法中加入校验		//     int area = getArea(-10);
        System.out.println("area = " + area);									//     System.out.println("area = " + area);
    }																			// } catch (Exception e) {
    /**																			//     e.printStackTrace();
     * 功能:计算正方形的面积,需要参数:边长										// }
     * 语法:方法内部如果出现了异常,必须在方法定义上暴露							// 推荐使用 try...catch 处理
     */
    public static int getArea(int length) throws Exception {
        if(length<=0){ // 数据错误,导致后面的计算无法进行
            // 内部出现问题
            throw new Exception("边长不存在");
        }
        return length*length;
    }

4. finally 代码块

finally 代码块跟随 try … catch 使用,也可以跟随 try 使用
finally 代码块里面的程序,无论是否出现异常,都会执行,必须执行(但是结束 JVM 后,finally 就不会执行)

finally 代码块后期主要用于释放资源
测试:

public static void main(String[] args) {
    try {
        int[] arr = {1};
        System.out.println(arr[1]);
    }catch (Exception ex){ // 捕获异常
        ex.printStackTrace();
    }finally {
        // 后期用于资源的释放
        System.out.println("这里的代码,必须执行");
    }
}

找茬问题①:

    public static void main(String[] args) {
        int x=getNum();
        System.out.println("x = " + x);
    }
    public static int getNum(){
        try{
            return 1;
        }catch (Exception ex){
            return 2;
        }finally {
            return 3;
        }
        // 方法一旦遇到 return 就会结束,但是 finally 一定要执行,所以 return 3; 就会覆盖 return 1;
    }

找茬问题②:

    public static void main(String[] args) {
        int x=getNum();
        System.out.println("x = " + x);
    }
    public static int getNum(){
        int a=1;
        try{
            return a; // 程序运行起来 a 就不存在了,就不能再进行运算,所以在这里 JVM 已经决定返回 "1" 了,所以不会再更改
        }catch (Exception ex){
            return a;
        }finally {
            ++a; // a 在这里变为 2,但是在前面已经决定返回 "1" 了
        }
    }
    // 最终结果就是 "1"

5. RuntimeException 异常

异常的父类是 Exception,Exception 类的子类有 RuntimeException,凡是 RuntimeException 和他的所有子类,都称为运行异常,RuntimeException 和的它的子类之外的则都称为编译异常

  • 编译异常:方法出现编译异常,调用者必须处理,否则编译失败。处理方式可以是 try…catch 或者是 throws
  • 运行异常:方法出现运行异常,在方法的定义上,不需要 throws 声明,调用者也不需要处理这个异常

建议不要处理运行异常:程序一旦发生运行异常,请程序人员修改源码

  • 常见的运行异常:
    • NullPointerException 空指针
    • IndexOutOfBoundsException 越界异常
    • ClassCastException 类型强制转换
    • IllegalArgumentException 无效的参数异常

6.自定义异常

Java 官方已经定义了大量的异常类,但是依然不够,以后做项目的时候,会出现的异常,在 JDK 中没有定义的,需要我们自己定义异常

  • 自定义异常,需要继承 Exception 或者 RuntimeException
    • 只有 Exception 和他的子类,才具有可抛出性
  • 在自定义的类中,构造方法,super 调用父类构造方法,传递异常信息

自定义的异常类:

/**
 * 自定义的 异常类
 *   成绩负数的异常
 *   选择继承的父类
 * 需要自定义信息:继承的父类 RuntimeException 带有 String 类型的构造方法 (String 异常信息)
 */
public class ScoreException extends RuntimeException{
    public ScoreException(String s){
        super(s); // 自定义的异常不要写死错误,用构造器传递参数
    }
}

测试类:

public class ScoreTest {
    public static void main(String[] args) {
        int avg=getAvg(100,-1);
        System.out.println("avg = " + avg);
    }
    /**
     * 计算成绩的平均分
     */
    public static int getAvg(int math,int chinese){
        // 判断成绩是否合法
        if(math<0||chinese<0){
            // 手动抛出自定义的异常
            throw new ScoreException("成绩不合法!");
        }
        return (math+chinese)/2;
    }
}

二、集合框架

1.集合框架由来

JDK 1.2 版本后,出现集合框架,到 JDK1.5 后,大幅度优化。

①集合本质上是存储对象的容器
②数组也能存储对象,数组的弊端就是定长(限制长度)
③为了解决数组的问题,开发出来集合框架,集合框架无需考虑长度

  • 集合和数组的区别与共同点:
    • 集合,数组都是容器,都可以存储数据
    • 集合只存储引用数据类型不存储基本数据类型
    • 数组可以存储基本类型,也可以存储引用类型
    • 数组定长,集合容器可以变长

牢记:数据多了存数组,对象多了存集合

  • 集合学习的关键点:
    • 怎么存储数据
    • 怎么取出数据
    • 选择哪种容器

2.集合框架的继承体系

(1)第一个派系:
  • Collection (集合) 顶级接口 单列集合(一次只能存一个对象)
    • List (列表) 接口
      • ArrayList (数组列表) 实现类
      • LinkedList (链表) 实现类
      • Vector (数组列表) 实现类,已过时
    • Set (集合) 接口
      • HashSet (哈希表) 实现类
        • LinkedHashSet (链表哈希表) 实现类,继承自 HashSet
      • TreeSet (红黑树) 实现类
(2)第二个派系:
  • Map (映射键值对) 顶级接口 双列集合(一次可以存两个对象)
    • HashMap (哈希表) 实现类
      • LinkedHashMap (链表哈希表) 实现类,继承自 HashMap
    • TreeMap (红黑树) 实现类
    • Hashtable (哈希表) 实现类,已过时
      • Properties (哈希表) 实现类,继承自 Hashtable
    • ConCurrentHashMap (哈希表) 线程相关
(3)存在一个独立的接口
  • Iterator 迭代器接口(用来做遍历)
(4)泛型
  • 泛型 Generic
    • 写法
    • 泛型类 ,泛型方法,泛型接口,泛型限定,泛型通配符
(5)增强型循环
  • for(:) 循环

3.Collection 接口

是所有单列集合的顶级接口,任何单列集合都是他的子接口或者是实现类,该接口中定义的方法,是所有单列集合的共性方法。

使用接口 Collection 的实现类 ArrayList,创建对象。
Collection<E> 尖括号就是泛型,(这是 API 文档中的写法)自己编程时 E 处要写,集合存储的数据类型

(1) Collection 接口的常用方法
方法的定义方法作用
boolean add(E)元素添加到集合
void clear()清空集合容器中的元素
boolean contains(E)判断元素是否在集合中
boolean isEmpty()判断集合的长度是不是0,如果是0返回 true
int size()返回集合的长度,集合中元素的个数
boolean remove(E)移除集合中指定的元素,移除成功返回 true
T[ ] toArray(T[ ] a)集合转成数组

Collection 接口的常用方法,使用ArrayList实现类创建对象

boolean add(E)
/**
 *  boolean add(E) 元素添加到集合中
 *  返回值,目前都是true
 */
public static void collectionAdd(){
    // 建议使用接口多态创建集合容器对象,存储的数据类型是字符串
    Collection<String> coll = new ArrayList<>(); // 后面尖括号中的数据类型可以不写,但是如果要写前后的数据类型必须一致
    // 注意:集合不能存储基本数据类型
    // 集合对象的方法 add 添加元素
    coll.add("hello");
    coll.add("world");
    coll.add("java");
    coll.add("apple");
    coll.add("banana");
    /**
     *  输出语句中,输出集合对象,调用的是方法 toString()
     *  看到的内容是一个完整的字符串,这种操作不叫遍历
     */
    System.out.println(coll);
}
void clear(), int size(), boolean isEmpty()
    /**
     *  void clear() 清空集合中的所有元素
     *  int size() 集合的长度
     */
    public static void collectionClear(){
        Collection<Integer> coll = new ArrayList<>(); // 可以写包装类,但是不能写 int
        coll.add(1);
        coll.add(2);
        coll.add(3); // 具备自动装箱的操作
        System.out.println(coll);
        System.out.println("集合的长度::"+ coll.size()); //长度
        coll.clear();
        System.out.println(coll); // 里面的元素被清空了,但是集合本身仍然存在
        System.out.println("集合的长度::"+ coll.size());
        System.out.println("集合是空吗?" + coll.isEmpty()); //长度=0,isEmpty() 返回 true
    }
boolean contains(), boolean remove()
    /**
     *  boolean contains(E)  判断是否包含
     *  boolean remove(E)  移除元素
     */
public static void collectionContains(){
    // 接口多态创建集合容器对象,存储的数据类型是字符串
    Collection<String> coll = new ArrayList<>();
    // 集合对象的方法 add 添加元素
    coll.add("hello");
    coll.add("wife");
    coll.add("world");
    coll.add("java");
    coll.add("apple");
    coll.add("banana"); 
    // 判断集合中是否包含某个元素
    boolean b = coll.contains("world");
    System.out.println("b = " + b);

    // 移除集合中的元素
    // 删除成功返回 true,如果有多个相同的对象,删除最先遇到的那个
    boolean b1 = coll.remove("banana"); // 写一个本来就没有的元素,删不掉就是 false
    System.out.println("b1 = " + b1);
    System.out.println(coll);
}

4. Iterator 接口

迭代器接口 Iterator ,为集合进行遍历的,迭代器技术是所有 Collection 集合的通用遍历形式。

(1)Iterator 接口的抽象方法
  • boolean hasNext() 判断集合中是否有下一个可以遍历的元素,如果有,就返回 true
  • E next() 获取集合中下一个元素(集合存的是什么,“E” 就是什么)
  • void remove() 移除遍历到的元素
(2)获取迭代器接口实现类

迭代器就是为了遍历集合而产生,集合的顶层接口 Collection 中定义了方法:方法的名字就是 iterator() ,返回值是 Iterator 接口类型,准确来说返回的是 Iterator 接口实现类的对象

Collection 接口中的方法摘要:
public Iterator iterator(); 返回迭代器接口实现类的对象

使用的对象 ArrayList ,它会实现接口 Collection,重写方法 iterator();(new 对象 new 的是 ArrayList, iterator() 是写在 ArrayList 的接口里面的,所以要进行方法重写)

public static void main(String[] args) {
    // 迭代器遍历集合
    Collection<String> coll = new ArrayList<>();
    coll.add("hello");
    coll.add("world");
    coll.add("java");
    coll.add("apple");
    coll.add("banana");
    // ①遍历 集合对象,调用方法 iterator() 获取迭代器接口的实现类对象
    Iterator<String> it = coll.iterator(); // 集合存什么,遍历时的数据类型就是什么,迭代器的泛型跟随集合
    // ②迭代器对象的方法,判断集合是否有下一个元素
    boolean b = it.hasNext();
    System.out.println(b); // 如果有就会返回 true
    // ③迭代器对象的方法,取出元素
    String str = it.next();
    System.out.println(str);
    // ② 与 ③ 的过程应该是反复执行的所以,使用循环:第②步与第③步可以缩减
    // 条件,集合中有下一个元素就可以
    while ( it.hasNext() ){
        String str =  it.next();
        System.out.println(str);
    }
    // 这种方式适用于所有的单列集合
}

迭代器在每一次运行中只可以使用一次
解释:
迭代器的运行可以看作是指针,开始指向索引 -1 位置,运行循环过程时,指针一直向后移动,最后停留在最后一个元素上,迭代器停止运行,程序结束。迭代器使用结束,如果需要再次使用迭代器,必须再次重新调用方法产生一个迭代器。

    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<>();
        coll.add("hello");
        coll.add("world");
        coll.add("java");
        coll.add("apple");
        coll.add("banana");
        Iterator<String> it = coll.iterator();
        while ( it.hasNext() ){
            String str =  it.next();
            System.out.println(str);
        }
        // 可以使用 for 循环调用方法产生新的迭代器重新遍历
        for(Iterator<String> its= coll.iterator(); its.hasNext(); System.out.println(its.next()));
        // 这种 for 循环的写法可以节约内存,变量写在 for 之中,for 循环一旦结束,对象就会消失。
    }
(3)迭代器的实现原理

每个集合容器,内部结构不同,但是迭代器都可以进行统一的遍历实现

结论:迭代器是隐藏在集合的内部的, 提供公共的访问方式: Iterator 接口

伪代码:

interface Iterator{
	// 定义一个接口
    boolean hasNext();
    E next();
    void remove();
}

public class ArrayList {
    public Iterator iterator(){ // 权限是公共的,返回值是 Iterator 接口类型
        return new Itr(); // 拿到内部类的对象,内部类实现了该接口,再使用内部类调用三个方法
    }
    
    private class Itr implements Iterator{
    	 // 私有的成员,外部要调用必须要有 get/set 方法
     	 // 要实现接口,必须重写方法
         boolean hasNext(); //重写,要加入权限和主体
    	 E next(); //重写,要加入权限和主体
         void remove(); //重写,要加入权限和主体
    }
    
}
(4)并发修改异常(属于运行异常)

异常的产生原因:在迭代器遍历集合的过程中,使用了集合的功能,改变了集合的长度造成的并发修改异常。

public static void main(String[] args) {
    Collection<String> coll = new ArrayList<>();
    coll.add("hello");
    coll.add("world");
    coll.add("java");
    coll.add("apple");
    coll.add("banana");
    // 迭代器遍历集合,首先获得接口的实现类
    Iterator<String> it = coll.iterator();
    while ( it.hasNext() ){
        String str = it.next(); // 取出元素
        // 判断,遍历到的集合元素是不是 java
        if (str.equals("java")){
            // 故意添加元素 出现并发修改异常
            coll.add("add");
            // 用集合的方法 add 改变了集合的长度,一旦改变长度就会出现并发修改异常
            // 但是有一个特殊情况,可以删除倒数第二个元素,不会报并发修改异常
            // 原因:遍历到倒数第二个元素时,将它已经删除导致循环无法进入,循环停止,it.next(); 就不会执行,就不会报错
            // 所以建议做遍历时就不要动集合中的元素
        }
        System.out.println(str);
    }
}
(5)集合存储自定义对象并迭代
public static void main(String[] args) {
    // 创建集合,存储自定义的对象
    Collection<Person> coll = new ArrayList<>();
    // 集合的方法 add 存储 Person 对象
    coll.add( new Person("张三",21) ); // 匿名对象存储
    coll.add( new Person("李四",22) );
    coll.add( new Person("王五",23) );
    // 迭代器遍历集合
    Iterator<Person> iterator = coll.iterator();
    while (iterator.hasNext()){
        Person person = iterator.next();
        System.out.println(person); // 打印对象需要调用 toString() 方法,否则返回哈希值地址
        System.out.println(person.getName()); // 单独打印姓名,调用方法即可
    }
}

建议重新创建一个包,并把 Person 类放入其中(简单的 Java 对象放在一起):

/**
 *  ①定义私有成员
 *  ② get set方法
 *  ③无参数构造方法(一定要有)
 *
 *  满足以上的三个条件,这个类,就可以换一个名字,叫作 JavaBean
 */
public class Person   {
    private String name;
    private int age;

	// 无参构造器
    public Person(){}
	// 有参构造器
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  • ①定义私有成员
  • ②拥有 get set方法
  • ③无参数构造方法(一定要有)

满足以上的三个条件,这个类就可以换一个名字,叫作 JavaBean

5. Collection 下的 List 接口

List 接口,继承 Collection 接口,是单列集合

(1)List 接口的特点
  • 这个接口的集合都具有索引
  • 这个接口中的元素允许重复
  • 这个接口中的元素是有序
    • 元素不会排序,有序指的是:元素存储和取出的顺序是一致的

List 接口的所有实现类,都具有以上三个特征
(与 List 接口并列存在的 Set 接口,基本上特点是相反的,Set 接口的集合没有索引,元素不允许重复,接口中的元素根据实际有些有序有些无序。)

(2)List 接口自己(独有)的方法 (带有索引)
add(int index ,E e)
/**
* List接口的方法 add(int index, E e)
* 指定的索引位置,添加元素
*
*   IndexOutOfBoundsException (继承自RuntimeException 异常) 集合越界异常  集合的长度是size()
*     子类:①StringIndexOutOfBoundsException 字符串越界异常  字符串的长度是 length()
*     		②ArrayIndexOutOfBoundsException 数组越界异常  数组的长度是 length
*/
public static void listAdd(){
    List<String> list = new ArrayList<>();
    list.add("a") ; // 这样是在集合的尾部添加
    list.add("b");
    list.add("c");
    list.add("d");
    list.add("e");
    System.out.println(list); // 按照输入的顺序输出
    // 指定的索引上,添加元素,3 索引上添加元素
    list.add(3,"QQ"); // 如果超出本来的索引数就会出现异常
    System.out.println(list); // 添加后按照索引,依次输出
}
get(int index)
    /**
     *  List 接口的方法 E get(int index)
     *  返回指定索引上的元素
     *  List 集合可以使用 for 循环像数组一样的方式遍历
     */
    public static void listGet(){
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        // List 接口方法 get 取出元素
        // String s = list.get(3);
        // System.out.println(s);
        for(int i = 0 ; i < list.size() ; i++){
            System.out.println(list.get(i));
            // 已经有了索引后,就和数组的遍历一样
        }
    }
set(int index,E e),remove(int index)
	/**
     *  List接口方法
     *  E set (int index , E e) 修改指定索引上的元素,返回被修改之前的元素
     *  E remove(int index) 移除指定索引上的元素,返回被移除之前的元素
     */
    public static void listSetRemove(){
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        System.out.println(list);
        // 修改指定索引上的元素,修改 3 索引
        String str = list.set(3,"https://www.baidu.com");
        System.out.println(list);
        System.out.println(str);
        // 删除指定索引上的元素,删除 3 索引
        str = list.remove(3);
        System.out.println(list);
        System.out.println(str);
    }
(3)List 集合的特有迭代器

List 接口中的方法 listIterator() 返回迭代器,迭代器的接口是 ListIterator ,集合的专用迭代器

  • ListIterator 迭代器接口的方法:
  • boolean hasNext()
  • E next()
  • boolean hasPrevious() 判断集合中是否有上一个元素,反向遍历
  • E previous() 取出集合的上一个元素
    /**
     *   List 接口的方法:
     *   listIterator() List 集合的特有迭代器
     *   反向遍历
     */
    public static void iterator(){
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        // 获取特有迭代器接口实现类对象
        ListIterator<String> lit = list.listIterator();
        // 由于集合遍历中的指针只有一个,需要让指针到最后位置,所以先要正向遍历
        while (lit.hasNext()){
            String s = lit.next();
            System.out.println(s);
        }
        // 反向遍历
        // 判断上一个元素
        while (lit.hasPrevious()){
            //取出元素
            String s = lit.previous();
            System.out.println(s);
        }
        // 反向遍历并不实用 
    }

6. List 接口的实现类 ArrayList

ArrayList 集合,其内部定义了一个数组,数组的名字叫做: elementDate ,默认初始化长度为 10,一旦超过长度 10,长度就会翻1.5倍,拷贝原数组中的值进入新数组,从而扔掉原数组,但是不能减容量,如果要删除中间的某个元素,就会把之后的元素复制粘贴前进到新的位置,但是它的数组长度不是元素存储的长度(10),而是其中所包含的的元素个数 ArrayList() 一旦被创建(new),就会构造一个初始容量为十的空列表,其中有一个计数器,一旦通过该类调用 size 计数器方法就会返回输入元素的个数

7. List 接口的实现类的数据结构

链表结构

链表
(存储数据时,都会放入三个节点中间的地方,起初的节点数据为 null ,要在之后再次输入数据就会在后一个节点中输入下一个元素的地址,再次在新地址中重复操作,存储到最后的节点数据也为 null,删除其中的一个数据,大体结构不会变化,就让要删除元素的上一个节点存储要删除元素的下一个的对象地址。)
数组与链表的对比:

  • 数组:
    • 有索引,数组中元素的地址是连续,查询速度快
    • 数组的长度为固定的,实现扩容需要新创建数组,要通过数组元素的复制,增加或者删除堆内存中的数据导致效率慢
  • 链表:
    • 链表没有索引,采用对象之间内存地址记录的方式存储
    • 查询元素,必须通过第一个节点依次查询,查询性能慢
    • 增删元素,不会改变原有链表的结构,速度比较快
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值