本篇我们将会学习Java基础语法之数组和方法。数组,是一种基础的数据结构,数组可以让我们通过一个变量管理一组数据;方法可以将一个功能封装,在需要这个功能的地方,只需要调用方法即可,而不用再重复编写冗余的代码。接下来,我们将会详细讲解Java中的数组、方法。
需求:统计10个人每个人的薪资,并计算出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:
double[]salay; int[]age; char[]arr;
格式2:
double salay[]; int age[]; char arr[];
以上仅仅是定义了数组的名称,但是未赋值。
什么是动态初始化
数组动态初始化就是 只给定数组的长度 ,由 系统给出默认初始化值
动态初始化格式:
double[]salary = new double[10];
=
左边:
=
右边:
访问数组元素(数组中的数据),就是获取数组中的某一个位置的数据。
索引
每一个存储到数组的元素,都会自动的拥有一个编号,从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]); } }
内存
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]); }
执行过程:
基本数据类型和引用数据类型
基本数据类型,之前学习的数据类型,如: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]); } }
基本数据类型数据传递过程
引用数据类型数据传递过程
什么是静态初始化
在创建数组时,直接将元素确定
静态初始化格式:
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:索引越界异常
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 空指针异常。
解决方式:给数组一个真正的堆内存空间引用即可!
数组遍历:就是将数组中的每个元素分别获取出来,就是遍历。遍历也是数组操作中的基石。
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 ,可以作为循环的条件出现。
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]); } } }
需求:统计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); } }
需求
一个简单的需求:有三个数组如下:
int[]arrA = {22,11,44,33}; int[]arrB = {1,4,5,2,3}; int[]arrC = {20,33,29,18};
分别计算并输出数组中最大值。
分析
按照现学的知识,我们可能会这么做:
计算数组arrA中的最大值
计算数组arrB中的最大值
计算数组arrC中的最大值
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); } }
问题及解决方案
以上解决方案确实可以实现功能。但是存在这样的问题:
此处的重复,是逻辑重复,若有更多的数组需要计算,岂不是要写更多一样的逻辑代码,这样代码会越来越臃肿且难以维护,若需求更变,要求最小值,岂不是要逐一修改。
那如何去解决呢?以上是逻辑重复,变化的仅仅是数组,所以我们想办法这样解决问题:
这个模板只需要定义一次,在需要的时候调用这个模板即可。
在编程中,确实提供了这样的语法来实现把逻辑封装成一个模块,这个语法机制就是 方法
方法,在编程中也叫函数,也表示功能。
注意:
定义格式
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方法是程序执行的入口。
每个方法在被调用执行的时候,都会进入栈内存,并且拥有自己独立的内存空间,方法内部代码调用完毕之后,会从栈内存中弹栈消失。
定义格式
参数:由数据类型和变量名组成 , 数据类型 变量名
方法定义时,参数中的数据类型与变量名都不能缺少,缺少任意一个程序将报错,多个参数之间用 ,
分割
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); } }
方法调用时,参数的数量与类型必须与方法定义中的设置相匹配,否则程序将报错 。
形参:在定义方法时,小括号中定义的变量。
实参:在方法调用时,小括号中传入的实际的数据。
需求:计算三个数组中三个最大值的和。
此时,我们需要调用完方法后,得到结果,这个结果不是输出,而是用来和其他最大值相加。
如何得到结果呢?
可以使用方法返回值,就是一个方法调用完毕后,可以通过一个变量接收方法的返回值。
带返回值的方法定义:
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; } }
① 方法不能嵌套定义
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语句后面不能跟数据或代码 } }
通用格式
public static 返回值类型 方法名(参数) { 方法体; return 数据 ; }
如何定义方法
如何调用方法
void类型的方法,直接调用即可。
非void类型的方法,推荐用变量接收调用。
在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){ }
链接: https://pan.baidu.com/s/1fuZu...
提取码:bfbc