JavaSE第05篇:Java基础语法之数组、方法

本篇我们将会学习Java基础语法之数组和方法。数组,是一种基础的数据结构,数组可以让我们通过一个变量管理一组数据;方法可以将一个功能封装,在需要这个功能的地方,只需要调用方法即可,而不用再重复编写冗余的代码。接下来,我们将会详细讲解Java中的数组、方法。

第一章:数组

1.1-为什么要学习数组(了解)

需求:统计10个人每个人的薪资,并计算出10个人薪资的总和以及平均薪资?

此时,面临这个需求,我们会怎么做呢?

按照目前已经学过的知识,我们可能会这么解决:

  1. 定义10个变量,存放10人的薪资
  2. 让10个变量相加,计算总薪资
  3. 让总薪资除以10,计算平均薪资

以上的解决方案,确实可以满足我们的需求,代码如下:

package com.penglei666.com;

public class Test01 {
    public static void main(String[] args) {
        /*
        * 定义10个变量,存放10个人的薪资
        * */
        double salary1 = 10000;
        double salary2 = 13000;
        double salary3 = 15888;
        double salary4 = 12000;
        double salary5 = 11888;
        double salary6 = 15888;
        double salary7 = 10000;
        double salary8 = 13000;
        double salary9 = 12000;
        double salary10 = 11888;
        // 计算总薪资
        double sum = salary1 + salary2 + salary3 + salary4 + salary5 + salary6 + salary7 + salary8 + salary9 + salary10;
        // 计算平均薪资
        double avg = sum / 10;
        System.out.println("总薪资:" + sum);
        System.out.println("平均薪资:" + avg);

    }
}


但是我们可以发现,一些不好的现象:

  1. 变量定义太多,若是计算100个人的薪资,那岂不是要定义100个变量,那1000个人、10000个人更不用说了。
  2. 连续累加,计算重复。

以上这些不好的问题,根本的原因,就是变量定义太多,一个具体的薪资数据对应一个变量,导致操作复杂且臃肿。

如何解决以上的问题呢?我们当然要从根本上解决,想办法实现,让一个变量管理一组数据。

此时,我们就需要学习数组。

1.2-什么是数组 (理解)

一个固定长度的数据容器,可以有序地存放同类型的数据

  • 固定长度,存放数据的个数。
  • 有序,容器中的每一个数据都有一个索引(编号),从左向右,索引从0开始。
  • 同类型的数据,容器中的存放的数据类型要一致。

1.3-数组的定义格式(记忆)

格式1:

数据类型[] 数组名

double[]salay;
int[]age;
char[]arr;

格式2:

数据类型 数组名[]

double salay[];
int age[];
char arr[];

以上仅仅是定义了数组的名称,但是未赋值。

1.4-数组的动态初始化(记忆)

什么是动态初始化

数组动态初始化就是只给定数组的长度,由系统给出默认初始化值

  • double类型数组,默认值0.0
  • int类型数组,默认值是0
  • boolean类型数组,默认值是false
  • char类型数组,默认值是0.0
  • 对象类型数组,默认值是null

动态初始化格式:

数据类型[] 数组名 = new 数据类型[数组长度];

数据类型 数组名[] = new 数据类型[数组长度];

double[]salary = new double[10];

=左边:

  • double,表示数组的类型
  • [],表示是一个数组
  • salary,表示数组的名称(变量名)

=右边:

  • new,为数组开辟内存空间

  • double,表示数组的类型

  • [],表示是一个数组

  • 10,表示数组的长度

1.5-访问数组元素(记忆)

访问数组元素(数组中的数据),就是获取数组中的某一个位置的数据。

索引

每一个存储到数组的元素,都会自动的拥有一个编号,从0开始,向后逐一加1。

这个自动编号称为数组索引(index),可以通过数组的索引访问到数组中的元素。

访问数组元素格式

数组名[索引]

package com.penglei666.com;

public class Test02 {
    public static void main(String[] args) {
        double[]salary = new double[10];
        // 输出数组,输出结果:[D@b684286
        System.out.println(salary);
        // 输出数组中索引为0的元素,double数组中数据默认值是0.0
        System.out.println(salary[0]);
        System.out.println(salary[0]);
        System.out.println(salary[0]);
    }
}

1.6-内存分配 (理解)

内存

  • 内存是计算机中的重要原件,临时存储区域,作用是运行程序。

  • 我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的。

  • 必须放进内存中才能运行,运行完毕后会清空内存。

  • Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。

Java中的内存分配

目前我们只需要记住两个内存,分别是:栈内存堆内存

数组在内存中的分配过程

public static void main(String[] args) {
    double[]salary = new double[10];
    // 输出数组,输出结果:[D@b684286
    System.out.println(salary);
    // 输出数组中索引为0的元素,double数组中数据默认值是0.0
    System.out.println(salary[0]);
    System.out.println(salary[1]);
    System.out.println(salary[2]);
}

执行过程:

  • ① 程序运行时,首先main方法,入栈执行。

  • ② main方法执行时,发现new关键字创建数组,则会在堆内存中,为数组开辟连续的空间,并设置默认值。

  • ③ 数组开辟空间后,返回内存地址给数组名称,输出数组名称,则输出了内存地址。

  • ④ salary[0]表示,通过数组内存地址,找到内存堆区中数组空间中的索引为0的数据。

  • ⑤ salary[1]表示,通过数组内存地址,找到内存堆区中数组空间中的索引为1的数据。

  • ⑥ salary[2]表示,通过数组内存地址,找到内存堆区中数组空间中的索引为2的数据。

1.7-基本类型和引用类型的区别(理解)

基本数据类型和引用数据类型

基本数据类型,之前学习的数据类型,如:int、long、double、boolean等。

引用数据类型,现在学习的数组就是引用数据类型

区别1:程序运行时,在内存中创建数据时,内存分配不同

  • 基本数据类型:
    • 会在栈内存开辟一块空间存放数据。
  • 引用数据类型:
    • 会在堆内存开辟一块空间存放数据具体信息。
    • 同时也会在栈内存开辟一块空间存放堆数据的引用(堆区的地址)

区别2:数据传递过程不同

  • 基本数据类型是值传递(数据在栈中会克隆一份新的,两个数据互不影响)。
  • 引用数据类型是引用传递(数据的引用在栈中会克隆一份新的,但两个引用指向堆区中的同一个具体数据)
package com.penglei666.com;

public class Test02 {
    public static void main(String[] args) {
        /*【基本数类型值传递】*/
        // 创建变量a,赋值为10
        int a = 10;
        // 把变量a,赋值给变量b
        int b = a;
        // 更改变量b的值
        b = 20;
        // 变量b发生改变,结果:20
        System.out.println(b);
        // 变量a没有发生改变,结果:10
        System.out.println(a);

        /*【引用类型引用传递】*/
        // 创建数组arr1
        int[]arr1 = new int[2];
        // 创建数组arr2,并把arr1赋值给arr2
        int[]arr2 = arr1;
        // 输出arr1索引为0的值,结果为0
        System.out.println(arr1[0]);
        // 输出arr2索引为0的值,结果为0
        System.out.println(arr2[0]);
        // 更改arr1索引为0的值
        arr1[0] = 99;
        // 输出arr1索引为0的值,结果为99
        System.out.println(arr1[0]);
        // 输出arr2索引为0的值,结果为99
        System.out.println(arr2[0]);

    }
}

基本数据类型数据传递过程

引用数据类型数据传递过程

1.8-数组静态初始化(记忆)

什么是静态初始化

在创建数组时,直接将元素确定

静态初始化格式:

  • 完整版格式:数据类型[] 数组名 = new 数据类型[]{元素1,元素2,...};
  • 简化版格式:数据类型[] 数组名 = {元素1,元素2,...};
public class ArrayDemo {
    public static void main(String[] args) {
        //定义数组
        int[] arr = {1, 2, 3};

        //输出数组名
        System.out.println(arr);

        //输出数组中的元素
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
    }
}

1.9-数组中常见的问题(了解)

问题1:索引越界异常

public class ArrayDemo {
    public static void main(String[] args) {
        int[] arr = new int[3];
        System.out.println(arr[3]);  // 异常
    }
}

数组长度为3,索引范围是0~2,但是我们却访问了一个3的索引。

程序运行后,将会抛出ArrayIndexOutOfBoundsException 数组越界异常。在开发中,数组的越界异常是不能出现的,一旦出现了,就必须要修改我们编写的代码。

解决方式:将错误的索引修改为正确的索引范围即可!

问题2:空指针异常

public class ArrayDemo {
    public static void main(String[] args) {
        int[] arr = new int[3];

        //把null赋值给数组,变量将不会执行任何有效对象。
        arr = null;
        System.out.println(arr[0]);
    }
}

arr = null 这行代码,意味着变量arr将不会在保存数组的内存地址,也就不允许再操作数组了,因此运行的时候会抛出 NullPointerException 空指针异常。

解决方式:给数组一个真正的堆内存空间引用即可!

1.10-数组遍历(重点)

数组遍历:就是将数组中的每个元素分别获取出来,就是遍历。遍历也是数组操作中的基石。

public class ArrayTest01 {
	public static void main(String[] args) {
		int[] arr = { 1, 2, 3, 4, 5 };
		System.out.println(arr[0]);
		System.out.println(arr[1]);
		System.out.println(arr[2]);
		System.out.println(arr[3]);
		System.out.println(arr[4]);
	}
}

以上代码是可以将数组中每个元素全部遍历出来,但是如果数组元素非常多,这种写法肯定不行,因此我们需要改造成循环的写法。数组的索引是 0 到 length-1 ,可以作为循环的条件出现。

  • 获取数组的长度:数组名.length
public class ArrayTest01 {
    public static void main(String[] args) {
        //定义数组
        int[] arr = {11, 22, 33, 44, 55};

        //使用通用的遍历格式
        for(int x=0; x<arr.length; x++) {
            System.out.println(arr[x]);
        }
    }
}

1.12-数组应用(重点)

需求:统计10个人的薪资,计算总薪资、平均薪资和最大薪资。

package com.penglei666.com;

public class Test03 {
    public static void main(String[] args) {
        // 创建数组,并静态初始化10个人的薪资
        double[]salary={12000,10000,13000,15000,14000,18000,10000,13000,15000,14000};
        // 创建变量sum,表示总薪资,初始化为0
        double sum = 0;
        // 创建变量avg,表示平均薪资,初始化为0
        double avg = 0;
        // 创建变量maxValue,表示最高薪资,初始化数组索引0为最大值,最终谁是最大值,需要比较
        double maxValue = salary[0];
        // 循环遍历每一个人的薪资
        for(int i = 0; i < salary.length; i++) {
            // 取出每一个人的薪资,累计到变量sum中
            sum+=salary[i];
            // 从索引1开始,和maxValue比较,比maxValue值大,就把谁赋值给maxValue
            if(i>0) {
                if(salary[i]>maxValue) {
                    maxValue = salary[i];
                }
            }
        }
        // 计算平均薪资
        avg = sum / salary.length-1;
        // 输出总薪资
        System.out.println("薪资总和:" + sum);
        System.out.println("平均薪资:" + avg);
        System.out.println("最大薪资:" + maxValue);
    }
}

第二章:方法

2.1-为什么要学习方法(理解)

需求

一个简单的需求:有三个数组如下:

int[]arrA = {22,11,44,33};
int[]arrB = {1,4,5,2,3};
int[]arrC = {20,33,29,18};

分别计算并输出数组中最大值。

分析

按照现学的知识,我们可能会这么做:

  • 计算数组arrA中的最大值
    1. 定义一个变量如:maxA,表示最大值,初始化为arrA[0]
    2. 循环遍历数组arrA,取出每一个值与maxA比较,若遍历的元素大于maxA,则把当前元素赋值给maxA
    3. 遍历结束后,maxA的值就代表最大值。
  • 计算数组arrB中的最大值
    1. 思路同上
  • 计算数组arrC中的最大值
    1. 思路同上
package com.penglei666.com;

public class Test04 {
    public static void main(String[] args) {
        /*定义三个数组*/
        int[]arrA = {22,11,44,33};
        int[]arrB = {1,4,5,2,3};
        int[]arrC = {20,33,29,18};
        /*求数组arrA中的最大值*/
        int maxA = arrA[0];
        for(int i = 1; i < arrA.length; i++){
            if(arrA[i]>maxA) {
                maxA = arrA[i];
            }
        }
        System.out.println("最大值:" + maxA);
        /*求数组arrB中的最大值*/
        int maxB = arrB[0];
        for(int i = 1; i < arrB.length; i++){
            if(arrB[i]>maxB) {
                maxB = arrB[i];
            }
        }
        System.out.println("最大值:" + maxB);
        /*求数组arrC中的最大值*/
        int maxC = arrC[0];
        for(int i = 1; i < arrC.length; i++){
            if(arrC[i]>maxC) {
                maxC = arrC[i];
            }
        }
        System.out.println("最大值:" + maxC);
    }
}

问题及解决方案

以上解决方案确实可以实现功能。但是存在这样的问题:

  • 代码重复

此处的重复,是逻辑重复,若有更多的数组需要计算,岂不是要写更多一样的逻辑代码,这样代码会越来越臃肿且难以维护,若需求更变,要求最小值,岂不是要逐一修改。

那如何去解决呢?以上是逻辑重复,变化的仅仅是数组,所以我们想办法这样解决问题:

  1. 把逻辑封装一个模板。
  2. 向这个模板中传入一个数组,就会得到一个最大值的结果,传入一个数组,就会得到一个最大值的结果。

这个模板只需要定义一次,在需要的时候调用这个模板即可。

在编程中,确实提供了这样的语法来实现把逻辑封装成一个模块,这个语法机制就是方法

2.2-什么是方法 (了解)

方法,在编程中也叫函数,也表示功能。

方法,可以将一段代码封装在一个代码块中,代表一个功能

注意:

  • 方法必须先创建才可以使用,该过程成为方法定义
  • 方法创建后并不是直接可以运行的,需要手动使用后,才执行,该过程成为方法调用

2.3-无参数方法定义和调用(记忆)

定义格式

public static void 方法名 (   ) {
	// 方法体;
}

示例如下:

public class Test05 {
    public static void main(String[] args) {
        
    }

    /**
     * 定义一个求数组中最大值的方法
     */
    public static void getMax(){
        int[]arr = {22,11,44,33};
        int max = arr[0];
        for(int i = 1; i < arr.length; i++){
            if(arr[i]>max) {
                max = arr[i];
            }
        }
        System.out.println(max);
    }
}

注意:方法定义不能嵌套,比如:不能再main方法中定义getMax。

调用方法

调用格式:方法名()

示例如下:

public class Test05 {
    public static void main(String[] args) {
        // 调用getMax方法
        getMax();
    }

    /**
     * 定义一个求数组中最大值的方法
     */
    public static void getMax(){
        int[]arr = {22,11,44,33};
        int max = arr[0];
        for(int i = 1; i < arr.length; i++){
            if(arr[i]>max) {
                max = arr[i];
            }
        }
        System.out.println(max);
    }
}

为什么在main方法中调用,因为main方法是程序执行的入口。

每个方法在被调用执行的时候,都会进入栈内存,并且拥有自己独立的内存空间,方法内部代码调用完毕之后,会从栈内存中弹栈消失。

2.4-带参数方法定义和调用(记忆)

定义格式

参数:由数据类型和变量名组成 , 数据类型 变量名

方法定义时,参数中的数据类型与变量名都不能缺少,缺少任意一个程序将报错,多个参数之间用,分割

public static void 方法名 (参数1) {
	方法体;
}

public static void 方法名 (参数1, 参数2, 参数3...) {
	方法体;
}

示例:

public static void isEvenNumber(int number){
    ...
}
public static void getMax(int num1, int num2){
    ...
}

案例改进:

public class Test05 {
    public static void main(String[] args) {

    }

    /**
     * 求一个数组中的最大值
     * @param arr 表示一个数组
     */
    public static void getMax(int[]arr){
        int max = arr[0];
        for(int i = 1; i < arr.length; i++){
            if(arr[i]>max) {
                max = arr[i];
            }
        }
        System.out.println(max);
    }
}

调用

方法名(参数);

方法名(参数1,参数2);

方法调用时,要传入实际的数据。

public class Test05 {
    public static void main(String[] args) {
        /*定义三个数组*/
        int[]arrA = {22,11,44,33};
        int[]arrB = {1,4,5,2,3};
        int[]arrC = {20,33,29,18};
        /*求数组arrA中的最大值*/
        getMax(arrA);
        /*求数组arrB中的最大值*/
        getMax(arrB);
        /*求数组arrC中的最大值*/
        getMax(arrC);
    }

    /**
     * 求一个数组中的最大值
     * @param arr 表示一个数组
     */
    public static void getMax(int[]arr){
        int max = arr[0];
        for(int i = 1; i < arr.length; i++){
            if(arr[i]>max) {
                max = arr[i];
            }
        }
        System.out.println(max);
    }
}

方法调用时,参数的数量与类型必须与方法定义中的设置相匹配,否则程序将报错 。

2.5-形参和实参 (理解)

形参:在定义方法时,小括号中定义的变量。

实参:在方法调用时,小括号中传入的实际的数据。

2.6-带返回值方法的定义和调用(记忆)

需求:计算三个数组中三个最大值的和。

此时,我们需要调用完方法后,得到结果,这个结果不是输出,而是用来和其他最大值相加。

如何得到结果呢?

可以使用方法返回值,就是一个方法调用完毕后,可以通过一个变量接收方法的返回值。

带返回值的方法定义:

public static 数据类型 方法名 ( 参数 ) { 
	return 数据 ;
}

方法定义时return后面的返回值与方法定义上的数据类型要匹配,否则程序将报错。

范例:

// 检测一个数字是否是偶数
public static boolean isEvenNumber( int number ) {           
	boolean isEven = number%2==0;
	return isEven;
}
// 求两个不同数字的最大值
public static int getMax( int a, int b ) {
	if(a>b) {
		return a;
	}else {
		return b;
	}
}

调用

调用方式:返回值类型 变量名 = 方法名(实参)

示例:

public class Test06 {
    public static void main(String[] args) {
        // 检测8是否是偶数
        boolean isEven = isEvenNumber(8);
        System.out.println(isEven);  // isEven是true
        // 求10和100哪个数字比较大
        int max = getMax(10,100);
        System.out.println(max);     // max是100
    }

    /**
     * 检测要给数字是否是偶数
     * @param number ,传入一个数字
     * @return 返回布尔值,true表示是偶数,false表示不是偶数
     */
    public static boolean isEvenNumber( int number ) {
        boolean isEven = number%2==0;
        return isEven;
    }

    /**
     * 求两个数字中的最大值
     * @param a 一个数字
     * @param b 另一个数字
     * @return  返回较大的int类型数字
     */
    public static int getMax( int a, int b ) {
        if(a>b) {
            return a;
        }else {
            return b;
        }
    }
}

案例代码:

public class Test05 {
    public static void main(String[] args) {
        /*定义三个数组*/
        int[]arrA = {22,11,44,33};
        int[]arrB = {1,4,5,2,3};
        int[]arrC = {20,33,29,18};
        /*求数组arrA中的最大值*/
        int maxA = getMax(arrA);
        /*求数组arrB中的最大值*/
        int maxB =getMax(arrB);
        /*求数组arrC中的最大值*/
        int maxC = getMax(arrC);
        // 求最大值的和
        System.out.println(maxA + maxB + maxC);  // 82
    }

    /**
     * 求一个数组中的最大值
     * @param arr 表示一个数组
     * @return 返回一个int类型的数字,表示最大值
     */
    public static int getMax(int[]arr){
        int max = arr[0];
        for(int i = 1; i < arr.length; i++){
            if(arr[i]>max) {
                max = arr[i];
            }
        }
        return max;
    }
}

2.7-方法注意事项(了解)

① 方法不能嵌套定义

public class MethodDemo {
    public static void main(String[] args) {

    }

    public static void methodOne() {
		public static void methodTwo() {
       		// 这里会引发编译错误!!!
    	}
    }
}

② void表示无返回值,可以省略return,也可以单独的书写return,后面不加数据

public class MethodDemo {
    public static void main(String[] args) {

    }
    public static void methodTwo() {
        //return 100; 编译错误,因为没有具体返回值类型
        return;	
        //System.out.println(100); return语句后面不能跟数据或代码
    }
}

2.8-方法通用格式(记忆)

通用格式

public static 返回值类型 方法名(参数) {
   方法体; 
   return 数据 ;
}
  • public static ,修饰符,目前先记住这个格式

  • 返回值类型,方法操作完毕之后返回的数据的数据类型,如果方法操作完毕,没有数据返回,这里写void,而且方法体中一般不写return

  • 方法名,调用方法时候使用的标识,定义规则和变量名一样。

  • 参数,由数据类型和变量名组成,多个参数之间用逗号隔开。

  • 方法体,完成功能的代码块

  • return,如果方法操作完毕,有数据返回,用于把数据返回给调用者

如何定义方法

  • 明确返回值类型:主要是明确方法操作完毕之后是否有数据返回,如果没有,写void;如果有,写对应的数据类型。
  • 明确参数:主要是明确参数的类型和数量

如何调用方法

void类型的方法,直接调用即可。

非void类型的方法,推荐用变量接收调用。

2.9-方法的重载(理解)

在Java程序中,可以定义的多个·重名参数列表不同(参数的个数或类型不同)的方法。这种现象叫做方法的重载。

public static void fn(int num1,int num2){
     System.out.print(num1 + num2);                        
}
// 定义有参有返回值方法
public static int fn(int num1,int num2,int num3){
  return num1 + num2 + num3;                        
}

注意:方法的重载与方法的返回值没有关系

错误示例:以下不是方法重载,与返回值没有关系。

public static int fn(int num1,int num2){
	
}
public static void fn(int num1,int num2){
	
}

第三章:IDEA 安装下载教程

链接:https://pan.baidu.com/s/1fuZucWizXdLLfhBNu97Bbg
提取码:bfbc

原文地址:https://www.cnblogs.com/lpl666/p/13336874.html