Java 常用类 极度详细完整版
本章核心说明
Java 常用类是开发每天都在用的基础 API,重点包含:
- Object(所有类的父类)
- String(字符串,面试重灾区)
- StringBuilder / StringBuffer(字符串拼接)
- 包装类(8 大基本类型包装类、自动装箱拆箱)
- Math / Random / System
- BigDecimal(解决浮点运算精度丢失,企业必用)
- Date / SimpleDateFormat / LocalDateTime(时间类)
所有内容均包含:底层结构 + 常用方法 + 执行原理 + 企业坑 + 面试题
一、java.lang.Object(所有类的顶级父类)
Java 中所有类默认直接或间接继承 Object,即使不写 extends Object 也成立。
1. 核心方法(必须全部掌握)
1.1 public String toString()
- 默认返回:
类名@十六进制哈希值 - 意义:用于打印对象时展示信息
- 企业规范:所有实体类必须重写 toString
1.2 public boolean equals(Object obj)
- 默认逻辑:直接比较
==,即比较对象地址 - String、Integer、BigDecimal 等都重写了 equals,用于比较内容
- equals 规范(自反、对称、传递、一致、非空)
1.3 public int hashCode()
- 返回对象的哈希码值(int)
- 规范:
- equals 相等 → hashCode 必须相等
- hashCode 相等 → equals 不一定相等
- 不重写 hashCode 直接用 HashSet/HashMap 会出 BUG
1.4 protected Object clone() throws CloneNotSupportedException
- 对象克隆(浅克隆)
- 必须实现
Cloneable接口(标记接口) - 浅克隆:基本类型复制值,引用类型复制地址
1.5 public final Class<?> getClass()
- 获取对象的运行时类对象(Class 类型)
- 用于反射
1.6 protected void finalize()
- 垃圾回收前调用
- 不推荐使用,不确定执行时间,企业几乎不用
1.7 public final void wait() / notify() / notifyAll()
- 线程等待/唤醒
- 必须在
synchronized代码块中使用
2. == vs equals(企业高频坑)
- ==
- 基本类型:比较值
- 引用类型:比较内存地址
- equals
- 未重写:同 ==
- 重写后:比较内容(如 String)
坑:
Integer a = 128;
Integer b = 128;
a == b; // false(超过缓存范围)
a.equals(b); // true
二、java.lang.String(最常用、面试最多)
1. 底层本质
- String 是不可变字符序列
- JDK8 底层:
private final char[] value - JDK9+ 底层:
private final byte[] value + coder(节省空间) - 不可变:一旦创建,字符串内容无法修改,所有修改都会产生新对象
2. String 内存分配(核心)
2.1 字符串常量池(String Pool)
- 位于方法区/堆中(JDK7+ 移到堆)
- 作用:共享字符串,节省内存
- 字面量创建会进入常量池
2.2 创建方式对比
// 1. 字面量:进入常量池,复用对象
String s1 = "abc";
// 2. new:一定在堆中创建新对象,可能指向常量池数据
String s2 = new String("abc");
s1 == s2 → false s1.equals(s2) → true
3. 常用方法(全)
equals()/equalsIgnoreCase():比较内容length():长度charAt(int index):获取指定位置字符indexOf(String str):查找子串位置substring(int begin, int end):截取(左闭右开)replace(char old, char new):替换split(String regex):分割trim():去除首尾空格toUpperCase()/toLowerCase():大小写startsWith()/endsWith():判断开头结尾toCharArray():转 char 数组
4. String 不可变性的影响
- 频繁拼接会产生大量垃圾对象 → 内存浪费、GC 压力大
- 线程安全(天生不可变)
- 适合作为 HashMap key(安全稳定)
5. 企业级巨坑
坑 1:使用 String 做大量循环拼接
String s = "";
for (int i=0; i<10000; i++) {
s += i;
}
- 每次循环创建新 String 对象
- 性能极差,OOM 风险
- 必须用 StringBuilder
坑 2:使用 substring 导致内存泄漏(JDK7 之前)
旧版 substring 会复用原数组,大字符串截取后无法释放,导致内存泄漏 JDK7+ 已修复,会复制新数组
坑 3:String 不可变被误解
String s = "a";
s = "b"; // 不是修改对象,是改变引用指向
坑 4:使用 == 比较字符串
业务中 99% 应该用 equals
三、StringBuilder & StringBuffer
1. 底层
- 可变字符序列
- 底层
char[](JDK8),没有 final,可扩容 - 默认容量 16,满了自动
2*旧容量+2
2. 区别(必考)
- StringBuilder
- JDK5
- 线程不安全
- 速度快
- 开发 99% 场景使用
- StringBuffer
- JDK1.0
- 线程安全(方法带 synchronized)
- 速度慢
- 多线程共享变量才用
3. 常用方法
append():追加(最常用)insert():插入delete():删除reverse():反转toString():转回 String
4. 企业规范
字符串拼接、循环拼接、动态构建字符串,一律使用 StringBuilder
四、8 大基本类型包装类
1. 对应关系
- byte → Byte
- short → Short
- int → Integer
- long → Long
- float → Float
- double → Double
- char → Character
- boolean → Boolean
2. 自动装箱 / 拆箱(JDK5+)
- 装箱:基本 → 包装
Integer a = 10;// 底层Integer.valueOf(10) - 拆箱:包装 → 基本
int b = a;// 底层a.intValue()
3. 包装类缓存池(企业坑)
- Integer:默认缓存
[-128, 127] - Long、Byte、Short:同样缓存 -128~127
- Boolean:缓存 TRUE/FALSE
- Character:缓存 0~127
坑:
Integer a = 127;
Integer b = 127;
a == b → true
Integer c = 128;
Integer d = 128;
c == d → false
4. 常用方法
parseInt(String):字符串转 intvalueOf(int):装箱toString():转字符串MAX_VALUE/MIN_VALUE
5. 企业坑
- 包装类是引用类型,可能为 null,拆箱时 NPE
Integer a = null;
int b = a; // 空指针!
五、java.math.BigDecimal(企业金钱计算必用)
1. 为什么要用
float、double 运算会精度丢失:
0.1 + 0.2 = 0.30000000000000004
金融、金额计算绝对禁止使用 double
2. 创建方式(坑点)
// 错误!依然精度丢失
BigDecimal a = new BigDecimal(0.1);
// 正确!使用字符串构造
BigDecimal b = new BigDecimal("0.1");
3. 常用方法
add():加subtract():减multiply():乘divide():除(必须指定舍入模式,否则无限小数抛异常)setScale(2, RoundingMode.HALF_UP):保留两位小数,四舍五入
4. 企业巨坑
divide 除不尽时直接抛出 ArithmeticException
必须指定舍入模式:
divide(bd, 2, RoundingMode.HALF_UP);
六、java.util.Date & 时间类
1. Date(过时但仍大量使用)
- 表示特定时间戳
- 很多方法已废弃(如 getYear())
2. SimpleDateFormat(线程不安全!)
大坑:
- 类内有
Calendar对象,多线程共用会导致时间解析错误 - 禁止定义为 static 全局变量
正确用法:方法内局部变量
3. JDK8 全新时间类(企业推荐)
LocalDate:日期LocalTime:时间LocalDateTime:日期+时间DateTimeFormatter:线程安全格式化工具Instant:时间戳
优势:
- 不可变
- 线程安全
- API 清晰
- 无性能问题
七、java.lang.Math
Math.abs():绝对值Math.sqrt():平方根Math.pow(a,b):a 的 b 次方Math.random():[0,1) 随机数Math.round():四舍五入Math.ceil():向上取整Math.floor():向下取整
八、java.util.Random
生成随机数:
Random r = new Random();
r.nextInt(10); // 0~9
多线程下推荐 ThreadLocalRandom 性能更高
九、java.lang.System
System.out:标准输出System.err:错误输出System.in:输入System.currentTimeMillis():获取当前时间戳(常用)System.arraycopy():高效数组复制System.gc():建议 GC(不一定执行)System.exit(0):退出 JVM
十、本章企业级坑总结(超级重要)
- String 不可变,循环拼接必须用 StringBuilder
- new String("abc") 创建 1~2 个对象
- 包装类 == 比较要注意缓存范围,一律用 equals
- 包装类为 null 时拆箱 NPE
- SimpleDateFormat 线程不安全,不能 static
- 金钱计算必须用 BigDecimal,且必须用字符串构造
- equals 重写必须同时重写 hashCode
- BigDecimal 除法必须指定舍入模式
- 字符串比较禁止用 ==,必须用 equals
- JDK8 时间类全面替代 Date,线程安全
十一、高频面试题(100%考)
- String 为什么不可变?底层结构?
- String、StringBuilder、StringBuffer 区别?
- == 和 equals 区别?
- Integer 缓存范围?为什么 128 用 == 不等?
- new String("abc") 创建几个对象?
- SimpleDateFormat 为什么线程不安全?
- BigDecimal 为什么能解决精度问题?
- 为什么重写 equals 必须重写 hashCode?
- String 常量池作用?位置变化?
- JDK8 时间类优势?