九、java常用类

0 阅读6分钟

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 不可变性的影响

  1. 频繁拼接会产生大量垃圾对象 → 内存浪费、GC 压力大
  2. 线程安全(天生不可变)
  3. 适合作为 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):字符串转 int
  • valueOf(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

十、本章企业级坑总结(超级重要)

  1. String 不可变,循环拼接必须用 StringBuilder
  2. new String("abc") 创建 1~2 个对象
  3. 包装类 == 比较要注意缓存范围,一律用 equals
  4. 包装类为 null 时拆箱 NPE
  5. SimpleDateFormat 线程不安全,不能 static
  6. 金钱计算必须用 BigDecimal,且必须用字符串构造
  7. equals 重写必须同时重写 hashCode
  8. BigDecimal 除法必须指定舍入模式
  9. 字符串比较禁止用 ==,必须用 equals
  10. JDK8 时间类全面替代 Date,线程安全

十一、高频面试题(100%考)

  1. String 为什么不可变?底层结构?
  2. String、StringBuilder、StringBuffer 区别?
  3. == 和 equals 区别?
  4. Integer 缓存范围?为什么 128 用 == 不等?
  5. new String("abc") 创建几个对象?
  6. SimpleDateFormat 为什么线程不安全?
  7. BigDecimal 为什么能解决精度问题?
  8. 为什么重写 equals 必须重写 hashCode?
  9. String 常量池作用?位置变化?
  10. JDK8 时间类优势?