基础语法
一、基本数据类型
Java 有八大基本数据类型,它们分别是:byte、short、int、long、float、double、char、boolean,不同的数据类型有着不同的取值范围和内存占用大小。这些 类型 由 JVM 直接管理,存储在栈(Stack)内存中,效率极高。
整数和小数取值范围大小关系:double > float > long > int > short > byte
| 分类 | 关键字 | 位数 (bit) | 字节 (Byte) | 取值范围 | 默认值 | 快速记忆 |
|---|---|---|---|---|---|---|
| 整数 | byte | 8 | 1 | -128 ~ 127 | 0 | 极小整数 |
| short | 16 | 2 | -32,768 ~ 32,767 | 0 | 短整数 | |
| int | 32 | 4 | 约 ±21亿 (2³¹−1) | 0 | 默认整数类型 | |
| long | 64 | 8 | 约 ±9×10¹⁸ (2⁶³−1) | 0L | 大数据 / 时间戳 | |
| 浮点 | float | 32 | 4 | ±3.4E38 (有效位数 6~7 位) | 0.0f | 单精度 |
| double | 64 | 8 | ±1.7E308 (有效位数 15 位) | 0.0d | 默认浮点类型 | |
| 字符 | char | 16 | 2 | 0 ~ 65,535 (Unicode) | '\u0000' | 单个文字 / 符号 |
| 布尔 | boolean | 8* | 1* | true / false | false | 逻辑判断 |
💡 核心要点补充
后缀要求:
- long:赋值时必须加 L(如 long num = 100L;)。
- float:赋值时必须加 F(如 float f = 3.14F;),否则会被当作 double 处理导致编译报错。
精度损耗:float 和 double 采用的是 IEEE 754 标准,不能用于精确的货币计算(会出现 0.1+0.2 != 0.3 的情况)。精确计算请使用 java.math.BigDecimal。
Boolean 占用空间:在 JVM 规范中,单个 boolean 变量在编译后使用 int 代替(4字节),而 boolean 数组则会被编译成 byte 数组(1字节)。
为什么 String 不是基本类型?
八大基本数据类型是由 Java 虚拟机直接支持的,它们是为了解决最基本的存储和计算需求,效率更高,占用更少内存。String 属于引用类型,它本质是一个类(java.lang.String),对象的内存分配和管理由 Java 的垃圾回收机制负责。
基本类型追求的是极致的速度。如果字符串也做成基本类型,由于其长度不可控,JVM 很难在内存中预留固定空间,且字符串频繁的拼接、比较操作需要复杂的逻辑封装,这些只有通过“类”才能完美实现。
| 特性 | 基本数据类型 (e.g., int) | 引用类型 (e.g., String) |
|---|---|---|
| 存储位置 | 值直接存在 栈 (Stack) | 对象存在 堆 (Heap),栈里存地址 |
| 内存占用 | 固定且较小 | 随内容长度变化,较大 |
| 功能 | 仅能进行算术/逻辑运算 | 拥有丰富的方法(如 .length(), .substring()) |
| 本质 | 纯粹的数据单元 | Java 定义的一个类 (Class) |
二、运算符
各类编程语言中都有运算符,都包括算术运算符、自增自减运算符、赋值运算符、关系运算符、逻辑运算符、三元运算符、运算符优先级。
1. 算术运算符与类型提升
在 Java 中,运算不仅仅是数字相加,还涉及内存空间的转换。
- 隐式转换原则:取值范围小的和取值范围大的进行运算,小的会先提升为大的,再进行运算。
- 特殊规则 (必记): byte, short, char 在进行算术运算时,一律先自动提升为 int 再计算。
- 强制转换: 如果需要将大容量转回小容量,必须手动强转:byte c = (byte)(a + b);。
2. 自增自减运算符
| 语法 | 名称 | 规则 | 助记 |
|---|---|---|---|
| a++ | 后置自增 | 先取值参加运算,后自增 | 先用后加 |
| ++a | 前置自增 | 先自增,后取值参加运算 | 先加后用 |
3. 逻辑运算符
&& (短路与): 如果左边为 false,右边不再执行(因为结果注定是 false)。
|| (短路或): 如果左边为 true,右边不再执行(因为结果注定是 true)。
| 符号 | 作用 | 说明 |
|---|---|---|
| & | 逻辑与(且) | 左右都执行。全真才为真 |
| l | 逻辑或 | 左右都执行。全假才为假 |
| ^ | 逻辑异或 | 不同为 true,相同为 false |
| ! | 逻辑非 | 真变假,假变真 |
三、判断和循环
| 循环类型 | 最佳使用场景 | 核心特点 |
|---|---|---|
| for | 已知循环次数 | 初始化、条件、迭代逻辑集中在一起,结构紧凑。 |
| while | 未知循环次数 | 只要满足条件就执行(先判断后执行)。 |
| do...while | 至少执行一次 | 无论条件是否满足,先执行一次循环体。 |
| 增强 for | 遍历集合/数组 | 无需索引,语法最简洁(内部基于迭代器)。 |
/** if语句 */
if (flag) {}
/** switch语句 */
switch (flag) {
case 'xx':
break;
default:
break;
}
switch (flag) {
case 1 -> {}
default -> {}
}/** for循环 */
for (int i = 0; i < 5; i++) {
if (i == 3) {
// 跳过本次循环的剩余代码,直接开启下一次循环
continue;
// 彻底终结当前循环,跳出大括号
break;
}
System.out.println(i);
}
/** 循环嵌套与标号 */
outer: // 定义标号
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (j == 2) break outer; // 直接跳出外层的 outer 循环
}
}
// 增强for
Collection<String> coll = new ArrayList<>();
coll.add("A");
coll.add("B");
coll.add("C");
for (String s : coll) {
System.out.println(s);
}/** while循环 */
int num = 1;
while (num < 2) {
System.out.println("while");
num++;
}四、数组
数组是存储同种数据类型、固定长度的连续空间。数组容器在存储数据的时候,需要结合隐式转换考虑。
int类型的数组容器可存(byte、short、int、❌double、❌boolean)
double类型的数组容器可存(byte、short、int、long、float、double)
| 方式 | 语法示例 | 适用场景 |
|---|---|---|
| 静态初始化 | int[] arr = {1, 2, 3}; | 已知具体数据内容 |
| 动态初始化 | int[] arr = new int[5]; | 只知长度,数据后续动态存入 |
import java.util.Arrays;
int[] arr1 = {11, 12, 13};
String[] arr2 = {"张三", "李斯"};
double[] arr3 = {1.93, 1.78};
System.out.println(arr1[2]);
System.out.println(Arrays.toString(arr));
/** 数组遍历 */
// 方式 A: 标准 for 循环 (需要操作索引时使用)
for (int i = 0; i < arr1.length; i++) {
System.out.println("索引 " + i + " 的值: " + arr1[i]);
}
// 方式 B: 增强 for 循环 (仅需获取值时使用,更简洁)
for (int val : arr1) {
System.out.println(val);
}String[] arr = new String[10];
arr[0]="张三";
// 数组默认初始化值的规律
// 整数类型:默认初始化值e
// 小数类型:默认初始化值0.0
// 字符类型:默认初始化值'u0000'空格
// 布尔类型:默认初始化值 false
// 引用数据类型:默认初始化值nu1I五、集合
集合的长度可变。集合只能存储引用类型,基础类型存储需要进行包装类。
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
/**
* ArrayList<泛型> list = new ArrayList<>();
* 包装类:Integer可以存储int。Character存储字符
* 存储类:泛型 替换为 类名
*/
ArrayList<String> list = new ArrayList<>();
// 增
list.add("zeming");
list.add("bbb");
// 删
list.remove(1);
// 改
list.set(0, "哥哥");
// 查
String a = list.get(0);
int a1 = list.size();
System.out.println(list);
System.out.println(a);
System.out.println(a1);
}
}六、方法
public class Main {
public static void main(String[] args) {
playGame();
}
public static void playGame() {
System.out.println("这里是plyGame方法");
}
}public class Main {
public static void main(String[] args) {
playGame("张三", 25);
}
public static void playGame(String name, int age) {
System.out.println("这里是plyGame方法");
System.out.println("姓名:" + name);
System.out.println("年龄:" + age);
}
}public class Main {
public static void main(String[] args) {
int sum = getSum(1, 2, 3);
System.out.println(sum);
}
public static int getSum(int a, int b, int c) {
return a + b + c;
}
public static int[] copy(int[] arr, int from, int to) {
int[] temp = new int[to-from];
return temp;
}
}七、String 拓展
String 的核心特性是不可变性(Immutable)。一旦创建,其内容在内存中无法更改。
// 当使用双引号直接赋值时,系统会检查该字符串在串池中是否存在。
// 不存在:创建新的
// 存在:复用
String name = "asfsdffsf";
System.out.println(name);
String a = new String("sdfs");
System.out.println(a);
char[] chs = {'a', 'b', 'c'};
String b = new String(chs);
System.out.println(b);
/** 判断是否相等 */
String s1 = "abc";
String s2 = "Abc";
System.out.println(s1.equals(s2)); // 不忽略大小写StringBuilder sb = new StringBuilder("Zm");
System.out.println(sb.append("zzzzz")); // 添加元素
System.out.println(sb.reverse()); // 反转
// 再把 StringBuilder 变回字符串
String str = sb.toString();
System.out.println(str);/**
* public StringJoiner (间隔符号)
* public StringJoiner (间隔符号, 开始符号, 结束符号)
*/
import java.util.StringJoiner;
public class Main {
public static void main(String[] args) {
StringJoiner sj = new StringJoiner("---");
sj.add("sd").add("sdf");
System.out.println(sj.toString());
StringJoiner sj2 = new StringJoiner(",", "[", "]");
sj2.add("1").add("2");
System.out.println(sj2.toString());
}
}1. 内容修改神器:StringBuilder & StringJoiner
StringBuilder:极致的性能
- 特点: 像一个可以伸缩的抽屉,专门用来高效修改内容。
- 必会方法: append() (拼接), reverse() (反转), length() (长度)。
StringJoiner:优雅的格式化
- 特点: JDK 8 引入,专门解决“拼接数组/列表并加上前后缀”的场景。
- 优势: 不再需要手动判断 if (i != arr.length - 1) 来处理末尾的分隔符。
2. == 与 equals()
| 比较方式 | 基本数据类型 (int, double...) | 引用数据类型 (String, 数组...) |
|---|---|---|
| == | 比较的是 具体的值 | 比较的是 内存地址 |
| equals() | 不适用 | 比较的是 内容是否相同 (String 重写了此方法) |
3. 怎么选
| 场景 | 推荐工具 |
|---|---|
| 单纯定义一个固定名字或描述 | String |
| 在循环中大量拼接字符串,或进行字符串反转 | StringBuilder |
| 需要将多个元素拼接成类似 [1, 2, 3] 的格式 | StringJoiner |
小结
| 知识点 | 重点强调 | 容易忽视的 Bug |
|---|---|---|
| 数据类型 | long 加 L,float 加 F | 丢失后缀导致的编译错误 |
| 运算符 | && 和 || 是短路运算 | 误用 & / | 导致多余计算 |
| 数组 | 长度固定,索引从 0 开始 | ArrayIndexOutOfBoundsException 越界 |
| String | 字符串内容不可变 | 用 == 比较内容(务必用 .equals()) |
| 方法 | 基本类型传值,引用类型传地址 | 在方法内修改数组会影响原数组 |