Java基础
注释
- 单行注释:
1 | // 单行注释,只注释一行 |
- 多行注释:
1 | /* |
- 文档注释:
1 | /** |
关键字和字面量
- 关键字指的是被Java赋予了特定含义的英文单词
- 关键词用户不能随意使用
- 字面量这个知识要求学会
数据在程序中的书写格式 - 字符、字符串在程序中的书写格式要求:
字符使用单引号,且单引号内只能有一个字符;字符串使用双引号,对数量没有要求
变量
变量的定义格式:数据类型 变量名称 = 变量值
示例:
1 | public class VariableDemo { |
注意事项:
- 变量要先声明才能使用
- 变量是什么类型,就必须装什么类型的数据
- 变量只在自己所归属的{}范围内有效(作用域)
- 同一个范围内,变量的名称不能重复
- 变量定义的时候可以不赋初始值,但在调用/使用时,变量里必须有值
1 | int a; |
- 一条语句可以定义多个变量,中间使用逗号分隔
1 | int a = 10,b = 20,c = 30; |
标识符
- 由数字、字母、下划线(_)和美元符号($)组成
- 不能以数字开头
- 不能是关键字
- 区分大小写
小驼峰命名法(适用于变量、方法):
- 规范1:标识符是一个单词的时候,所有字母小写
- 范例1:name
- 规范2:标识符由多个单词组成的时候,从第二个单词开始,首字母大写
- 范例2:firstName
大驼峰命名法(适用于类):
- 规范1:标识符是一个单词的时候,首字母大写
- 范例1:Student
- 规范2:标识符由多个单词组成的时候,每个单词的首字母大写
- 范例2:GoodStudent
数据类型
基本数据类型
主要有
- 整数类型:int、long、short、byte
- 浮点数:float、double
- 字符:char
- 布尔:boolean
所有的整数默认为
int,所有的小数默认为double
运算符
算数运算符
| 符号 | 作用 | 说明 |
|---|---|---|
| + | 加 | 数据相加 |
| - | 减 | 数据相减 |
| * | 乘 | 数据相乘 |
| / | 除 | 数据相除 |
| % | 取模 | 两个数据做除法的余数 |
/ 和 % 的区别:两个数据做除法,/ 取结果的商,% 取结果的余数
整数操作只能得到整数,想要得到小数,必须有浮点数参与运算
练习:获取到三位数上个位、十位、百位的数字。如256,个位为6,十位为5,百位为2
答案:
1 | public class OperatorDemo { |
当 + 操作中,遇到了字符串,这时 + 就是字符串拼接符,而不是算数运算
自增自减运算符
| 符号 | 作用 | 说明 |
|---|---|---|
| ++ | 自增 | 变量自身的值加1 |
| – | 自减 | 变量自身的值减1 |
++ 和 – 既可以放在变量的后边,也可以放在变量的前边
自增自减只能操作变量,不能操作字面量
示例:
1 | public class Operator2Demo { |
类型转换
隐式转换
- 把一个取值范围小的数值或者变量,赋值给另一个取值范围大的变量
1 | int a = 10; |
- 取值范围小的数据,和取值范围大的数据进行运算,小的会先提升为大的之后,再进行运算
1 | int a = 10; |
- byte、short、char三种数据在运算的时候,都会提升为int,然后再进行运算
1 | byte a = 10; |
强制转换
- 把一个取值范围大的数值或者变量,赋值给另一个取值范围小的变量
- 不允许直接复制,需要加入强制转换
- 格式:
目标数据类型 变量名 = (目标数据类型) 被强转的数据
1 | double a = 12.3; |
赋值运算符
| 符号 | 作用 | 说明 |
|---|---|---|
| = | 赋值 | a=10,将10赋值给变量a |
| += | 加后赋值 | a+=b,将a + b的值赋给a |
| -= | 减后赋值 | a-=b,将a - b的值赋给a |
| *= | 乘后赋值 | a*=b,将a * b的值赋给a |
| /= | 除后赋值 | a/=b,将a / b的值赋给a |
| %= | 取模后赋值 | a%=b,将a % b的值赋给a |
关系运算符
| 符号 | 说明 |
|---|---|
| == | a==b,判断a和b的值是否相等,成立为true,不成立为false |
| != | a!=b,判断a和b的值是否不相等,成立为true,不成立为false |
| > | a>b,判断a是否大于b,成立为true,不成立为false |
| >= | a>=b,判断a是否大于等于b,成立为true,不成立为false |
| < | a<b,判断a是否小于b,成立为true,不成立为false |
| <= | a<=b,判断a是否小于等于b,成立true,不成立为false |
逻辑运算符
- 把多个条件放在一起运算,最终返回布尔类型的值:true、false
| 符号 | 介绍 | 说明 |
|---|---|---|
| & | 逻辑与 | 并且,遇false则false |
| | | 逻辑或 | 或者,遇true则true |
| ! | 逻辑非 | 取反 |
| ^ | 逻辑异或 | 相同为false,不同为true |
短路逻辑运算符
| 符号 | 介绍 | 说明 |
|---|---|---|
| && | 短路与 | 作用和&相同,但是有短路效果 |
| || | 短路或 | 作用和|相同,但是有短路效果 |
- 逻辑与&,无论左边true false,右边都要执行
- 短路与&&,如果左边为true,右边执行,如果左边为false,右边不执行
- 逻辑或|,无论左边true false,右边都要执行
- 短路或||,如果左边为false,右边执行,如果左边为true,右边不执行
实际开发中,最常用的是
!、&&、||这三个
三元运算符
- 格式:
判断条件 ? 值1 : 值2; - 执行流程:
- 首先计算判断条件的值
- 如果值为true,值1就是运算结果
- 如果值为false,值2就是运算结果
运算符优先级
| 优先级 | 运算符 |
|---|---|
| 1 | . () {} |
| 2 | !、-、++、– |
| 3 | *、/、% |
| 4 | +、- |
| 5 | >>、<<、>>> |
| 6 | <、<=、>、>=、instanceof |
| 7 | ==、!= |
| 8 | & |
| 9 | ^ |
| 10 | | |
| 11 | && |
| 12 | || |
| 13 | ? : |
| 14 | =、+=、-=、*=、/=、%=、&= |
Scanner键盘录入
使用顺序:
- 引入Scanner包
1 | import java.util.Scanner |
- 创建Scanner对象
1 | Scanner sc = new Scanner(System.in); |
- 使用变量接收键入值:
1 | int number = sc.nextInt(); |
完整示例:
1 | import java.util.Scanner; |
方法(函数)
方法(函数):一段具有独立功能的代码块,不调用不执行
方法的出现:
- 可以将挤在一起的臃肿代码,按照功能进行分类管理,提高维护性
- 提高代码的复用性
方法的基本定义和调用
- 定义格式:
1 | public static void 方法名() { |
- 调用格式:
1 | 方法名(); |
示例:
1 | public class MethodDemo01 { |
方法的调用流程
- 方法没有被调用的时候,在方法区中的字节码文件中存放
- 方法被调用的时候,需要进入到栈内存中运行
方法区:字节码文件加载时进入的内存
栈内存:方法运行时入栈,方法运行结束出栈
带参方法
- 定义格式:
1 | public static void 方法名(数据类型 参数名1, 数据类型 参数名2) { |
- 调用格式:
1 | 方法名(字面量或变量名); |
示例:
1 | public class MethodDemo02 { |
形参:方法定义时声明的参数
实参:方法调用时传入的参数
带返回值方法
- 定义格式:
1 | public static 数据类型 方法名(数据类型 参数名1, 数据类型 参数名2) { // 也可以为无参方法 |
返回的结果的数据类型一定要与定义方法时的数据类型匹配
- 调用格式:
1 | 数据类型 变量名 = 方法名(); |
示例:
1 | public class MethodDemo03 { |
方法的注意事项
方法不调用就不执行
方法与方法之间是平级关系,不能嵌套定义
方法的编写顺序和执行顺序无关
方法的返回值类型为
void,表示该方法没有返回值,没有返回值的方法可以省略return语句不写如果要编写return,后面不能有具体的数据
public static void sayHello() { System.out.println("Hello"); return; // 后面不能有具体的数据 }1
2
3
4
5
6
7
8
- 当执行到return语句后,就表示该方法已经得到了结果,此时方法就会结束运行
- ```java
public static int count(int a.int b) {
return a + b;
System.out.println(a + b); // 这条代码不会执行
}
方法重载
为了减少命名空间,可以使用方法重载,重载条件如下:
- 参数数量不同
- 参数位置不同
- 参数类型不同
但是,返回值不同不能作为重载条件
示例:
1 | public class MethodDemo04 { |
流程控制语句
顺序结构
Java程序默认的执行流程,没有特定的语法结构,按照代码的先后顺序,依次执行
大多数的代码都是这样执行的
分支结构
分支结构if语句
if第一种格式:
1 | if (判断条件) { |
执行流程:
- 首先计算判断条件的结果
- 如果条件的结果为true,则执行语句体
- 如果条件的结果为false,则不执行语句体
示例:
1 | int age = 17; |
if第二种格式:
1 | if (判断条件) { |
执行流程:
- 首先计算判断条件的结果
- 如果条件的结果为true,则执行语句体1
- 如果条件的结果为false,则执行语句体2
示例:
1 | int age = 19; |
if第三种格式:
1 | if (判断条件1) { |
执行流程:
- 首先计算判断条件1的值
- 如果为true就执行语句体1;如果值为false就计算判断条件2的值
- 如果为true就执行语句体2;如果值为false就计算判断条件3的值
- …
- 如果没有任何判断条件为true,就执行语句体n+1
示例:
1 | int age = 33; |
注意事项:
- if语句中,如果大括号控制的是一条语句,大括号可以省略不写
1 | if (age <= 0) System.out.println("年龄不存在"); |
- if语句的
()和{}之间不要写分号 - if语句的
()中需要产生boolean类型的结果(true、false),根据结果决定程序的走向
分支结构switch语句
- 通过比较值来决定执行哪条分支
switch分支的执行流程
- 先计算表达式的值,再拿着这个值去与case后的值进行匹配
- 与哪个case后的值匹配为true就执行哪个case块的代码,遇到break就跳出switch分支
- 如果全部case后的值与之匹配都是false,则执行default块的代码
1 | switch(表达式) { |
示例:
1 | Scanner sc = new Scanner(System.in); |
注意事项:
- 表达式类型只能是byte、short、int、char,不支持double、float、long
- JDK5开始支持枚举
- JDK7开始支持String
- case给出的值不允许重复,且只能是字面量,不能是变量
- 正常使用switch的时候,不要忘记写break,否则会发生穿透现象
- case后可以用逗号分隔多个字面量,如
case 1,2,3: ...
if和switch的选择
- if适合做条件是区间判断的情况
- switch适合做:条件是比较值的情况,代码优雅且性能较好
Debug工具
- Debug:是供程序员使用的程序调试工具,它可以用于查看程序的执行流程,也可以用于追踪程序执行过程来调试程序
- Debug调试,又被成为断点调试,断点其实是一个标记,告诉Debug从标记的地方开始查看

循环结构
- 可以让一段代码重复执行多次
for循环
格式:
1 | for (初始化语句; 条件判断语句; 条件控制语句) { |
示例:
1 | for (int i = 0; i < 10; i++) { |
结果为:第0次第1次第2次第3次第4次第5次第6次第7次第8次第9次
注意事项
- 循环
{}中定义变量,在每一轮循环结束后,都会从内存中释放 - 循环
()中定义的变量,在整个循环结束后,都会从内存中释放 - 循环语句
()和{}之间不要写分号
水仙花数
水仙花数的个位、十位、百位的数字立方和等于原数
1 | 123 1^3 + 2^3 + 3^3 = 1 + 8 + 27 = 36 36 != 123 不是水仙花数 |
求所有100 ~ 999之间的所有水仙花数
1 | public class Practice { |
循环嵌套
在循环体中,继续出现循环语句
示例:
1 | for (int i = 0; i < 10; i++) { |
while循环
格式:
1 | while(判断语句) { |
示例:
1 | int a = 0; |
案例:
1 | /* |
for和while的选择
- 功能上是完全一样的,for能解决的while也能解决,反之亦然
- 使用规范:知道循环次数,使用for;不知道循环次数建议使用while
do…while循环
格式:
1 | 初始化语句; |
示例:
1 | int a = 20; |
解释:与while不同(先判断,后执行),do…while即使最开始没有满足循环条件,也会执行一次do括号里的代码(先执行,后判断)
break、continue
- break:终止循环体内容的执行,也就是说结束当前的整个循环
- continue:跳过某次循环体内容的执行,继续下一次的执行
break示例:
1 | int a = 0; |
continue示例:
1 | int a = 0; |
注意事项:
- 遇到循环嵌套时,break和continue操作的是内循环
- break只能在循环和switch中使用,continue只能在循环中进行使用
标号(循环体命名)
当希望break和continue操作外循环时,可以通过给外循环起名(标号),并在break或continue后指定循环体名称即可
示例:
1 | lo: |
lo是loop的缩写,也就是对外层循环起的名称
Random随机数
使用步骤:
- 导包:
1 | import java.util.Random; |
- 创建Random对象:
1 | Random r = new Random(); |
- 生成随机数:
1 | int num1 = r.nextInt(10); // 范围:0 ~ 9 |
案例:
1 | import java.util.Random; |
数组
数组定义
- 格式一:
数据类型[] 数组名 - 示例:
int[] arr; - 格式二:
数据类型 数组名[] - 示例:
int arr[];
在Java中,推荐使用格式一的书写规范
数组静态初始化
- 初始化:就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程
- 完整格式:
数组类型[] 数组名 = new 数据类型[] {元素1, 元素2, 元素3, ...}; - 示例:
int[] arr = new int[] {11, 22, 33};
- 简化格式:
数据类型[] 数组名 = {元素1, 元素2, 元素3, ...}; - 示例:double[] arr = {11.1, 22.2, 33.3};
推荐使用简化格式,阅读起来更加方便
直接打印数组名,输出的不是数组中的数据,而是数组在内存中的地址(十六进制)。实际上,就也就说明了数组其实是引用数据类型
数组元素访问
- 格式:
数组名[索引]; - 示例:
arr[0]; - 索引:索引是数组容器中空间的编号,编号从0开始,逐个+1增长
完整代码如下:
1 | public class ArrayDemo01 { |
数组遍历
- 数组遍历:依次访问数组中的每一个元素
- 本质:利用for循环访问数组中的元素
示例:
1 | public class ArrayDemo02 { |
进阶用法:
1 | public class ArrayDemo02 { |
由于数组是可迭代对象,所以可以直接使用
for(数据类型 变量名 : 数组名),也就是增强型for循环或者叫for-each循环
反转数组
案例:
1 | public class ArrayReverse { |
- 第一种反转算法较为简单(从尾到头遍历),但是效率较低
- 第二种反转算法较为复杂(头尾交换),但是效率较高
- 最常用的是第二种写法
数组动态初始化
动态初始化:初始化时只指定数组长度,由系统为数组分配初始值
- 格式:
数据类型[] 数组名 = new 数据类型[数组长度]; - 示例:
int[] arr = new int[3];
案例:
1 | public class ArrayDemo03 { |
动态数组初始化,其实就是将数组中的元素全部以默认值填充,长度由用户指定
数据类型 默认值 整数 0 小数 0.0 字符 ‘\u0000’ 常体现为空白字符 布尔 false 类、接口、数组、字符串 null 动态初始化适用场景:不明确要操作元素的时候,比如随机数生成
二维数组
- 二维数组是一种容器,该容器用于存储一维数组
- 完整格式:
数据类型[][] 数组名 = new 数据类型[][] {{元素1,元素2,元素3},{元素4,元素5,元素6},{元素7,元素8,元素9,元素10}, ... }` - 简化格式:`数据类型[][] 数组名 = {{元素1,元素2,元素3},{元素4,元素5,元素6},{元素7,元素8,元素9,元素10}, ... }` - 示例:`int[][] arr = {{123},{456},{789}}; - 访问:
arr[1][1]; // 5
完整代码:
1 | public class ArrayDemo04 { |
二维数组遍历
示例:
1 | public class ArrayDemo04 { |
常见异常
索引越界异常
- ArrayIndexOutOfBoundsException:当访问了数字中不存在的索引,就会引发索引越界异常
- 示例:
int[] a = {1,2,3}; a[5] = 15;
空指针异常
- NullPointerException:当引用数据类型被赋值为null后,地址的指向被切断,如果还继续访问堆内存数据,就会引发空指针异常
- 示例:
1 | int[] arr = {1,2,3,4,5,6}; |
Java内存分配
Java内存分配有以下5种:
- 栈:每个方法调用生成一个栈帧,存储局部变量、操作数栈、方法出口等信息。例如:
main()方法运行时进入栈内存 - 堆:new出来的东西会在这块内存中开辟空间并产生地址
- 方法区:存储类元数据(类名、方法名、常量池等)。JDK 8+ 使用元空间(Metaspace)替代,部分功能由堆承担
- 本地方法栈:用于
native方法调用(如Java调用C/C++代码),通过JNI(Java Native Interface)实现 - 寄存器:CPU内部高速存储单元,用于临时存储指令和数据,是代码执行的核心桥梁
数组内存
数组简化格式:int[] arr = {11,22,33};
但真正运行时,还是按照完整格式运行的:int[] arr = new int[]{11,22,33};