JAVA学习之JAVA基础

4 阅读17分钟

JAVA基础

1.标识符

1.1.什么是标识符

Java 标识符(Identifier)是程序员在代码中为类、方法、变量、包、接口、标签等自定义命名的符号。与关键字不同,标识符完全由开发者定义,但必须严格遵守 Java 的命名规则

1.2.标识符可以标识什么

变量(Variable),方法(Method),类(Class),接口(Interface),枚举(Enum),注解(Annotation),包(Package),类型参数(Type Parameter),类型名称(Type Name),常量(Constant)

1.3.命名规则

  1. 组成字符:只能由 字母(A-Z, a-z)、数字(0-9)、下划线(_)和 美元符号($)组成
  2. 首字符限制:不能以数字开头。必须以字母、_ 或 $ 开头。
  3. 不能是关键字:不能使用 Java 的关键字(如 class, public)和保留字(如 goto, const)作为标识符。
  4. 大小写敏感:MyClass、myclass、MYCLASS 是三个完全不同的标识符。
  5. 长度无上限:理论上没有长度限制,但应保持合理可读性。

1.4.标识符命名规范**(约定俗成)**

类型规范示例
包名全小写,单词间用 . 分隔,通常使用反向域名com.alibaba.fastjson
类名 / 接口名大驼峰(UpperCamelCase),名词或名词短语UserService, Serializable
方法名小驼峰(lowerCamelCase),动词或动宾短语getUserById(), calculateTotal()
变量名小驼峰,有意义的名称,避免单字母(循环变量除外)orderList, isActive
常量名全大写 + 下划线分隔MAX_RETRY_COUNT, DEFAULT_TIMEOUT
枚举值同常量,全大写+下划线PENDING, COMPLETED
泛型参数单个大写字母或有意义的大驼峰缩写T, E, K, V, Req

2.关键字

Java 关键字(Keywords)是 Java 语言中预定义的、具有特殊含义的保留字。它们全部为小写,不能用作变量名、类名、方法名等标识符

3.字面量

3.1.什么是字面量

Java 字面量(Literal)是指在源代码中直接书写的固定值。它们不需要通过变量或表达式计算,编译器在编译阶段就能确定其值和类型

3.2.Java中都有哪些字面量

  1. 整数字面量:100,-42
  2. 浮点字面量:3.14,3.14f
  3. 字符字面量:‘A’
  4. 字符串字面量:"Hello, World!"
  5. 布尔字面量:true,false
  6. null 字面量:null(唯一值)

4.变量

4.1.什么是变量

Java 变量是程序中用于存储数据值的命名内存空间。每个变量都有明确的类型、名称和作用域,且在使用前必须先声明

4.2.变量的分类

根据声明位置和生命周期,Java 变量分为三大类

类型声明位置生命周期默认值存储位置
局部变量方法/代码块/构造器内部方法调用开始 → 结束❌ 无默认值(必须手动初始化)栈(Stack)
成员变量(实例变量)类中、方法外,无 static对象创建 → 被GC回收✅ 有默认值堆(Heap)
静态变量(类变量)类中、方法外,有 static类加载 → 程序结束✅ 有默认值方法区/元空间

示例对比

public class VariableDemo {
    static int classVar = 10;      // 静态变量:属于类,所有实例共享
    int instanceVar;               // 实例变量:默认值为 0
    
    public void method() {
        int localVar = 5;          // 局部变量:必须初始化
        // int uninit;             // ❌ 编译错误:未初始化就使用
        System.out.println(localVar);
    }
}

4.3.基本数据类型与默认值

类型分类数据类型占用空间默认值 (成员变量)取值范围备注
整数型byte1 字节0-2⁷ ~ 2⁷-1 (-128 ~ 127)最小整型,适合节省内存的场景
short2 字节0-2¹⁵ ~ 2¹⁵-1 (-32,768 ~ 32,767)较少使用
int4 字节0-2³¹ ~ 2³¹-1 (-2,147,483,648 ~ 2,147,483,647)Java 中最常用的整型
long8 字节0L-2⁶³ ~ 2⁶³-1 (-9.2×10¹⁸ ~ 9.2×10¹⁸)字面量需加 L 后缀
浮点型float4 字节0.0f±1.4E-45 ~ ±3.4E+38(有效位数约 6~7 位)IEEE 754 单精度,字面量需加 F/f
double8 字节0.0d±4.9E-324 ~ ±1.7E+308(有效位数约 15~16 位)IEEE 754 双精度,默认浮点类型
字符型char2 字节'\u0000''\u0000' ~ '\uffff' (0 ~ 65,535)无符号,采用 UTF-16 编码单元
布尔型booleanJVM 实现相关false仅 true / false不直接对应数值,不可与整数互转

4.4.核心规则

  1. 先声明后使用:Java 不允许隐式声明,x = 10; 在未声明 x 时直接报错

  2. 局部变量无默认值:这是新手最常踩的坑。编译器会严格检查" definite assignment "(确定性赋值),未赋值的局部变量连读取都不允许

  3. 作用域限制

    -- 局部变量仅在 {} 内可见
    -- 同名变量不能在同一作用域内重复声明
    -- 内层块可以声明与外层同名的变量(遮蔽),但不推荐
    
  4. final 修饰符:final 变量只能赋值一次,之后不可修改。对于引用类型,final 仅保证引用不变,对象内容仍可修改

4.5.命名规范速查

场景规范正例反例
普通变量小驼峰,名词/形容词userName, isActiveUserName, user_name
常量全大写+下划线MAX_SIZE, DEFAULT_TIMEOUTmaxSize, Max_Size
循环变量单字母可接受i, j, k, row, colloopCounterVariable
布尔变量is/has/can/should 开头isValid, hasPermissionvalid, permissionFlag
集合变量复数或带类型后缀users, orderListdata, temp

4.6.常见陷阱与最佳实践

  1. Integer 缓存池:Integer a = 128; Integer b = 128; a == b 结果为 false!因为超出 [-128, 127] 缓存范围,每次 new 了新对象。比较包装类永远用 .equals()
  2. 浮点精度丢失:0.1 + 0.2 != 0.3。金融计算必须用 BigDecimal,禁止用 float/double
  3. 线程安全:实例变量和静态变量在多线程环境下不安全。局部变量天然线程安全(每个线程有自己的栈帧)
  4. 避免魔法值:不要直接在代码中写 if (status == 3),应定义为常量 ORDER_COMPLETED = 3 或使用枚举
  5. 最小作用域原则:变量尽量在最靠近使用的地方声明,减少认知负担和误用风险

5.二进制

5.1.二进制字面量表示

从 Java 7 开始,支持直接使用 0b 或 0B 前缀书写二进制整数

int bin = 0b1010;       // 十进制 10
long binLong = 0B1111_0000L; // 支持下划线分隔,增强可读性
byte b = (byte) 0b11111111;  // byte 需要强制转换(因为默认是 int)

5.2. 常用进制转换方法(Integer / Long 类)

功能方法示例
十进制 → 二进制字符串Integer.toBinaryString(n)toBinaryString(10) → "1010"
二进制字符串 → 十进制Integer.parseInt(s, 2)parseInt("1010", 2) → 10
指定宽度补零String.format("%32s", ...).replace(' ', '0')输出完整32位二进制
其他进制互转Integer.toString(n, radix)radix=8(八进制), 16(十六进制)

5.3. 位运算符(Bitwise Operators)

Java 提供完整的位操作,直接对二进制位进行处理:

运算符含义示例
&按位与0b1100 & 0b1010 = 0b1000
``按位或`0b11000b1010 = 0b1110`
^按位异或0b1100 ^ 0b1010 = 0b0110
~按位取反~0b1100 = ...11110011(补码)
<<左移(低位补0)0b0001 << 2 = 0b0100
>>算术右移(高位补符号位)-8 >> 1 = -4
>>>逻辑右移(高位补0)-8 >>> 1 = 2147483644

5.4.Java 整数的二进制存储:补码(Two's Complement)

  1. 正数:原码 = 反码 = 补码
  2. 负数:补码 = 反码 + 1
  3. 符号位:最高位为 1 表示负数,0 表示正数

6.数据类型

6.1.基本数据类型(8种)

基本类型直接存储值,分配在栈内存中,不是对象,没有方法。

类型关键字字节数取值范围默认值说明
整型byte1-128 ~ 1270节省空间,常用于IO流/网络传输
short2-32,768 ~ 32,7670较少使用
int4-2³¹ ~ 2³¹-1 (约±21亿)0最常用的整数类型
long8-2⁶³ ~ 2⁶³-10L时间戳、大计数等,字面量需加 L
浮点型float4IEEE 754 单精度0.0f字面量需加 F/f,精度约6-7位有效数字
double8IEEE 754 双精度0.0d默认浮点类型,精度约15-16位有效数字
字符型char20 ~ 65,535 (Unicode)'\u0000'无符号,用单引号 'A',支持中文
布尔型booleanJVM未明确规定true / falsefalse逻辑判断专用,不能与整数互转

6.2.引用数据类型

引用类型存储的是对象的内存地址(引用),对象本身在堆内存中。

类别示例说明
类(Class)String, ArrayList, 自定义类所有类的实例都是引用类型
接口(Interface)List, Runnable变量声明为接口,实际指向实现类对象
数组(Array)int[], String[]数组是对象,即使是基本类型数组
枚举(Enum)Color.RED本质是特殊的类
注解(Annotation)@Override元数据标记

6.3.自动装箱 / 拆箱(Autoboxing & Unboxing)

每个基本类型都有对应的包装类(Wrapper Class)

基本类型包装类缓存范围
byteByte-128 ~ 127
shortShort-128 ~ 127
intInteger-128 ~ 127 ⭐高频考点
longLong-128 ~ 127
floatFloat无缓存
doubleDouble无缓存
charCharacter0 ~ 127
booleanBooleanTRUE/FALSE 两个常量

6.4.如何选择数据类型

场景推荐类型原因
一般整数运算intCPU 原生字长,性能最优
时间戳/文件大小/IDlongint 范围不够
金额/汇率/税率BigDecimal避免浮点精度灾难
科学计算/图形学double精度和性能的平衡
大量标志位/状态压缩byte + 位运算节省内存
文本处理String / StringBuilder不可变安全 / 可变高效拼接
集合容器元素包装类泛型不支持基本类型

7.运算符

Java 运算符是执行数据操作的核心符号。为了便于理解和记忆,我们可以将其分为 算术、关系、逻辑、位运算、赋值、三元 六大类,并重点关注优先级和易错陷阱

7.1.算术运算符

用于基本的数学计算

运算符说明示例⚠️ 注意事项
+ - * /加减乘除10 / 3 = 3整数相除结果仍为整数(截断小数)
%取模(求余)10 % 3 = 1结果符号与被除数相同:-10 % 3 = -1
++ --自增/自减a++ vs ++a见下方详解
+字符串拼接"age:" + 25只要一侧是 String,另一侧自动调用 toString()
int a = 5;
int b = a++; // b=5, a=6 (先赋值给b,再自增)
int c = ++a; // c=7, a=7 (先自增,再赋值给c)

7.2.关系运算符(比较运算符)

结果为 boolean 类型。

运算符说明适用类型
== !=等于 / 不等于基本类型比值;引用类型比地址
> < >= <=大于/小于/大于等于/小于等于仅基本数值类型
instanceof判断对象是否为某类的实例仅引用类型
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2);      // false(不同堆对象)
System.out.println(s1.equals(s2)); // true(内容相同)

7.3.逻辑运算符

用于组合布尔表达式

运算符名称短路?说明
&&短路与✅左侧为 false 则不计算右侧
``短路或✅左侧为 true 则不计算右侧
&非短路与❌两侧都计算
``非短路或❌两侧都计算
!逻辑非-取反
^异或-两值不同为 true,相同为 false

7.4.位运算符

运算符含义典型用途
& ` ^ ~`与/或/异或/取反掩码、标志位、加密
<<左移乘以 2ⁿ
>>算术右移除以 2ⁿ(保留符号)
>>>逻辑右移无符号除法、哈希计算

7.5.赋值运算符

运算符等价形式⚠️ 隐藏行为
=基本赋值引用类型赋的是地址,不是拷贝
+= -= *= /= %=复合赋值自带隐式强制转换
&= `= ^= <<= >>= >>>=`位复合赋值同上
byte b = 10;
b += 200;    // ✅ 编译通过!等价于 b = (byte)(b + 200),结果溢出为 -46
b = b + 200; // ❌ 编译报错!int 不能自动转回 byte

7.6.三元运算符

唯一的三目运算符,是 if-else 的简洁替代

result = condition ? valueIfTrue : valueIfFalse;

7.7.运算符优先级(从高到低)

无需死记硬背,掌握核心原则即可

  1. 括号 () 优先级最高 → 不确定时就加括号
  2. 一元 > 算术 > 移位 > 关系 > 位 > 逻辑 > 三元 > 赋值
  3. 同级别从左到右(赋值运算符除外,从右到左)
// ❌ 难以阅读且容易出错
int r = a + b << 2 & 0xFF;

// ✅ 清晰明确
int r = ((a + b) << 2) & 0xFF;

7.8.实战避坑清单

#陷阱正确做法
1== 比较字符串/对象用 .equals(),且常量放前面:"hello".equals(var)
2整数除法丢精度至少一侧转 double:(double)a / b
3& 代替 && 判空始终用 && 做条件组合
4三元运算符拆箱 NPE确保两侧类型安全,或对包装类做空检查
5复合赋值静默溢出关键计算显式强转并校验范围
6浮点数比较不用 ==,用 Math.abs(a-b) < epsilon 或 BigDecimal

8.控制语句

8.1.选择语句(分支)

  1. if-else

    最基础的分支结构

    if (condition) {
        // ...
    } else if (anotherCondition) {
        // ...
    } else {
        // ...
    }
    
  2. switch

    根据表达式的值匹配多个分支

    特性传统 switch增强 switch (Java 14+)
    语法case X: + break;case X -> (无需 break)
    穿透问题❌ 容易忘记 break 导致 fall-through✅ 天然无穿透
    返回值❌ 不支持✅ 可作为表达式赋值
    多值匹配多个 case 重复写case A, B, C ->
    null 处理❌ NPE✅ case null -> (Java 17+)
    支持类型byte/short/int/char/String/enum同上 + sealed class 模式匹配(预览)

8.2.循环语句

  1. for 循环
    // 经典 for
    for (int i = 0; i < n; i++) { ... }
    
    // 增强 for (for-each)
    for (String s : list) { ... }
    
  2. while / do-while
    while (condition) { ... }      // 先判断后执行
    do { ... } while (condition); // 先执行后判断(至少执行一次)
    
  3. 循环性能对比
    场景推荐方式原因
    ArrayList 遍历经典 for / for-each随机访问 O(1),两者性能接近
    LinkedList 遍历for-each / Iterator避免 get(i) 的 O(n) 开销
    已知次数经典 for最直接
    流式处理/并行Stream API声明式 + 可并行化
    大数据量数值计算经典 for避免装箱和 Stream 开销

8.3.跳转语句

语句作用注意事项
break跳出当前循环/switch支持标签:break outerLoop;
continue跳过本次迭代,进入下一次支持标签:continue outerLoop;
return退出当前方法finally 块仍会执行
yieldswitch 表达式中返回值 (Java 14+)仅用于 switch 表达式内部

8.4.异常控制流(补充)

try-catch-finally 本质上也是一种控制语句,影响程序执行路径

try {
    // 可能异常的代码
} catch (IOException | SQLException e) { // 多异常捕获 (Java 7+)
    // 处理
} finally {
    // 必定执行(即使 try/catch 中有 return)
}

8.5.常见陷阱与最佳实践

#陷阱正确做法
1switch 忘记 break 导致穿透使用 Java 14+ -> 语法
2for-each 中修改集合用 Iterator.remove() 或 removeIf()
3if (obj == null) 放后面常量/null 放左侧:if (null == obj) 防误写成 =
4浮点数做循环条件for(double d=0; d!=1.0; d+=0.1) 可能死循环,改用整数计数
5嵌套过深(>3层)提取方法 / 提前 return / 策略模式重构
6switch 对 null 传参传统 switch 会 NPE;Java 17+ 可用 case null
7finally 中 return永远不要这样做,会吞掉 try/catch 中的异常和返回值

9.方法

Java 方法(Method)是类或对象的行为抽象,是代码复用和模块化的基本单元。以下是从基础语法到高级特性的系统性梳理

9.1.方法定义与核心要素

[修饰符] 返回类型 方法名(参数列表) [throws 异常列表] {
    // 方法体
}
要素说明⚠️ 关键点
修饰符public/protected/private/static/final/abstract/synchronized/native可组合使用,顺序无强制要求但建议按规范排列
返回类型任意类型或 voidvoid 方法不能用 return 返回值(但可用 return; 提前退出)
方法名标识符,遵循驼峰命名构造器不是方法(无返回类型、名称=类名)
参数列表(类型 名称, ...)Java 只有值传递,见下方详解
throws声明可能抛出的受检异常运行时异常(RuntimeException)无需声明

9.2.参数传递机制:只有值传递

这是 Java 最重要的概念之一,也是面试高频考点

参数类型传递的内容方法内修改的影响
基本类型值的副本❌ 不影响原始变量
引用类型引用的副本(地址拷贝)✅ 通过引用修改对象属性 → 影响原对象 ❌ 重新赋值引用本身 → 不影响原引用
// 经典示例
void modify(int num, StringBuilder sb) {
    num = 100;           // 修改副本,外部不变
    sb.append(" world"); // 通过副本引用操作同一对象,外部可见
    sb = new StringBuilder("new"); // 重新赋值副本引用,外部不受影响
}

9.3.方法重载 vs 重写

对比维度重载 (Overload)重写 (Override)
位置同一个类中父子类之间
方法名相同相同
参数列表必须不同必须相同
返回类型可以不同(不能仅靠返回类型区分)相同或是其子类型(协变返回)
访问修饰符无限制不能比父类更严格
绑定时机编译期静态绑定运行期动态绑定(多态)
注解无需建议加 @Override 防误写

9.4.特殊方法类型

构造器
  1. 名称与类名相同,无返回类型
  2. 不写则编译器自动生成无参构造器;写了有参构造器后,无参构造器不再自动生成
  3. 支持 this(...) 调用同类其他构造器,super(...) 调用父类构造器(必须是第一条语句)
static 方法
  1. 属于类而非实例,可通过类名直接调用
  2. 不能访问非静态成员、不能使用 this/super
  3. 不能被重写(只能被隐藏),不参与多态
  4. 典型用途:工具方法、工厂方法、main 入口
final 方法
  1. 不能被子类重写
  2. JVM 可进行内联优化(现代 JIT 已能自动判断,手动加 final 的性能收益有限)
abstract 方法
  1. 只有声明没有实现,以 ; 结尾
  2. 所在类必须是抽象类
  3. 子类必须实现,否则子类也必须是抽象类
native 方法
  1. 由 C/C++ 等本地语言实现(JNI)
  2. 无方法体,以 ; 结尾
  3. 典型:System.arraycopy(), Thread.sleep()
可变参数 (Varargs)
void print(String... args) { } // 本质是 String[] 数组
// 可变参数必须是最后一个参数;避免与重载混用导致歧义。

9.5.Java 新方法特性演进

版本特性说明
8Lambda / 方法引用list.forEach(System.out::println) 函数式编程
8default 方法接口中可提供默认实现,解决接口演化问题
9private 接口方法接口中抽取私有辅助方法,避免 default 方法代码重复
16+Record 紧凑构造器自动生成全参构造器/getter/equals/hashCode/toString
21未命名变量 _void process(int _, String name) 忽略不需要的参数

9.6.实战避坑清单

#陷阱正确做法
1重写时签名不一致变成重载始终加 @Override 注解
2父类构造器带参,子类忘记 super()显式调用 super(args)
3static 方法中用 thisstatic 方法无 this 上下文
4可变参数传 nullmethod(null) 可能匹配歧义,明确传 new Type[]{}
5方法过长 (>50行)拆分为多个职责单一的私有方法
6参数过多 (>4个)封装为参数对象或使用 Builder 模式
7在构造器中调用可重写方法子类字段尚未初始化,导致 NPE 或逻辑错误
8用 boolean 参数控制行为process(true) 可读性差,改用枚举或策略模式

9.7.方法设计原则速查

  1. 单一职责:一个方法只做一件事
  2. 最小权限:能用 private 就不用 protected,能用 protected 就不用 public
  3. 防御性编程:公开方法校验参数(Objects.requireNonNull()),私有方法可用断言
  4. 命名即文档:calculateTotalPrice() 优于 calc(),isValid() 优于 check()
  5. 避免副作用:查询方法不应修改状态,修改方法应有明确命名(如 set/add/remove)