JAVA入门学习二

时间:2022-07-28
本文章向大家介绍JAVA入门学习二,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

[TOC]

0x05 JAVA控制流程语句

1.顺序结构语句

Q:什么是流程控制语句? 答:流程控制语句,可以控制程序得执行流程;

流程控制语句得分类:

  • 顺序结构
  • 选择(条件)结构 : if / switch
  • 循环结构 : for / while / do…while

Q:顺序结构语句执行流程? 答:从上而下,依此执行;

2.选择结构

选择结构分类:if语句 / switch 语句

使用案例:

//选择语句案例:
import java.util.Scanner;

import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory.Default;;
class Demo_SelectStatement {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入您选择的序号(0-2):");
        int list = sc.nextInt();
        System.out.print("请输入成绩:");
        int score = sc.nextInt();
        sc.close();

        /**
         * IF语句:
         * a.比较表达式无论简单还是复制,结果必须是boolean类型;
         * b.if语句控制的语句体如果是一条语句大括号可以省略(与其他编程语言一致);
         * c.一般来说有左大括号就没有分号,有分号就没有左大括号(代码if语句结束);
         **/
        if(list == 0){
            System.out.println("0.您输入序号是:"+list);
        }else if(list == 1){
            System.out.println("1.您输入序号是:"+list);
        }else if(list == 2){
            System.out.println("2.您输入序号是:"+list);
        }else{
            System.out.println("3.您输入序号有误!");
        };

        if(list % 2 == 0)
            System.out.println("少年,您发现了新大陆!if没有{}");

        /**
         * SWITCH语句:
         * a.表达式可以接收byte,short,char,int类型的数据,且引用数据类型还可以接收枚举(JDK1.5),String字符串(JDK1.7)
         * b.执行流程:先计算表达式的值然后在和case后面的匹配,如果有就执行对应的case语句,否则执行default控制语句
         * c.case后面只能是常量,不能是变量或者表达式,
         * d.switch语句遇到break就结束(不加break可能导致case穿透),遇到continue就继续执行下一个case语句
         * e.switch语句总是从上执行到下,不论default发在哪里
         **/    
        switch(score)
        {
            case 90:
                System.out.println("评分为优");
                break;
            case 80:
                System.out.println("评分为良");
                break;
            case 70:
                System.out.println("评分为中等");
                break;
            case 60:
                System.out.println("评分为良");
                break;
            default:
                System.out.println("不及格");
                break;  //最后一个break可以省略
        }
        
        //switch 注意点
        int x = 1;
        int y = 1;
        switch(x){
            default:
                y++; //2
            case 2:
                y++; //3
            case 3:
                y++; //4
        }
        System.out.println(y);   //4
            
    }
}

//########### 执行结果 ##########
// 请输入您选择的序号(0-2):3
// 请输入成绩:90
// 3.您输入序号有误!
// 评分为优
// 4
3.循环结构

循环结构分类:for / while / do…while 跳出循环:break; [ 只能在switch和循环中 ] 继续执行:continue; [ 只能在循环中 ] 结束方法:return value; 返回值作用不是结束循环而是结束方法;

(1) for循环 for循环执行流程:

  • 1.执行初始化语句
  • 2.执行判断语句,查看返回值是true(继续执行)还是false(退出循环)
  • 3.执行循环体语句
  • 4.执行循环后的操作表达式
  • 5.回到上面2处理进行判断

Q:三种循环语句的区别?

  • do…while循环至少执行一次循环体
  • for和while循环必须先判断条件是否成立然后再决定是否执行循环体;

案例:

// 循环语句结构
class Demo_Circulation {
    public static void main(String[] args) {
        //1.for 语句
        int sum = 0;
        for(int i = 0; i <= 10; i++)
        {
            if(i % 2 == 0)
            {
                sum += i;
                System.out.print(i+" ");
            }
        }
        System.out.println("n0~10之间偶数之和:"+sum);
        //水仙花数
        for(int i = 100; i <= 999; i++)
        {
            int i1 = i / 100 % 10; //百位
            int i2 = i / 10 % 10;  //十位
            int i3 = i % 10;      //个位
            if(Math.pow(i1, 3) + (Math.pow(i2, 3)) + (Math.pow(i3,3)) == i)
            {
                System.out.println("水仙花数:"+i);
            }
        }
        
        //2. while 语句
        int count = 0;  //计数器
        int number = 100;
        while(number <= 999) {
            int ge = number % 10;
            int shi = number / 10 % 10;
            int bai = number / 100 % 10;

            if((Math.pow(ge, 3) + Math.pow(shi, 3) + Math.pow(bai, 3)) == number) {
                System.out.print(number+" | ");
                count++;
            }
            number++;
        }
        System.out.println("水仙花数的个数:"+count);

        //3. do...while 语句
        int x = 0;
        sum = 0;
        do {
            sum += x;
            x++;
        }while(x <= 100);
        System.out.println("从1+2+..+100 = "+sum);
    }
}
 
//########## 执行结果 ##########
// 0 2 4 6 8 10
// 0~10之间偶数之和:30
// 水仙花数:153
// 水仙花数:370
// 水仙花数:371
// 水仙花数:407
// 153 | 370 | 371 | 407 | 水仙花数的个数:4
// 从1+2+..+100 = 5050

(2)控制跳转语句标号 标号:标记某个循环对其控制 (外outer/内inner),使用它可以跳出多重循环; 标号组成规则:其实就是合法的标识符。

// 控制流程案例
class Demo_Demo1 {
    public static void main(String[] args) {
        //* 1.九九乘法表 */
        for(int i = 1; i <= 9; i++)  //控制行数
        {
            for(int j = 1; j <= i; j++) //列数
            {
                System.out.print(j+"*"+i+"="+(i*j)+"t");
            }
            System.out.println("");
        }

        //* 2. 控制跳转语句标号 | mark 标记*/
        outer: for(int x = 1; x < 10; x++)
        {
            System.out.println("外循环:x = "+x);
            inner: for(int y = 1; y < 10; y++)
            {
                System.out.print("内循环:y = "+y +"t");
                if(x * y == 4)
                {
                    System.out.println("以跳出多重循环");
                    break outer;  //直接跳出多重循环 break 标号
                }
            }
        }

        //3.面试题 (下面http只是一个标号,后面是一个注释所有可以正确执行)
        http://www.baidu.com
        System.out.println("我也是可以正确执行得");
    }
}
// ##########################
// 外循环:x = 1
// 内循环:y = 1   内循环:y = 2   内循环:y = 3   内循环:y = 4   以跳出多重循环
// 我也是可以正确执行得

注意事项:

  • 一定要注意控制条件语句控制的那个变量问题,不要弄丢了否则会导致死循环;
  • 死循环方法:while(true) / for(;;)

0x06 JAVA函数(方法)

A:为什么要有方法?

  • 提高代码的复用性,使程序更加简洁易读,模块易扩展;

B:什么是方法?

  • 完成特定功能的代码块。

方法的格式:

main方法的格式详细解释:
public static void main(String[] args) 
- public : 被jvm调用,所以权限要足够大
- static : 被jvm调用,不需要创建对象直接类名.调用即可
- void   : 被jvm调用,不需要有任何的返回值
- main   : 只有这样写才能被jvm识别,main不是关键字
- String[] args : 以前是用来接收键盘录入的

修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2...) {
    方法体语句;
    return 返回值; 
}

//方法的格式说明
  * 修饰符:目前就用 public static。后面我们再详细的讲解其他的修饰符。
  * 返回值类型:就是功能结果的数据类型。
  * 方法名:符合命名规则即可。方便我们的调用。
  * 参数:
    * 实际参数:就是实际参与运算的。
    * 形式参数;就是方法定义上的,用于接收实际参数的。
  * 参数类型:就是参数的数据类型
  * 参数名:就是变量名
  * 方法体语句:就是完成功能的代码。
  * return:结束方法的。
  * 返回值:就是功能的结果,由return带给调用者。 
``` 


```java
import java.util.Scanner;
// JAVA函数(方法案例)
class Demo_Function {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("5 + 12 = " +sum(5,12)); //调用方法

        System.out.print("请输入显示多少个斐波那契:");
        int count = sc.nextInt();
        sc.close();
        System.out.println("显示"+count+"斐波那契数列:");
        fibonacci(count);


        //递归 -> 汉诺塔
        char a ='A',b='B',c='C';
        hanio(3,a,b,c);
        //递归 => 斐波那契
        System.out.println("第"+count+"个斐波那契数值为:"+fibo(10));
        System.out.println("第5个人的年龄为:"+age(5));
    }
    //1.方法需要 明确参数列表以及返回值类型
    public static int sum(int x, int y)
    {
        return x + y; 
    }

    //2.斐波那契
    public static void fibonacci(int count)
    {
        int a = 0;
        int b = 1;
        for(int i = 0; i < count; i++)
        {
            int temp = a;   //坑
            a = b;
            b += temp;
            System.out.print(a+"t");
        }
        return ; //返回值类型是void,return可以忽略系统也会默认加上return ;
    }

    //3.函数递归 汉诺塔
    public static void hanio(int n,char a,char b,char c){
        if(n==1)
            System.out.println("移动"+n+"号盘子从"+a+"到"+c);
        else{
            hanio(n-1,a,c,b);//把上面n-1个盘子从a借助b搬到c
            System.out.println("移动"+n+"号盘子从"+a+"到"+c);//紧接着直接把n搬动c
            hanio(n-1,b,a,c);//再把b上的n-1个盘子借助a搬到c
        }
    }

    //4.函数递归 斐波那契
    public static int fibo(int i)
    {
        if(i == 1 || i == 2 )
        {
            return 1;
        }else{
            return (fibo(i-1)+fibo(i-2));
        }
    }
    
    //5.函数递归 吃年龄问题
    public static int age(int person)
    {
        if (person == 1)
        {
            return 10;
        }else{
           return age(person-1) + 2;
        }
    }

}
//###########################
// 5 + 12 = 17
// 请输入显示多少个斐波那契:10
// 显示10斐波那契数列:
// 1       1       2       3       5       8       13      21      34      55      移动1号盘子从A到C
// 移动2号盘子从A到B
// 移动1号盘子从C到B
// 移动3号盘子从A到C
// 移动1号盘子从B到A
// 移动2号盘子从B到C
// 移动1号盘子从A到C
// 第10个斐波那契数值为:55

WeiyiGeek.递归原理图

方法的注意事项:

  • a:方法不调用不执行
  • b:方法与方法是平级关系,不能嵌套定义
  • c:方法定义的时候参数之间用逗号隔开
  • d:方法调用的时候不用再传递数据的类型
  • e:如果方法有明确的返回值,一定要有return带回一个值,如果没有return返回值 可导致 输出调用/赋值调用错误;

(1)方法重载概述和使用 A:什么是方法重载:

  • 在同一个类中,方法名相同,参数列表不同。与返回值类型无关。
  • 参数列表不同:
    • :参数个数不同
    • :参数类型不同
    • :参数的顺序不同(算重载,但是在开发中不用)

案例:

// 方法重载 overload 案例
class Demo_Overload {
    public static void main(String[] args) {
        //1.重载:方法名称相同。参数列表格式/类型不同(顺序不同),并且返回类型值无关
        System.out.println("重载案例1:"+sum(5,9));  //重载案例1:14.0
        System.out.println("重载案例2:"+sum(5,9,12));  //重载案例2:26
        System.out.println("重载案例3:"+sum(6,5.3,7.7)); //重载案例3:19.0

        System.out.println("#### 重载案例4 ####"); 
        System.out.println(isEqual(1,6));
        System.out.println(isEqual(6.1,6.1));
    }

    //(1) add方法求两个参数的和
    //注意返回的类型:
    public static double sum(int a,int b)
    {
        return (a + b);
    }

    //(2) add方法求三个整型参数的和
    public static int sum(int a, int b, int c)
    {
        return a + b + c;
    }

    //(3) add方法求三个浮点数参数这和
    //注意设置参数列表类型
    public static double sum(int a, double b, double c)
    {
        return a + b + c;
    }

    //案例4:比较两个整数/浮点数是否相等
    public static boolean isEqual(int a, int b)
    {
        return (a==b)?true:false;
    }
    public static boolean isEqual(double a, double b)
    {
        return (a==b)?true:false;
    }
}

// #### 重载案例4 ####
// false
// true

(2)方法可变参数的概述和使用 描述:定义方法的时候不知道该定义多少个参数 格式:修饰符 返回值类型 方法名(数据类型… 变量名){} 注意事项:

  • 这里的变量其实是一个数组
  • 如果一个方法有可变参数,并且有多个参数,那么可变参数肯定是函数的最后一个

基础实例:

public class Demo1_ChangeAbleArgs {
  public static void main(String[] args) {
    //实例1.可变参数函数讲解
    int[] arr = {11,33,22,77,32};
    print(arr);
    println(arr);
    printlns("重点:可变参数特征", arr);
  }
  
  //可变参数函数接收实际上是数组(与下面int ... arr)进行对比
  public static void print(int[] arr)
	{
    for (int i = 0; i < arr.length; i++) {
      System.out.print(arr[i] + " ");
    }
    System.out.println();
  }
  
  //可变参数采用...表示
  public static void println(int ... arr)
	{
    //foreach 方式值得学习
    for (int i : arr) {
      System.out.print(i + " - ");
    }
  }
  
  //多个参数,可变参数一定要放在函数参数的最后
  public static void printlns(String test, int ... arr)
	{
    System.out.println("n#####可变参数一定要放在函数参数的最后######n" + test);
     for (int i : arr) {
      System.out.print(i + " # ");
    }
  }
}

执行实例:

11 33 22 77 32 
11 - 33 - 22 - 77 - 32 - 
#####可变参数一定要放在函数参数的最后######
重点:可变参数特征
11 # 33 # 22 # 77 # 32 #

0x07 JAVA数组

Q:为什么要有数组(容器) 答:数组是储存在堆上的对象,可以存储同类型变量数据的多个值

数组的概念:

  • 数组是存储同一种数据类型多个元素的集合,也是一个容器
  • 数组可以存储基本数据类型也能存储引用数据类型

数组定义格式与初始化:

//如何对数据进行初始化
a.动态初始化,只指定长度由系统给出初始化值
    数据类型[] 数组名 = new 数据类型[数组长度] //[] 有几个代表几维数组
    int[] arr = new int[5]   //从内存中开辟5个连续的空间来存储5个int类型数据 动态初始化

b.静态初始化,给出初始值由系统判断长度
    数据类型[] 数组名 = new 数据类型[]{元素1,元素2,....};
    int[] arr = new int{1,2,3};
    int[] arr = {1,2,3};  //简化类型


//补充:对于动态初始化来说
整数类型:byte , short, int , long 默认初始值都是0
浮点类型:float , double 默认初始化初始值是0.0
布尔类型:boolean 默认初始值是'u0000'
//注解:u0000,其实每一个0其实代表的是16进制的0,4个0代表了16个二进制位
1.数组内存详解

(1) java内存分配及栈堆的区别

  • 栈(stack):存储局部变量,特点:先进后出
  • 堆(heap):存储new出来的数组或对象
  • 方法区:面向对象部分讲解
  • 本地方法区:和系统相关
  • 寄存器:给CPU使用

案例:

//数组案例
class Demo_array {
    public static void main(String[] args) {
        //#案例1.1: 动态初始化
        int[] arr = new int[5];  //动态创建5个连续的空间
        System.out.println(arr[0]); //系统默认初始化值,整数类型都是0
        arr[0] = 10;
        arr[1] = 11;
        arr[2] = 12;
        System.out.println(arr[0]); //对数组重新赋值后输出
        /** 
         * 数组arr信息:[[email protected]c8
         * [代表是数组,由几个代表几维
         * I代表是int类型
         * @是固定标识位
         * 8102c8代表16进制的地址值
        */
        System.out.println("数组arr信息:"+arr);

        //#案例1.2 (3个引用两个数组)
        int[] arr1 = new int[3];
        int[] arr2 = new int[3];
        int[] arr3 = arr2;  // arr3 实际指向arr2的内存地址
        arr1[0] = 1;
        arr2[1] = 2;
        arr3[1] = 3; //arr3将回覆盖arr2[1]的值
        arr3[2] = 3; 
        System.out.println("arr1数组:"+arr1[0] + "t" + arr1[1]  + "t" + arr1[2]);
        System.out.println("arr2数组:"+arr2[0] + "t" + arr2[1]  + "t" + arr2[2]);
        System.out.println("arr3数组:"+arr3[0] + "t" + arr3[1]  + "t" + arr3[2]);
//############ 执行结果 ####################
// 0
// 10
// 数组arr信息:[[email protected]
// arr1数组:1     0       0
// arr2数组:0     3       3
// arr3数组:0     3       3

        //#案例2.2 静态初始值 (注意不允许动静结合)
        int[] arr4 = new int[] {1,2,3,4,5};  //声明数组引用 (先默认初始化值0 / 然后在显示初始化值)
        int[] arr6;                          //另外一种书写方法
        arr6 = new int[] {5,4,3,2,1};

        int[] arr5 = {1,2,3,4,5};  //简写形式声明和赋值在同一行(必须)
        System.out.println(arr4[0]); //1
        System.out.println(arr5[4]); //5
    }
}

WeiyiGeek.数组内存图

2.一维数组/多维数组

(1) 一维数组 数组遍历:依此输出数组元素中每一个元素; 数组属性:arr.length = 数组的长度; 数组最大索引值:arr.length - 1;

一维数组案例:

//一维/多维数组
class Demo_ArrayDemo {
    public static void main(String[] args) {
        //案例1:常规数组遍历
        int[] arr = {126,115,17,129,80};
        for(int i = 0; i < arr.length; i++)
        {
            System.out.print(arr[i]+"t");
        }
        System.out.println();

        //案例2: 封装方法调用数组遍历
        print(arr);
        //案例3:获取数组中的最大值
        System.out.println("n数组arr最大值:"+printMax(arr));
        //案例4:反转数组
        reverseArray(arr);
        //案例5:查找数组元素(返回其索引)
        int res = searchIndex(115, arr);
        if(res != -1)
        {
            System.out.println("n查询值得Index = " + res);
        }else{
            System.out.println("n未查询到相应值的索引!");
        }
    }

    /***
     * function_name: print
     * function:数组的遍历
     * param:参数列表int[] arr
     * return:返回值类型void
     */
    public static void print(int[] arr)
    {
        for(int i = 0; i < arr.length; i++)
        {
            System.out.print(arr[i]+"t");
        }
    }

    /**
     * function_name:printMax
     * function:获取数组中最大值
     * 参数:int[] arr
     * 返回:int 类型
     */
    public static int printMax(int[] arr1) {
        int max = arr1[0];  //这里记录数组中第一值就行
        for(int i = 1; i < arr1.length; i++)
        {
            max = max > arr1[i] ? max:arr1[i];
        }
        return max;
    }

    /**
     * function_name : reverseArray 
     * function:数组元素反转
     * 参数:传入数组
     * 返回值:void
     **/
    public static void reverseArray(int[] arr2) {
        for(int i = 0 ; i < arr2.length / 2 ; i++)
        {
            int temp = arr2[i];
            arr2[i] = arr2[arr2.length-1-i]; //注意这里需要进行-1
            arr2[arr2.length-1-i] = temp;
        }
        //之后再调用上面的输出即可
        print(arr2);
    }

    /**
     * function_name: searchIndex
     * function:查找对应元素的索引
     * 参数:传入查找的int值,与int[] arr数组
     * 返回值:int类型的索引值
     */  
    public static int searchIndex(int value,int[] arr3)
    {   
        int index = -1;
        for(int i = 0; i < arr3.length; i++)
        {
            if(arr3[i] == value)
            {
                return i;
            }
        }
        return index; 
    }
}

//############## 执行结果 ############
// 126     115     17      129     80
// 126     115     17      129     80
// 数组arr最大值:129
// 80      129     17      115     126
// 查询值得Index = 3

(2) 多维数组 二维数组格式:

1. 数据类型[][] 数组名 = new 数组类型[m][n]; #常用
2. 数据类型 数组名[][] = new 数据类型[m][n];
3. 数据类型[] 数组名[] = new 数组类型[m][n];
4. 数据类型[][] 数组名 = new 数组类型[m][];

int[][] arr = new int[3][2];

#注意数组定义得时候
int[] x,y[] #此时x是一维数组,Y是二维数组;

#多维数组得默认初始化值为:null;

(3)数组传递参数引用 基本数据类型得值传递,不改变原来得值;因为调用后就会弹栈,局部变量随之消失; 引用数据类型得值传递,改变原址;因为即使方法弹栈,但是堆内存数组对象还在,可以通过地址继续访问;

Q:JAVA中到底传值还是传址? 答:即是传值也是传地址,基本数据类型传递得值,引用数据类型传递得地址;但是常常我们再面试中会说java只有传值,因为地址值也是值;

案例:

//*多维数组 *//
class Demo_MutilArray {
    public static void main(String[] args) {
        //1. 方式1
        int[][] arr = new int[2][3];  // 默认初始化值为0 (注意与下面方式4得异同)
        //2. 方式2
        int[] arr1[] = new int[2][3];
        //3. 方式3
        int arr2[][] = new int[2][3];

        System.out.println("方式1:"+arr[0]+" ,首地址:"+ arr); //打印得是一维arr[0]得地址与arr[0][0]首地址 【注意这里与C语言不同】
        System.out.println("方式2:"+arr1[0][0]);
        System.out.println("方式3:"+arr2[1][2]); // 2行/三列

        //4. 方式4
        int[][] arr3 = new int[3][]; //存放了三个一维数组  默认初始化值为null,由于我们没有给出二维数组得值;
        System.out.println(arr3[0] +", " +arr3[1] +", "+arr3[2]);
        arr3[0] = new int[3]; //第一个一维数组存放了3个int值
        arr3[1] = new int[5]; //第二个一维数组存放了5个int值
        System.out.println(arr3[0] +", " +arr3[1] +", "+arr3[2]);

//############### 执行结果 ###############        
// 方式1:[[email protected] ,首地址:[[[email protected]
// 方式2:0
// 方式3:0
// null, null, null
// [[email protected], [[email protected], null

        //**案例1 */
        int[][] arr4 = {{1,2,3},{4,5},{6,7,8,9}};
        System.out.println("arr4:"+arr4+", arr[0]:"+ arr[0] + ", arr[0][0]:" + arr[0][0]+"n");
        //arr4 : 是一个二维数组地址值
        //arr4[0] : 一维数组得地址值
        //arr4[0][0] : 二维数组中得元素值
        //外循环控制行,内循环控制列
        for(int i = 0; i < arr4.length; i++ )
        {
            for(int j = 0; j < arr4[i].length; j++)  //获取每一一个一维数组中得元素
            {
                System.out.print(arr4[i][j] + "t");
            }
            System.out.println("n");            
        }

        //**案例2:将数组进行参数传递后值将被改变 */
        int[] arr5[] = {{1,2},{3,4,7}};
        arrayChange(arr5);  //数组中得值将发生改变
        for(int i = 0; i < arr5.length; i++ )
        {
            for(int j = 0; j < arr5[i].length; j++)  //获取每一一个一维数组中得元素
            {
                System.out.print(arr5[i][j] + "t");
            }
            System.out.println();            
        }
    } 

    /**
     * 函数名:arrayChange
     * 函数功能:实现二维数组中值进行*+1
     * 函数参数:array[][] 二维数组
     * 函数返回值:none
     */
     public static void arrayChange(int[][] array){
        for(int i = 0; i < array.length; i++ )
        {
            for(int j = 0; j < array[i].length; j++)  //获取每一一个一维数组中得元素
            {
                array[i][j] += 1;
            }
        }
     }

}

// ############### 执行结果  ##############
// arr4:[[[email protected], arr[0]:[[email protected], arr[0][0]:0
// 1       2       3
// 4       5
// 6       7       8       9

// 2       3
// 4       5       8

WeiyiGeek.二维数组内存图

n.数组越界和空指针

java数组中常见的异常情况:

  1. a:数组索引越界异常: java.lang.ArrayIndexOutOfBoundsException
  • 原因:访问了不存在的索引
  1. b:空指针异常: java.lang.NullPointerException
  • 原因:数组已经不指向堆内存空间地址,而您还使用数组名去访问元素;
// 数组异常案例
class Demo_ArrayException {
    public static void main(String[] args) {
        //1.数组索引越界异常
        int[] arr = new int[] {0,1,2}; //注意不能动静结合(这里与c/c++中数组是不一样的)
        //发生异常: java.lang.ArrayIndexOutOfBoundsException
        //System.out.println(arr[3]);  //发生异常: java.lang.ArrayIndexOutOfBoundsException

        //2.空指针异常
        int[] arr1 = new int[5];
        arr1 = null; // 使用null进行赋值为空,== 野指针(访问不再是执行堆内存空间的实体)所有再次调用回导致空指针异常
        //System.out.println(arr1[1]); //发生异常: java.lang.NullPointerException
    }
}