Java基础
注释
- 单行注释:
// 单行注释,只注释一行
- 多行注释:
/*
多行注释
多行注释
*/
- 文档注释:
/**
文档注释
文档注释
*/
关键字和字面量
- 关键字指的是被Java赋予了特定含义的英文单词
- 关键词用户不能随意使用
- 字面量这个知识要求学会
数据在程序中的书写格式 - 字符、字符串在程序中的书写格式要求:
字符使用单引号,且单引号内只能有一个字符;字符串使用双引号,对数量没有要求
变量
变量的定义格式:数据类型 变量名称 = 变量值
示例:
public class VariableDemo {
public static void main(String[] args) {
String name = "张三";
int age = 25;
float height = 1.86f;
boolean isMarried = false;
System.out.println("姓名:" + name);
System.out.println("年龄:" + age);
System.out.println("身高:" + height);
System.out.println("婚姻状况:" + isMarried);
}
}
注意事项:
- 变量要先声明才能使用
- 变量是什么类型,就必须装什么类型的数据
- 变量只在自己所归属的{}范围内有效(作用域)
- 同一个范围内,变量的名称不能重复
- 变量定义的时候可以不赋初始值,但在调用/使用时,变量里必须有值
int a;
int b;
a = 10;
System.out.println(a);// 10
System.out.println(b);// 报错:可能尚未初始化变量b
- 一条语句可以定义多个变量,中间使用逗号分隔
int a = 10,b = 20,c = 30;
System.out.println(a);// 10
System.out.println(b);// 20
System.out.println(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
答案:
public class OperatorDemo {
public static void main(String[] args) {
int num = 256;
int unitsDigit = num % 10;
int tensDigit = num / 10 % 10;
int hundredsDigit = num / 100;
System.out.println("个位数:" + unitsDigit);
System.out.println("十位数:" + tensDigit);
System.out.println("百位数:" + hundredsDigit);
}
}
当 + 操作中,遇到了字符串,这时 + 就是字符串拼接符,而不是算数运算
自增自减运算符
| 符号 | 作用 | 说明 |
|---|---|---|
| ++ | 自增 | 变量自身的值加1 |
| – | 自减 | 变量自身的值减1 |
++ 和 – 既可以放在变量的后边,也可以放在变量的前边
自增自减只能操作变量,不能操作字面量
示例:
public class Operator2Demo {
public static void main(String[] args) {
// 前置自增和后置自增的区别(自减同理)
int a = 10;
int b = 20;
int c = a++ + 10;
System.out.println("c:" + c); // 20
System.out.println("a:" + a); // 11
int d = ++b + 10;
System.out.println("d:" + d); // 31
System.out.println("b:" + b); // 21
// 自增自减运算符不能操作字面量
System.out.println(10++);// 报错
System.out.println(--10);// 报错
// 特殊写法(实际开发中不建议)
int x = 3;
int y = (x++) + (++x) + (x * 10);// 4 + 4 + 50
System.out.println(x);// 5
System.out.println(y);// 58
}
}
类型转换
隐式转换
- 把一个取值范围小的数值或者变量,赋值给另一个取值范围大的变量
int a = 10;
double b = a;
System.out.println(b);// 10.0
- 取值范围小的数据,和取值范围大的数据进行运算,小的会先提升为大的之后,再进行运算
int a = 10;
double b = 12.3;
double c = a + b;
- byte、short、char三种数据在运算的时候,都会提升为int,然后再进行运算
byte a = 10;
byte b = 20;
byte c = a + b;// 报错,c的数据类型应该是int
强制转换
- 把一个取值范围大的数值或者变量,赋值给另一个取值范围小的变量
- 不允许直接复制,需要加入强制转换
- 格式:
目标数据类型 变量名 = (目标数据类型) 被强转的数据
double a = 12.3;
int b = (int)a;
System.out.println(b);// 12
赋值运算符
| 符号 | 作用 | 说明 |
|---|---|---|
| = | 赋值 | 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 |
| 逻辑或 | ||
| ! | 逻辑非 | 取反 |
| ^ | 逻辑异或 | 相同为false,不同为true |
短路逻辑运算符
| 符号 | 介绍 | 说明 |
|---|---|---|
| && | 短路与 | 作用和&相同,但是有短路效果 |
- 逻辑与&,无论左边true false,右边都要执行
- 短路与&&,如果左边为true,右边执行,如果左边为false,右边不执行
- 逻辑或|,无论左边true false,右边都要执行
- 短路或||,如果左边为false,右边执行,如果左边为true,右边不执行
实际开发中,最常用的是
!、&&、||这三个
三元运算符
- 格式:
判断条件 ? 值1 : 值2; - 执行流程: 1. 首先计算判断条件的值 2. 如果值为true,值1就是运算结果 3. 如果值为false,值2就是运算结果
运算符优先级
| 优先级 | 运算符 |
|---|---|
| 1 | . () {} |
| 2 | !、-、++、– |
| 3 | *、/、% |
| 4 | +、- |
| 5 | >>、<<、>>> |
| 6 | <、<=、>、>=、instanceof |
| 7 | ==、!= |
| 8 | & |
| 9 | ^ |
| 10 | |
| 11 | && |
| 12 | |
| 13 | ? : |
| 14 | =、+=、-=、*=、/=、%=、&= |
Scanner键盘录入
使用顺序:
- 引入Scanner包
import java.util.Scanner
- 创建Scanner对象
Scanner sc = new Scanner(System.in);
- 使用变量接收键入值:
int number = sc.nextInt();
完整示例:
import java.util.Scanner;
public class ScannerDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int age = sc.nextInt();
String name = sc.next();
double height = sc.nextDouble();
}
}
方法(函数)
方法(函数):一段具有独立功能的代码块,不调用不执行
方法的出现:
- 可以将挤在一起的臃肿代码,按照功能进行分类管理,提高维护性
- 提高代码的复用性
方法的基本定义和调用
- 定义格式:
public static void 方法名() {
// 方法体
}
- 调用格式:
方法名();
示例:
public class MethodDemo01 {
public static void main(String[] args) {
sayHello();
}
public static void sayHello() {
System.out.println("Hello");
}
}
方法的调用流程
- 方法没有被调用的时候,在方法区中的字节码文件中存放
- 方法被调用的时候,需要进入到栈内存中运行
方法区:字节码文件加载时进入的内存
栈内存:方法运行时入栈,方法运行结束出栈
带参方法
- 定义格式:
public static void 方法名(数据类型 参数名1, 数据类型 参数名2) {
// 方法体
}
- 调用格式:
方法名(字面量或变量名);
示例:
public class MethodDemo02 {
public static void main(String[] args) {
count(10,20); // 结果为:30
int a = 11;
int b = 22;
count(a,b); // 结果为:33
}
public static void count(int num01,int num02) {
System.out.println("结果为:" + (num01 + num02));
}
}
形参:方法定义时声明的参数
实参:方法调用时传入的参数
带返回值方法
- 定义格式:
public static 数据类型 方法名(数据类型 参数名1, 数据类型 参数名2) {// 也可以为无参方法
// 方法体
return 结果;
}
返回的结果的数据类型一定要与定义方法时的数据类型匹配
- 调用格式:
数据类型 变量名 = 方法名();
示例:
public class MethodDemo03 {
public static void main(String[] args) {
String str = giveMeFive();
System.out.println(str); // GiveMeFive
int cnt = count(10,20);
System.out.println(cnt); // 30
}
public static String giveMeFive() {
return "GiveMeFive";
}
public static int count(int a,int b) {
return a + b;
}
}
方法的注意事项
- 方法不调用就不执行
- 方法与方法之间是平级关系,不能嵌套定义
- 方法的编写顺序和执行顺序无关
-
方法的返回值类型为
void,表示该方法没有返回值,没有返回值的方法可以省略return语句不写 -
如果要编写return,后面不能有具体的数据
-
``` public static void sayHello() { System.out.println("Hello"); return;// 后面不能有具体的数据}
``` - 当执行到return语句后,就表示该方法已经得到了结果,此时方法就会结束运行
java public static int count(int a.int b) { return a + b; System.out.println(a + b);// 这条代码不会执行 }```
方法重载
为了减少命名空间,可以使用方法重载,重载条件如下:
- 参数数量不同
- 参数位置不同
- 参数类型不同
但是,返回值不同不能作为重载条件
示例:
public class MethodDemo04 {
public static void main(String[] args) {
}
public static void count() {
System.out.println("请放入至少两个数");
}
public static void count(int a) {
System.out.println("请放入至少两个数");
}
public static int count(int a,int b) {
return a + b;
}
// 参数数量不同
public static int count(int a,int b, int c) {
return a + b + c;
}
// 参数类型不同
public static double count(double a,double b) {
return a + b;
}
public static double count(double a,double b,double c) {
return a + b + c;
}
// 参数位置不同
public static double count(double a,int b) {
return a + b;
}
public static double count(int a,double b) {
return a + b;
}
}
流程控制语句
顺序结构
Java程序默认的执行流程,没有特定的语法结构,按照代码的先后顺序,依次执行
大多数的代码都是这样执行的
分支结构
分支结构if语句
if第一种格式:
if (判断条件) {
语句体;
}
执行流程:
- 首先计算判断条件的结果
- 如果条件的结果为true,则执行语句体
- 如果条件的结果为false,则不执行语句体
示例:
int age = 17;
if (age < 18) {
System.out.println("未成年");
}
if第二种格式:
if (判断条件) {
语句体1;
} else {
语句体2;
}
执行流程:
- 首先计算判断条件的结果
- 如果条件的结果为true,则执行语句体1
- 如果条件的结果为false,则执行语句体2
示例:
int age = 19;
if (age < 18) {
System.out.println("未成年");
} else {
System.out.println("成年");
}
if第三种格式:
if (判断条件1) {
语句体1;
} else if (判断条件2) {
语句体2;
} ...
else {
语句体n+1;
}
执行流程:
- 首先计算判断条件1的值
- 如果为true就执行语句体1;如果值为false就计算判断条件2的值
- 如果为true就执行语句体2;如果值为false就计算判断条件3的值
- …
- 如果没有任何判断条件为true,就执行语句体n+1
示例:
int age = 33;
if (age <= 0) {
System.out.println("年龄不存在");
} else if (age < 18) {
System.out.println("未成年");
} else if (age < 35) {
System.out.println("青壮年");
} else if (age < 50) {
System.out.println("中年");
} else {
System.out.println("老年");
}
注意事项:
- if语句中,如果大括号控制的是一条语句,大括号可以省略不写
if (age <= 0) System.out.println("年龄不存在");
else if (age < 18) System.out.println("未成年");
else if (age < 35) System.out.println("青壮年");
else if (age < 50) System.out.println("中年");
else System.out.println("老年");
- if语句的
()和{}之间不要写分号 - if语句的
()中需要产生boolean类型的结果(true、false),根据结果决定程序的走向
分支结构switch语句
- 通过比较值来决定执行哪条分支
switch分支的执行流程
- 先计算表达式的值,再拿着这个值去与case后的值进行匹配
- 与哪个case后的值匹配为true就执行哪个case块的代码,遇到break就跳出switch分支
- 如果全部case后的值与之匹配都是false,则执行default块的代码
switch(表达式) {
case 值1:
语句体1;
break;
case 值2;
语句体2;
break;
...
default:
语句体n+1;
break;
}
示例:
Scanner sc = new Scanner(System.in);
int day = sc.nextInt();
switch (day) {
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
case 4:
System.out.println("星期四");
break;
case 5:
System.out.println("星期五");
break;
case 6:
System.out.println("星期六");
break;
case 7:
System.out.println("星期日");
break;
default:
System.out.println("输入数据有误");
break;
}
注意事项:
- 表达式类型只能是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循环
格式:
for (初始化语句; 条件判断语句; 条件控制语句) {
循环体语句;
}
示例:
for (int i = 0; i < 10; i++) {
System.out.print("第" + i + "次");
}
结果为:第0次第1次第2次第3次第4次第5次第6次第7次第8次第9次
注意事项
- 循环
{}中定义变量,在每一轮循环结束后,都会从内存中释放 - 循环
()中定义的变量,在整个循环结束后,都会从内存中释放 - 循环语句
()和{}之间不要写分号
水仙花数
水仙花数的个位、十位、百位的数字立方和等于原数
1231^3 + 2^3 + 3^3 = 1 + 8 + 27 = 3636 != 123不是水仙花数
3713^3 + 7 ^ 3 + 1^3 = 27 +343 + 1 = 371371 == 371是水仙花数
求所有100 ~ 999之间的所有水仙花数
public class Practice {
public static void main(String[] args) {
for (int i = 100; i < 1000; i++) {
int ge = i % 10;
int shi = i / 10 % 10;
int bai = i / 100;
int cnt = (int) (Math.pow(ge,3) + Math.pow(shi,3) + Math.pow(bai,3));
if (i == cnt) {
System.out.println(i + "是一个水仙花数");
}
}
}
}
循环嵌套
在循环体中,继续出现循环语句
示例:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.println(i + "---" + j);
}
}
while循环
格式:
while(判断语句) {
循环体语句;
控制语句;
}
示例:
int a = 0;
while (a < 10) {
System.out.println(a);
a++;
}
案例:
/*
世界最高山峰珠穆朗玛峰高度是:8848.86米 = 8848860毫米,
假如有一张足够大的纸,它的厚度是0.1毫米,
折多少次就会比珠穆朗玛峰高
*/
double peakHeight = 8848860.0;
double paperThickness = 0.1;
int cnt = 0;
while (paperThickness <= peakHeight) {
paperThickness = paperThickness * 2;
cnt++;
}
System.out.println(cnt); // 27
for和while的选择
- 功能上是完全一样的,for能解决的while也能解决,反之亦然
- 使用规范:知道循环次数,使用for;不知道循环次数建议使用while
do…while循环
格式:
初始化语句;
do {
循环体语句;
条件控制语句;
} while (循环条件);
示例:
int a = 20;
do {
System.out.println(a); // 20
a++;
} while (a < 10);
System.out.println(a); // 21
解释:与while不同(先判断,后执行),do…while即使最开始没有满足循环条件,也会执行一次do括号里的代码(先执行,后判断)
break、continue
- break:终止循环体内容的执行,也就是说结束当前的整个循环
- continue:跳过某次循环体内容的执行,继续下一次的执行
break示例:
int a = 0;
while (true) {
a++;
if (a == 99) { // 当a==99时终止循环
break;
}
}
System.out.println(a); // 99
continue示例:
int a = 0;
while (a < 50) {
a++;
if (a % 2 == 0) { // 碰到偶数跳过该次循环
continue;
}
System.out.println(a);
}
注意事项:
- 遇到循环嵌套时,break和continue操作的是内循环
- break只能在循环和switch中使用,continue只能在循环中进行使用
标号(循环体命名)
当希望break和continue操作外循环时,可以通过给外循环起名(标号),并在break或continue后指定循环体名称即可
示例:
lo:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (j == 2) {
break lo;
}
System.out.println(i + "---" + j);
}
}
lo是loop的缩写,也就是对外层循环起的名称
Random随机数
使用步骤:
- 导包:
import java.util.Random;
- 创建Random对象:
Random r = new Random();
- 生成随机数:
int num1 = r.nextInt(10);// 范围:0 ~ 9
案例:
import java.util.Random;
import java.util.Scanner;
public class Practice {
public static void main(String[] args) {
/*
产生一个1~100的随机数
用户键入一个数字,判断与目标数是否相等
如果不相等,则给出提示(猜大了或猜小了)
*/
Random r = new Random();
int n1 = r.nextInt(100) + 1;
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入一个1~100的数字:");
int n2 = sc.nextInt();
if (n2 < 1 || n2 > 100) {
System.out.println("注意范围是1 ~ 100哦");
}
if (n2 == n1) {
System.out.println("恭喜您,猜中了");
break;
} else if (n2 > n1) {
System.out.println("猜大了");
} else {
System.out.println("猜小了");
}
}
}
}
数组
数组定义
- 格式一:
数据类型[] 数组名 - 示例:
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增长
完整代码如下:
public class ArrayDemo01 {
public static void main(String[] args) {
int[] arr = {11,22,33,44,55};
System.out.println(arr[3]); // 44
arr[0] = 55;
System.out.println(arr[0]); // 55
}
}
数组遍历
- 数组遍历:依次访问数组中的每一个元素
- 本质:利用for循环访问数组中的元素
示例:
public class ArrayDemo02 {
public static void main(String[] args) {
int[] arr = {11,22,33,44,55,66,77,88,99};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
进阶用法:
public class ArrayDemo02 {
public static void main(String[] args) {
int[] arr = {11,22,33,44,55,66,77,88,99};
for (int n : arr) {
System.out.println(n);
}
}
}
由于数组是可迭代对象,所以可以直接使用
for(数据类型 变量名 : 数组名),也就是增强型for循环或者叫for-each循环
反转数组
案例:
public class ArrayReverse {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7,8,9,10};
reverse(arr);
for (int n : arr) {
System.out.println(n);
}
}
/*
public static int[] reverse(int[] arr) {
int[] tmp = new int[arr.length];
for (int i = arr.length - 1; i >= 0; i--) {
tmp[arr.length - 1 - i] = arr[i];
}
return tmp;
}
*/
public static void reverse(int[] arr) {
for (int i = 0; i < arr.length / 2; i++) {
int temp = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = temp;
}
}
}
- 第一种反转算法较为简单(从尾到头遍历),但是效率较低
- 第二种反转算法较为复杂(头尾交换),但是效率较高
- 最常用的是第二种写法
数组动态初始化
动态初始化:初始化时只指定数组长度,由系统为数组分配初始值
- 格式:
数据类型[] 数组名 = new 数据类型[数组长度]; - 示例:
int[] arr = new int[3];
案例:
public class ArrayDemo03 {
public static void main(String[] args) {
int[] arr = new int[10]; // 动态初始化
String[] sArr = new String[10];
boolean[] bArr = new boolean[10];
double[] dArr = new double[10];
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]); // 输出10次结果,都为0
System.out.println(sArr[i]); // 输出10次结果,都为null
System.out.println(bArr[i]); // 输出10次结果,都为false
System.out.println(dArr[i]); // 输出10次结果,都为0.0
}
}
}
动态数组初始化,其实就是将数组中的元素全部以默认值填充,长度由用户指定
数据类型 默认值 整数 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
完整代码:
public class ArrayDemo04 {
public static void main(String[] args) {
int[][] arr = {{1,2,3},{4,5,6},{7,8,9,10,11}};
System.out.println(arr[1][1]); // 5
}
}
二维数组遍历
示例:
public class ArrayDemo04 {
public static void main(String[] args) {
int[][] arr = {{1,2,3},{4,5,6},{7,8,9,10,11}};
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
// 1,2,3,4,5,6,7,8,9,10,11,
System.out.print(arr[i][j] + “,”);
}
}
}
}
常见异常
索引越界异常
- ArrayIndexOutOfBoundsException:当访问了数字中不存在的索引,就会引发索引越界异常
- 示例:
int[] a = {1,2,3}; a[5] = 15;
空指针异常
- NullPointerException:当引用数据类型被赋值为null后,地址的指向被切断,如果还继续访问堆内存数据,就会引发空指针异常
- 示例:
int[] arr = {1,2,3,4,5,6};
rr = null;
System.out.println(arr[0]);
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};