Java基础|1-01-Java基础语法(详细) @Java

写在前面:
此文是笔者在学习Java系列课程的过程中,参考相关课件、视频讲解、课程代码,并结合一些文档、思维导图及个人理解,对所学内容做的阶段性梳理与总结。

  • 写于:2021年1月17日~24日
  • 内容:Java后端系列笔记001(Java基础)
  • 全文:15619字;读完需要:20分钟


一、开发前言

1. 1 Java语言概述 [ 导图 ]

1. 2 计算机基础知识

二进制

  • 存储:数据在计算机中是以 二进制形式 存储的
  • 特点:“逢二进一”、“只含0和1”
  • 转换:
    • 十进制整数转成二进制整数:使用 除2取余-逆序排列 的方式
    • 二进制数据转成十进制数据:使用 8421编码 的方式(按权相加法)

tips:二进制数系统中,每个0或1就是一个位,叫做bit(比特)

问:什么是 8421编码 ?
答:8421码又称为BCD码,是十进制代码中最常用的一种,每一位二值代码的“1”都代表一个固定数值2^(n-1) [右→左] 。
将每位“1”所代表的二进制数加起来,就可以得到它所代表的十进制数字。因为代码中从左至右看每一位“1”分别代表数字“8”“4”“2”“1”,故得名8421码。

字节

  • 位(bit):二进制数据;一个数字0或一个数字1,代表一位
  • 字节(Byte):是我们常见的计算机中最小存储单元
    • 1 Byte = 8 bit (每逢8位是一个字节)
    • 1 KB = 1024 Byte
    • 1 MB = 1024 KB
    • 1 GB = 1024 MB
    • 1 TB = 1024 GB
    • 1 PB = 1024 TB
    • 1 EB = 1024 PB
    • 1 ZB = 1024 EB

tips:在计算机数据存储中,存储数据的最小单位 → 位(bit),基本单位 → 字节(Byte 简称B)

常用DOS命令

  • DOS:磁盘操作系统(Disk Operating System)
  • 进入DOS操作窗口:
    Windows+R → 打开运行窗口 → 输入cmd(命令提示符)回车 → 进入DOS的操作窗口
  • 常用命令
命令 操作符号
盘符切换 盘符名:
进入文件夹 cd 文件夹名
进入多级文件夹 cd 文件夹1\文件夹2\文件夹3
退出文件夹 cd …
直接回根路径 cd \
查看当前内容 dir
清屏 cls
退出 exit

二、Java语言开发环境

2. 1 JVM、JRE、JDK

概念:

  • JVM(Java Virtual Machine )
    • Java虚拟机,是运行所有Java程序的假想计算机
    • 是实现Java语言跨平台性的关键
  • JRE (Java Runtime Environment)
    • Java程序的运行环境
    • 包含:JVM + 运行时所需的核心类库
  • JDK (Java Development Kit)
    • Java程序开发工具包
    • 包含:JRE + 开发工具

关系:JDK > JRE > JVM

说明:

  • 运行一个已有的Java程序 —— 只需安装JRE
  • 开发一个全新的Java程序 —— 必须安装JDK

tips:
Java语言 具有跨平台性:同一段程序可运行在不同操作系统上
但 Java的虚拟机-JVM:本身不具有跨平台功能(每个操作系统配有不同版本的虚拟机)

2. 2 配置Java环境变量

目的:

  • 方便开发 —— 在任意的目录下都可以使用JDK的开发工具

意义:

  • 告诉操作系统 —— 使用的JDK开发工具所在的目录

步骤:

  • 计算机/此电脑 → 右键选属性 → 高级系统设置 → 高级-环境变量 → 新建系统变量
    • JAVA_HOME:jdk的安装目录
    • Path: %JAVA_HOME%\bin;

  • 配置完成后:打开cmd(DOS命令行),任意目录输入 javac,可看到内容

三、HelloWorld入门程序

3. 1 程序开发步骤

Java程序开发三步骤:编写、编译、运行

  • 编写Java源程序
    • 记事本中写入代码 → 保存 → 命名为 HelloWorld.java
    • 文件命名:和类的名字一致 HelloWorld,后缀 .java
    • .java文件:JVM看不懂,不能运行,需对文件进行编译 → JVM看得懂的 .class文件(字节码文件)
public class HelloWorld {
   
	public static void main(String[] args) {
   
		System.out.println("Hello, World!");  // 输出 Hello, World!
	}
}
  • 编译Java源文件
    • 命令:javac Java源文件名.后缀名,如:javac HelloWorld.java
    • .class文件:编译后会在目录下会产生一个HelloWorld.class的新文件(字节码文件)
    • 若遇到编码问题,我们可在cmd中使用 -encoding 选项设置 utf-8 来编译
javac -encoding UTF-8 HelloWorld.java 
java HelloWorld 
  • 运行Java程序
    • 命令:java 类名字,如:java HelloWorld
    • 注意:运行Java程序时,不要写 .class

tips:

  1. 程序的文件名:需和类的名字一致,注意大小写,每个字母和符号必须与示例代码一模一样。eg:HelloWorld
  2. 工具:(1).java文件的编译工具:javac.exe [ 编译器 ] (2).class文件的运行工具:java.exe [ 解释器 ]

3. 2 入门程序说明

编译和运行是两个不同概念

  1. 编译:将编写的Java源文件翻译成JVM认识的class文件(此过程中,编译器会检查所写程序是否错误——若有错误则会有提示,否则编译成功)
  2. 运行:将class文件通过解释器交给JVM运行(此时JVM就会去执行我们编写的程序)

3. 3 注释、关键字、标识符 [ 导图 ]


四、常量与变量

4. 1 常量

  • 概念:在程序运行期间,固定不变的量
  • 分类
类型 含义 举例
整数常量 所有的整数 4、200、0、-250
小数常量 所有的小数 0.0、 -0.1、2.55
字符常量 单引号引起来,只能写一个字符,必须有内容 ‘A’、‘b’、‘9’、‘中’
字符串常量 双引号引起来,可写多个字符,也可不写 “A” 、“Hello” 、“你好” 、""
布尔常量 只有两个取值 true 、false
空常量 只有一个取值,代表没有任何数据 null
  • 注意
    • 字符常量:两个单引号中间必须有且仅有一个字符
    • 空常量:不能直接用来打印输出
public class Demo01Const {
   
	public static void main(String[] args) {
   
		// 字符串常量
		System.out.println(""); // 字符串两个双引号中间的内容为空 √
		
		// 字符常量 —— 两个单引号中间必须有且仅有一个字符
		System.out.println('A');// √
		//System.out.println(''); // 没有字符不行 ×
		//System.out.println('AB'); // 有两个字符不行 ×
		
		// 空常量 —— 空常量不能直接用来打印输出 
		//System.out.println(null); // ×
	}

4. 2 数据类型与变量

数据类型

  • Java的数据类型分为两大类
    • 基本数据类型:整数、浮点数、字符、布尔
    • 引用数据类型:类、数组、接口
  • 基本数据类型(四类八种)
数据类型 关键字 内存占用 取值范围
字节型 byte 1个字节 -128~127
短整型 short 2个字节 -32768~32767
整型 int(默认) 4个字节 -231次方~2的31次方-1
长整型 long 8个字节 -2的63次方~2的63次方-1
单精度浮点数 float 4个字节 1.4013E-45~3.4028E+38
双精度浮点数 double(默认) 8个字节 4.9E-324~1.7977E+308
字符型 char 2个字节 0-65535
布尔类型 boolean 1个字节 true、false

变量

  • 概念:程序运行期间,内容可以发生改变的量
  • 变量定义的格式
    • 三要素: 数据类型变量名数据值
    • 创建一个变量并且使用的格式:
1. 格式1_先创建后赋值
数据类型 变量名称; // 创建了一个变量
变量名称 = 数据值; // 赋值,将右边的数据值,赋值交给左边的变量
eg: int num1; num1 = 10;

2. 格式2_一步到位
数据类型 变量名称 = 数据值; // 在创建一个变量的同时,立刻放入指定的数据值
eg: int num2 = 10;
  • 注意事项
    • 变量名称:若创建多个变量,则变量间的名称不可重复
    • 取值范围:若使用byte或short类型的变量,则右侧的数据值不能超过左侧类型的范围
    • 变量赋值: 定义的变量,不赋值不能使用
    • 作用范围:变量使用不能超过 作用域 的范围
      • 【作用域】- 从定义变量的一行开始,一直到直接所属的大括号结束为止
    • 创建变量:可通过一个语句来创建多个变量,但一般情况不推荐这么写
public class VariableNotice {
   
	public static void main(String[] args) {
   
		int num1 = 10; // 创建了一个新的变量,名叫num1
		// int num1 = 20; // [1] 又创建了另一个新的变量,名字也叫num1,错误!
		
		byte num2 = 30; // 注意:右侧数值的范围不能超过左侧数据类型的取值范围
		System.out.println(num2); // 30
		
		// byte num3 = 400; // [2] 右侧超出了byte数据范围,错误!
		
		int num4; // 定义了一个变量,但是没有进行赋值
		// System.out.println(num4); // [3]直接使用打印输出就是错误的!
		
		// System.out.println(num5); // 在创建变量之前,不能使用这个变量
		
		int num5 = 500;
		System.out.println(num5); // 500
		
		{
   
			int num6 = 60;
			System.out.println(num6); // 60
		}
		// int num6;
		// System.out.println(num6); //[4] 已经超出了大括号的范围,超出了作用域,变量不能再使用了
		
		//[5] 同时创建了三个全都是int类型的变量
		int a, b, c;
		// 各自分别赋值
		a = 10;
		b = 20;
		c = 30;
		System.out.println(a); // 10
		System.out.println(b); // 20
		System.out.println(c); // 30
		
		//[5] 同时创建三个int变量,并且同时各自赋值
		int x = 100, y = 200, z = 300;
		System.out.println(x); // 100
		System.out.println(y); // 200
		System.out.println(z); // 300
	}
}

tips:

  1. Java中的默认类型:整数类型是 int 、浮点类型是 double
  2. 变量的定义:long类型 — 数据后加L表示、float类型 — 数据后加F表示(字母后缀F和L不要丢掉)

五、数据类型转换

当数据类型不一样时,将会发生数据类型转换

5. 1 自动转换-隐式

  • 概念:将取值范围小的类型 自动提升为 取值范围大的类型
  • 特点:代码不需要进行特殊处理,自动完成
  • 规则:数据范围从小到大(byte、short、char‐‐>int‐‐>long‐‐>float‐‐>double
public static void main(String[] args) {
   
	int i = 1;
	byte b = 2;
	// byte x = b + i; // 报错
	//int类型和byte类型运算,结果是int类型
	int j = b + i;
	System.out.println(j); //3
	
	/* 左边是long类型,右边是默认的int类型,左右不一样 一个等号代表赋值,将右侧的int常量,交给左侧的long变量进行存储 int --> long,符合了数据范围从小到大的要求(自动类型转换) */
	long num1 = 100;
	System.out.println(num1); // 100
}

5. 2 强制转换-显式

  • 概念:将取值范围大的类型 强制转换为 取值范围小的类型
  • 特点:代码需要进行特殊的格式处理,不能自动完成
  • 格式:范围小的类型 变量名 = (范围小的类型) 原本范围大的数据;
int i =  1. 5 ; // 错误(将 double类型数据 赋值到 int类型变量,会产生编译失败,所以无法赋值)

int i = (int)1.5;//编译成功(double类型数据 强制转成 int类型,直接去掉小数点)
  • 注意:强制类型转换一般不推荐使用,因为有可能发生精度损失数据溢出
public static void main(String[] args) {
   
	//1. double --> int,强制类型转换
	int num1 = (int) 3.99;
	System.out.println(num1); // 3,这并不是四舍五入,所有的小数位都会被舍弃掉(精度损失)
	
	//2. long强制转换成为int类型
	int num2 = (int) 6000000000L;
	System.out.println(num2); // 1705032704(发生数据溢出,即:数据丢失)
	
	//3. 定义num3为short范围内最大值
	short num3 = 32767;
	// short + int --> int + int --> int --> short 
	// 运算后,4字节int强制转换为2字节short,砍掉2个字节后会出现不确定的结果(数据丢失)
	num3 = (short)(num3 + 10);
}

tips:

  1. byte/short/char这三种类型:
    (1)都可以发生数***算,例如 加法“+”;(2)在运算的时候,都会被首先提升成为int类型,然后再计算
  2. boolean类型:不能发生数据类型转换

5. 3 ASCII编码表

  • 数字和字符的对照关系表(编码表)
    • ASCII码表:美国信息交换标准代码(American Standard Code for Information Interchange)
    • Unicode码表:万国码(开头0-127部分和ASCII完全一样,但是从128开始包含有更多字符 )
public static void main(String[] args) {
   
	char c1 = '1';
	// char字符类型和int类型计算
	// char类型的字符先查询编码表,得到49,再与1求和,结果为50
	System.out.println(c1 + 1); // 50
	
	char c2 = 'A'; // 其实底层保存的是65数字
	
	char c3 = 'c';
	// 左侧是int类型,右边是char类型,
	// char --> int,范围从小到大(自动类型转换)
	int num = c3;
	System.out.println(num); // 99
	
	char c4 = '中'; // 正确写法 (Unicode码)
	System.out.println(c4 + 0); // 20013
}
  • 常见ASCII
字符 数值
0 48
9 57
A 65
Z 90
a 97
z 122

六、运算符 [ 导图 ]

思维导图

代码分析

  • 自增运算符 ++、自减运算符 --
public static void main(String[] args) {
   

	//1. 与打印操作混合的时候
	int num1 = 20;
	// 混合使用,先++(先加后用),变量立刻马上变成21,然后打印结果21
	System.out.println(++num1); // 21
	System.out.println(num1); // 21
	
	int num2 = 30;
	// 混合使用,后++(先用后加),首先使用变量本来的30,然后再让变量+1得到31
	System.out.println(num2++); // 30
	System.out.println(num2); // 31
	System.out.println("=================");
	
	//2. 和赋值操作混合
	int num3 = 40;
	int result1 = --num3; // 混合使用,前--,变量立刻马上-1变成39,然后将结果39交给result1变量
	System.out.println(result1); // 39
	System.out.println(num3); // 39
	
	int num4 = 50;
	int result2 = num4--;// 混合使用,后--,首先把本来的数字50交给result2,然后我自己再-1变成49
	System.out.println(result2); // 50
	System.out.println(num4); // 49
	System.out.println("=================");
	
	//3. 综合
	int x = 10;
	int y = 20;
	int result3 = ++x + y--;// 11 + 20 = 31
	System.out.println(result3); // 31
	System.out.println(x); // 11
	System.out.println(y); // 19
	
	// 30++; // 错误写法!常量不可以使用++或者--
}
  • 三元运算符 数据类型 变量名称 = 条件判断 ? 表达式A : 表达式B;
public static void main(String[] args) {
   
	int a = 10;
	int b = 20;
	
	// 判断a > b是否成立,如果成立将a的值赋值给max;如果不成立将b的值赋值给max。二者选其一
	int max = a > b ? a : b; // 最大值的变量
	System.out.println("最大值:" + max); // 20
	
	// int result = 3 > 4 ? 2.5 : 10; // 错误写法!( 2.5不符合int类型)
	
	System.out.println(a > b ? a : b); // 正确写法!
	
	// a > b ? a : b; // 错误写法!(三元运算符的结果必须被使用)
}
  • 注意:关于 “隐含强制类型转换” 的内容
/* 对于byte/short/char三种类型来说,如果右侧赋值的数值没有超过范围, 那么javac编译器将会自动隐含地为我们补上一个(byte)(short)(char)。 1. 如果没有超过左侧的范围,编译器补上强转。 2. 如果右侧超过了左侧范围,那么直接编译器报错。 */
public static void main(String[] args) {
   
		// int --> byte,不是自动类型转换
		byte num1 = /*(byte)*/ 30; // 右侧int数字没有超过左侧的范围,是正确的!
		System.out.println(num1); // 30
		
		// byte num2 = 128; // 右侧超过了左侧的范围,错误!
		
		// int --> char,没有超过范围
		// 编译器将会自动补上一个隐含的(char)
		char zifu = /*(char)*/ 65;
		System.out.println(zifu); // A
	}
  • 扩展:常量和变量的运算 “编译器的常量优化”
/* 在给变量进行赋值的时候,如果右侧的表达式当中全都是常量,没有任何变量, 那么编译器javac将会直接将若干个常量表达式计算得到结果。 short result = 5 + 8; // 等号右边全都是常量,没有任何变量参与运算 编译之后,得到的.class字节码文件当中相当于【直接就是】: short result = 13; 右侧的常量结果数值,没有超过左侧范围,所以正确。 这称为“编译器的常量优化”。 但是注意:一旦表达式当中有变量参与,那么就不能进行这种优化了。 */
public static void main(String[] args) {
   
	short num1 = 10; // 正确写法,右侧没有超过左侧的范围
		
	short a = 5;
	short b = 8;
	/* 右侧只有两个常量,没有任何变量 在编译的时候(编译器javac),已经确定了 5+8 的结果并没有超过short类型的取值范围, 可以赋值给变量 result ,因此result = 5 + 8 正确 */
	short result = 5 + 8;
	System.out.println(result);//13
	
	/* 右侧存在变量的情况 short + short --> int + int --> int */
	short result1 = a + b; // 错误写法!左侧需要是int类型
	
	short result2 = 5 + a + 8; // 编译报错!不兼容的类型:从int转换到short可能会有损失
}

七、流程控制语句

流程控制:通过控制语句的执行顺序来实现所需功能

7. 1 判断语句

判断语句 1:if

if(关系表达式)//如果关系表达式为 true,则执行语句体;否则不执行
	语句体;

判断语句 2:if…else

if(关系表达式) {
   
	//如果关系表达式为 true,则执行语句体1
	语句体 1 ;
}else {
   
	//如果关系表达式为 false,则执行语句体2
	语句体 2 ;
}

判断语句 3:if…else if…else

if (判断条件1) {
   
   //如果判断条件1的值为true,执行代码
	执行语句1;
} else if (判断条件2) {
   
   //如果判断条件2的值为true,执行代码
	执行语句2;
}
...
} else if (判断条件n) {
   
	执行语句n;
} else {
   
	//如果以上判断条件都不为true,执行代码
	执行语句n+1;
}

7. 2 选择语句

选择语句:switch

switch(表达式) {
   
	case 常量值1:
		语句体1;
		break; //可选
	case 常量值2:
		语句体2;
		break; //可选
	...
	default:   //可选
		语句体n+1;
		break; // 最后一个break语句可以省略,但是强烈推荐不要省略
}
  • 执行流程
    • 计算出表达式的值,并与case的值依次比较
    • 相等时,开始执行case之后的语句,直到break语句出现,才会跳出switch语句
    • 若与case都不匹配,则执行default语句体部分,然后程序结束
  • 注意事项
    • a. 多个case后面的数值不可以重复
    • b. switch后面小括号当中只能是下列数据类型:
      • 基本数据类型:byte/short/char/int;
      • 引用数据类型:String字符串、enum枚举
    • c. switch语句格式可以很灵活:前后顺序可以颠倒,而且break语句还可以省略

case的穿透性

在switch语句中,如果case的后面不写break,将出现穿透现象

即:匹配哪一个case就从哪一个位置向下执行,直到遇到了break或者整体结束为止

7. 3 循环语句

循环结构的基本组成部分,一般可以分成四部分:

  1. 初始化语句:在循环开始最初执行,而且只做唯一一次
  2. 条件判断(布尔表达式):如果成立,则循环继续;如果不成立,则循环退出
  3. 循环体:重复要做的事情内容,若干行语句
  4. 步进语句:每次循环之后都要进行的扫尾工作,每次循环结束之后都要执行一次

循环语句 1:for

for(初始化语句; 布尔表达式; 步进语句){
   
	循环体    //代码语句
}

循环语句 2:while

//格式 1:标准格式
while (条件判断) {
   
	循环体
}

//格式 2:扩展格式
初始化语句;
while (条件判断) {
   
	循环体;
	步进语句;
}

循环语句 3:do…while

//格式 1:标准格式
do {
   
	循环体
} while (条件判断);

//格式 2:扩展格式
初始化语句
do {
   
	循环体
	步进语句
} while (条件判断);
  • do…while循环的特点:无条件执行一次循环体,即使我们将循环条件直接写成false,也依然会循环一次。

三种循环语句的区别

  1. 如果条件判断从来没有满足过,那么for循环和while循环将会执行0次,但是do-while循环会执行至少一次。
  2. for循环的变量在小括号当中定义(局部变量),只有循环内部才可以使用。while循环和do-while循环初始化语句本来就在外面(全局变量),所以出了循环之后还可以继续使用。
  3. 循环的选择:在已知循环次数的时候推荐使用for,次数未知时推荐使用while。

扩展 - 死循环

  • 死循环:永远停不下来的循环
//死循环的标准格式:
while (true) {
   
	循环体
}

//如何结束一个死循环:使用跳出语句

扩展 - 嵌套循环

  • 嵌套循环:是指一个循环的循环体是另一个循环
// 格式:
for(初始化语句; 循环条件; 步进语句){
   
	for(初始化语句; 循环条件; 步进语句){
   
		执行语句
	}
}

//总共的循环次数 = 外循环次数 * 内循环次数

7. 4 跳出语句

break关键字

  • 常见用法(终止switch或循环)
    • 用在switch语句中:一旦执行,整个switch语句立刻结束
    • 用在循环语句当中:一旦执行,整个循环语句立刻结束,打断循环
public static void main(String[] args) {
   
	for (int i = 1; i <= 10; i++) {
   
		// 如果希望从第4次开始,后续全都不要了,就要打断循环
		if (i == 4) {
    // 如果当前是第4次
			break; // 那么就打断整个循环
		}
		System.out.println("Hello" + i);
	}
}

continue关键字

  • 用法:一旦执行,立刻跳过本次循环剩余内容,继续下一次循环
public static void main(String[] args) {
   
	for (int i = 1; i <= 10; i++) {
   
		if (i == 4) {
    // 如果当前是第4层
			continue; // 那么跳过本次循环,马上开始下一次(第5层)
		}
		System.out.println(i + "层到了。");
	}
}

八、开发工具IntelliJ IDEA

  • 概述:IDEA是一个专门针对Java的集成开发工具(IDE),由Java语言编写。所以,需要有JRE运行环境并配置好环境变量。
  • 优点:它可以极大地提升我们的开发效率。可以自动编译,检查错误。
  • 常见快捷键
快捷键 功能
Alt+Enter 导入包,自动修正代码
Ctrl+Y 删除光标所在行
Ctrl+D 复制光标所在行的内容,插入光标位置下面
Ctrl+Alt+L 格式化代码
Ctrl+/ 单行注释
Ctrl+Shift+/ 选中代码注释,多行注释,再按取消注释
Alt+Insert 自动生成代码,toString,get,set等方法
Alt+Shift+上下箭头 移动当前代码行

九、方法

9. 1 方法的定义和调用

什么是方法?方法就是一段可以重复调用的代码

定义方法的格式:

修饰符 返回值类型 方法名 (参数列表){
	代码...
	return ;

调用方法的三种格式:

  1. 单独调用:方法名称(参数);
  2. 打印调用:System.out.println(方法名称(参数));
  3. 赋值调用:数据类型 变量名称 = 方法名称(参数);
public class MethodDefine {
   

    public static void main(String[] args) {
   
        // 单独调用
        sum(10, 20);
        System.out.println("===========");

        // 打印调用
        System.out.println(sum(10, 20)); // 30
        System.out.println("===========");

        // 赋值调用
        int number = sum(15, 25);
        number += 100;
        System.out.println("变量的值:" + number); // 140
    }

    public static int sum(int a, int b) {
   
        System.out.println("方法执行啦!");
        int result = a + b;
        return result;
    }
}

注意事项:

  1. 方法定义的先后 [ 顺序无所谓 ]
  2. 方法 [ 不能嵌套 ],不能在一个方法的内部定义另外一个方法
  3. 方法定义之后,自己不会执行;如果希望执行,一定要进行方法的调用
  4. 如果方法 [ 有返回值 ],那么必须写上“return 返回值;”,不能没有
  5. return 后面的返回值数据,必须和方法的返回值 [ 类型对应 ] 起来
  6. 对于一个 [ void 没有返回值 ] 的方法,不能写 return 后面的返回值,只能写“return ;”(可省略)
  7. 一个方法当中可以有 [ 多个 return 语句 ],但是必须保证同时 [ 只有一个会被执行 ]到,两个return 不能连写
  8. [ 不能在 return 后面写代码 ], return 意味着方法结束,所有后面的代码永远不会执行,属于无效代码
public static void method1() {
   
// return 10; // 错误的写法!方法没有返回值,return后面就不能写返回值。
    return; // 没有返回值,只是结束方法的执行而已。
}

public static void method2() {
   
    System.out.println("AAA");
    System.out.println("BBB");
// return; // 最后一行的return可以省略不写。
}

public static int method3(int a,int b) {
   
	return a + b;
// System.out.println("Hello");// 错误,return已经结束,这里不会执行,无效代码
}

tips

  1. 对于有返回值的方法,可以使用单独调用、打印调用或者赋值调用。
  2. 但是对于无返回值的方法,只能使用单独调用,不能使用打印调用或者赋值调用。

9. 2 方法 - 图解

  • 方法的结构

  • 方法调用的流程

  • 方法返回值的有无

9. 3 方法重载 [ 导图 ]

  • 练习:判断哪些方法是重载关系
public static void open(){
   } // 正确重载
public static void open(int a){
   } // 正确重载
static void open(int a,int b){
   } // 代码错误:和第8行冲突 (与修饰符无关)
public static void open(double a,int b){
   } // 正确重载
public static void open(int a,double b){
   } // 代码错误:和第6行冲突 
public void open(int i,double d){
   } // 代码错误:和第5行冲突 (与修饰符无关)
public static void OPEN(){
   } // 代码正确不会报错,但是并不是有效重载
public static void open(int i,int j){
   } // 代码错误:和第3行冲突

//说明:方法重载与修饰符(public static)无关

十、数组

10. 1 数组定义和访问 [ 导图 ]

数组定义格式详解

注意事项:

  1. 静态初始化标准格式可以拆分成为两个步骤:声明数组、创建空间
  2. 动态初始化也可以拆分成为两个步骤
  3. 静态初始化一旦使用省略格式,就不能拆分成为两个步骤了
public static void main(String[] args) {
   
    // 省略格式的静态初始化
    int[] arrayA = {
    10, 20, 30 };
    System.out.println(arrayA); // 获得的是【地址值】
   
    /* 下方内容 【编译报错】,原因: 编译器会认为数组限定的元素个数[3]与实际存储个数{10,20,30}个数可能不一致, 存在一定的安全隐患。 */
// int[] arrayA2 = new int[3] { 10, 20, 30 }; //错误写法!

    // 静态初始化的标准格式,可以拆分成为两个步骤
    int[] arrayB;  //或 int arrayB[]; (效果相同,但不是首选方法)
    arrayB = new int[] {
    11, 21, 31 };

    // 动态初始化也可以拆分成为两个步骤
    int[] arrayC;
    arrayC = new int[5];

    // 静态初始化的省略格式,不能拆分成为两个步骤
// int[] arrayD;
// arrayD = { 10, 20, 30 }; //写法错误
}

使用动态初始化数组时,其中的元素将会自动拥有一个默认值。规则如下:

数据类型 默认值
整数类型 0
浮点类型 0.0
字符类型 ‘\u0000’
布尔类型 false
引用类型 null

tips

  1. 数组有定长特性,长度一旦指定,不可更改。
  2. 使用建议:如果不确定数组当中的具体内容,用动态初始化;否则,已经确定了具体的内容,用静态初始化
  3. 静态初始化其实也有默认值的过程,只不过系统自动马上将默认值替换成为了大括号当中的具体数值。

10. 2 数组原理内存图

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

Java虚拟机的内存划分(5部分)

区域名称 说明
(Stack) 存放的都是方法中的局部变量。方法的运行一定要在栈中执行
(Heap) 凡是new出来的东西,都在堆当中
方法区(Method Area) 存储.class相关信息,包括方法的信息
本地方法栈(Native Method Stack) 与操作系统相关
寄存器(pc Register) 与CPU相关

数组在内存中的存储

  • 只有一个数组的内存图
    • 方法区存储.class相关信息,保存了程序的main方法
    • ① 查看方法区信息,将main方法加载到栈内存中,并为其开辟一个内存空间(main方法进栈)
    • 创建数组,JVM在堆内存中开辟空间,用来存储数组(凡是new出来的东西,都在堆中)
    • ③ 数组中有三个元素,于是将空间划分为三部分,且元素默认值为0
    • ④ 创建好的数组在内存中有自己的内存地址(十六进制的地址值)
    • ⑤ 数组的地址值被JVM赋值给变量array(new出的数组在堆中,变量在栈中)
    • ⑥ 引用数据类型的变量array中存储的是数组的地址值,根据该地址值找到堆中的数组

  • 有两个独立数组的内存图

  • 两个引用指向同一个数组的内存图

10. 3 数组的常见操作

数组越界异常

  • 如果访问数组元素的时候,索引编号并不存在,那么将会发生数组索引越界异常 ArrayIndexOutOfBoundsException
  • 原因:索引编号(编号从0开始,一直到“数组的长度-1”为止)写错了
  • 解决:修改成为存在的正确索引编号
public static void main(String[] args) {
   
    int[] array = {
    15, 25, 35 };
    
	// 错误写法:并不存在3号元素,所以发生异常
	System.out.println(array[3]);
}

数组空指针异常

  • 所有的引用类型变量,都可以赋值为一个null值(代表其中什么都没有),数组必须进行new初始化才能使用其中的元素
  • 如果只是赋值了一个null,没有进行new创建,那么将会发生:空指针异常 NullPointerException
  • 原因:未对数组进行new初始化
  • 解决:补上new
public static void main(String[] args) {
   
    int[] array = null;
// array = new int[3]; //补上new即可
    System.out.println(array[0]);
}

数组遍历

  • 对数组当中的每一个元素进行逐一、挨个儿处理。默认的处理方式是打印输出
public static void main(String[] args) {
   
    int[] array = {
    15, 25, 30, 40 };

    // 首先使用原始方式
    System.out.println(array[0]); // 15
    System.out.println(array[1]); // 25
    System.out.println(array[2]); // 30
    System.out.println(array[3]); // 40
    System.out.println("=================");

    // 使用循环,次数其实就是数组的长度(array.length)
    for (int i = 0; i < array.length; i++) {
   
        System.out.println(array[i]);
    }
}

数组最值

//数组获取最大值元素
public static void main(String[] args) {
   
    int[] array = {
    5, 15, 30, 20, 10000, 30, 35 };
    // 定义变量,保存数组中0索引的元素
    int max = array[0]; 
    // 遍历数组,取出每个元素
    for (int i = 1; i < array.length; i++) {
   
        // 如果当前元素,比max更大,则max换成大值
        if (array[i] > max) {
   
            max = array[i];
        }
    }
    // 输出最大值
    System.out.println("最大值:" + max);
}

数组反转

  • 要求:
    • 数组元素反转,如:[1, 2, 3, 4] → [4, 3, 2, 1]
    • 不能使用新数组,就用原来的唯一一个数组
  • 思路与实现:

public static void main(String[] args) {
   
    int[] array = {
    10, 20, 30, 40, 50 };
    /* 初始化语句:int min = 0, max = array.length - 1 条件判断:min < max 步进表达式:min++, max-- 循环体:用第三个变量倒手 */
    for (int min = 0, max = array.length - 1; min < max; min++, max--) {
   
        int temp = array[min];
        array[min] = array[max];
        array[max] = temp;
    }

    // 打印遍历输出数组后来的样子
    for (int i = 0; i < array.length; i++) {
   
        System.out.println(array[i]);//50, 40, 30, 20, 10
    }
}

10. 4 数组作为方法参数和返回值

数组作为方法的参数

  • 传递进去的是:数组的地址值
public static void main(String[] args) {
   
     int[] array = {
    10, 20, 30, 40, 50 };
     System.out.println(array); // 地址值
     //调用方法,传递数组
     printArray(array); // 传递进去的是array中保存的地址值
 }

 /* 三要素 返回值类型:只是进行打印而已,不需要进行计算,也没有结果,用void 方法名称:printArray 参数列表:必须给我数组,我才能打印其中的元素。int[] array */
 public static void printArray(int[] array) {
   
     System.out.println("printArray方法收到的参数是:");
     System.out.println(array); // 地址值
     for (int i = 0; i < array.length; i++) {
   
         System.out.println(array[i]);
     }
 }

数组作为方法的返回值

  • 返回的是:数组的地址值
  • 一个方法可以有0、1、多个参数;但只能有0或1个返回值,不能有多个返回值
  • 问:如果希望一个方法当中产生了多个结果数据进行返回,怎么办?
    解决方案:使用一个数组作为返回值类型即可
public static void main(String[] args) {
   
   int[] result = calculate(10, 20, 30);

    System.out.println("main方法接收到的返回值数组是:");
    System.out.println(result); // 地址值

    System.out.println("总和:" + result[0]);
    System.out.println("平均数:" + result[1]);
}

public static int[] calculate(int a, int b, int c) {
   
    int sum = a + b + c; // 总和
    int avg = sum / 3; // 平均数
    // 两个结果都希望进行返回

    // 需要一个数组,也就是一个塑料兜,数组可以保存多个结果
    /* int[] array = new int[2]; array[0] = sum; // 总和 array[1] = avg; // 平均数 */
    int[] array = {
    sum, avg };
    System.out.println("calculate方法内部数组是:");
    System.out.println(array); // 地址值
    return array;
}

tips:

  1. 任何数据类型都能作为方法的参数类型,或者返回值类型
  2. 方法的参数为 基本类型 时,传递的是 数据值;
    方法的参数为 引用类型 时,传递的是 地址值

全部评论

相关推荐

牛客868257804号:九个中铁八个中建
点赞 评论 收藏
分享
牛客717484937号:双飞硕没实习挺要命的
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务