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

以上是 JavaSE第05篇:Java基础语法之数组、方法 的全部内容, 来源链接: utcz.com/z/518454.html

回到顶部