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:
- 程序的文件名:需和类的名字一致,注意大小写,每个字母和符号必须与示例代码一模一样。eg:HelloWorld
- 工具:(1).java文件的编译工具:javac.exe [ 编译器 ] (2).class文件的运行工具:java.exe [ 解释器 ]
3. 2 入门程序说明
编译和运行是两个不同概念
- 编译:将编写的Java源文件翻译成JVM认识的class文件(此过程中,编译器会检查所写程序是否错误——若有错误则会有提示,否则编译成功)
- 运行:将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:
- Java中的默认类型:整数类型是 int 、浮点类型是 double
- 变量的定义: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:
- byte/short/char这三种类型:
(1)都可以发生数***算,例如 加法“+”;(2)在运算的时候,都会被首先提升成为int类型,然后再计算- 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:for
for(初始化语句; 布尔表达式; 步进语句){
循环体 //代码语句
}
循环语句 2:while
//格式 1:标准格式
while (条件判断) {
循环体
}
//格式 2:扩展格式
初始化语句;
while (条件判断) {
循环体;
步进语句;
}
循环语句 3:do…while
//格式 1:标准格式
do {
循环体
} while (条件判断);
//格式 2:扩展格式
初始化语句
do {
循环体
步进语句
} while (条件判断);
- do…while循环的特点:无条件执行一次循环体,即使我们将循环条件直接写成false,也依然会循环一次。
三种循环语句的区别
- 如果条件判断从来没有满足过,那么for循环和while循环将会执行0次,但是do-while循环会执行至少一次。
- for循环的变量在小括号当中定义(局部变量),只有循环内部才可以使用。while循环和do-while循环初始化语句本来就在外面(全局变量),所以出了循环之后还可以继续使用。
- 循环的选择:在已知循环次数的时候推荐使用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 ;
}
调用方法的三种格式:
- 单独调用:方法名称(参数);
- 打印调用:System.out.println(方法名称(参数));
- 赋值调用:数据类型 变量名称 = 方法名称(参数);
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;
}
}
注意事项:
- 方法定义的先后 [ 顺序无所谓 ]
- 方法 [ 不能嵌套 ],不能在一个方法的内部定义另外一个方法
- 方法定义之后,自己不会执行;如果希望执行,一定要进行方法的调用
- 如果方法 [ 有返回值 ],那么必须写上“
return 返回值;
”,不能没有 - return 后面的返回值数据,必须和方法的返回值 [ 类型对应 ] 起来
- 对于一个 [ void 没有返回值 ] 的方法,不能写 return 后面的返回值,只能写“
return ;
”(可省略) - 一个方法当中可以有 [ 多个 return 语句 ],但是必须保证同时 [ 只有一个会被执行 ]到,两个return 不能连写
- [ 不能在 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:
- 对于有返回值的方法,可以使用单独调用、打印调用或者赋值调用。
- 但是对于无返回值的方法,只能使用单独调用,不能使用打印调用或者赋值调用。
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 数组定义和访问 [ 导图 ]
数组定义格式详解:
注意事项:
- 静态初始化标准格式可以拆分成为两个步骤:声明数组、创建空间
- 动态初始化也可以拆分成为两个步骤
- 静态初始化一旦使用省略格式,就不能拆分成为两个步骤了
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:
- 数组有定长特性,长度一旦指定,不可更改。
- 使用建议:如果不确定数组当中的具体内容,用动态初始化;否则,已经确定了具体的内容,用静态初始化。
- 静态初始化其实也有默认值的过程,只不过系统自动马上将默认值替换成为了大括号当中的具体数值。
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:
- 任何数据类型都能作为方法的参数类型,或者返回值类型
- 方法的参数为 基本类型 时,传递的是 数据值;
方法的参数为 引用类型 时,传递的是 地址值