java.lang 是 Java 语言的核心包,它包含了构成 Java 语言基础的类和接口。这个包是如此重要,以至于在编写 Java 代码时,其中的所有类和接口都会被自动导入 (implicitly imported),开发者无需使用 import 语句。java.lang 包定义了对象的根基、基本数据类型的封装、字符串处理、系统操作、线程管理以及异常处理等核心功能。

核心思想:java.lang 包定义了 Java 语言最基础、最核心的构建块,是所有 Java 程序的基石,提供对象模型、基本类型支持、字符串、并发、系统交互和异常处理等基础能力。


一、java.lang 包的重要性

java.lang 包是 Java 编程的起点和核心。其重要性体现在:

  1. 自动导入:无需 import java.lang.*,其中的所有类和接口都可直接使用。
  2. 对象模型的基础Object 类是所有类的父类。
  3. 基本数据类型的封装:提供了对应八种基本数据类型的包装类。
  4. 字符串处理:提供了 String, StringBuffer, StringBuilder 等核心字符串操作类。
  5. 运行时环境交互System, Runtime, Process 等类允许程序与操作系统和 JVM 进行交互。
  6. 并发编程基础Thread, Runnable 等为多线程编程提供了基础。
  7. 异常处理机制Throwable 及其子类构成了 Java 强大的异常处理体系。
  8. 反射机制入口Class 类是 Java 反射机制的基石。

二、java.lang 包中的核心类和接口

2.1 Object

  • 定义Object 是所有 Java 类的最终父类。每个类都直接或间接地继承自 Object 类。
  • 作用:提供了所有对象都应具备的基本行为,是 Java 对象模型的根基。
  • 常用方法
    • boolean equals(Object obj):比较两个对象是否相等。默认实现比较内存地址 (即 == 运算符)。通常需要根据业务逻辑重写。
    • int hashCode():返回对象的哈希码。与 equals() 约定:如果两个对象 equals 返回 true,则它们的 hashCode 也必须相等。
    • String toString():返回对象的字符串表示。默认返回 类名@哈希码的十六进制。建议重写以提供有意义的字符串描述。
    • Class<?> getClass():返回此 Object 的运行时类。这是反射的入口点。
    • void wait(), void wait(long timeout), void wait(long timeout, int nanos):在当前线程上等待,直到另一个线程调用此对象的 notify()notifyAll() 方法,或超时发生。必须在 synchronized 块内调用。
    • void notify():唤醒在此对象监视器上等待的单个线程。必须在 synchronized 块内调用。
    • void notifyAll():唤醒在此对象监视器上等待的所有线程。必须在 synchronized 块内调用。
    • protected Object clone():创建并返回此对象的副本。需要类实现 Cloneable 接口。
    • protected void finalize():当垃圾收集器确定不再有对该对象的引用时,由垃圾收集器调用。不推荐使用,因为其执行时机不确定且可能引入性能问题。

示例:Object 方法的重写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.util.Objects;

class Person {
private String name;
private int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

// 重写 toString() 提供有意义的描述
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}

// 重写 equals() 和 hashCode()
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}

@Override
public int hashCode() {
return Objects.hash(name, age);
}
}

public class ObjectDemo {
public static void main(String[] args) {
Person p1 = new Person("Alice", 30);
Person p2 = new Person("Alice", 30);
Person p3 = new Person("Bob", 25);

System.out.println("p1: " + p1); // 调用重写的 toString()
System.out.println("p1.getClass(): " + p1.getClass().getName()); // 获取运行时类名

System.out.println("p1.equals(p2): " + p1.equals(p2)); // true, 因为重写了 equals
System.out.println("p1.equals(p3): " + p1.equals(p3)); // false

System.out.println("p1.hashCode(): " + p1.hashCode());
System.out.println("p2.hashCode(): " + p2.hashCode()); // p1和p2哈希码相同
System.out.println("p3.hashCode(): " + p3.hashCode());
}
}

2.2 Class

  • 定义Class 类的实例代表正在运行的 Java 应用程序中的类和接口。每个加载到 JVM 中的类都有一个对应的 Class 对象。
  • 作用:是 Java 反射 (Reflection) 机制的入口。通过 Class 对象,可以在运行时获取类的构造器、方法、字段等信息,并动态创建对象、调用方法。
  • 获取 Class 对象的方式
    1. Object.getClass()对象实例.getClass()
    2. 类名.classMyClass.class
    3. Class.forName(String className)Class.forName("com.example.MyClass"),需要处理 ClassNotFoundException

示例:Class 类的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.lang.reflect.Method;

public class ClassDemo {
public static void main(String[] args) {
// 1. 通过对象实例获取 Class 对象
String str = "hello";
Class<?> cls1 = str.getClass();
System.out.println("cls1: " + cls1.getName());

// 2. 通过类名.class 获取 Class 对象
Class<?> cls2 = Integer.class;
System.out.println("cls2: " + cls2.getName());

// 3. 通过 Class.forName() 获取 Class 对象
try {
Class<?> cls3 = Class.forName("java.util.Date");
System.out.println("cls3: " + cls3.getName());

// 示例:使用反射获取方法并调用 (这里只是展示,实际中通常更复杂)
Object date = cls3.getDeclaredConstructor().newInstance(); // 创建 Date 实例
Method getTimeMethod = cls3.getMethod("getTime"); // 获取 getTime() 方法
long timestamp = (long) getTimeMethod.invoke(date); // 调用方法
System.out.println("Current timestamp (from Date.getTime() via Reflection): " + timestamp);

} catch (Exception e) {
e.printStackTrace();
}
}
}

2.3 String, StringBuffer, StringBuilder

这三个类都用于处理字符串,但它们在可变性、线程安全性和性能方面有所不同。

  • String

    • 不可变 (Immutable):一旦创建,其内容不能被改变。所有对 String 对象的修改操作 (如 concat(), substring()) 都会生成一个新的 String 对象。
    • 线程安全:由于不可变性,String 是天然线程安全的。
    • 性能:频繁修改字符串会创建大量新对象,导致性能开销和 GC 压力。
    • 字符串常量池:字面量字符串 ("abc") 会被存储在字符串常量池中,以实现内存共享。
  • StringBuffer

    • 可变 (Mutable):提供了 append(), insert(), delete() 等方法来修改其内容,而无需创建新对象。
    • 线程安全:所有公共方法都使用了 synchronized 关键字进行同步,因此是线程安全的。
    • 性能:在多线程环境下,性能开销略高,但在需要频繁修改字符串的场景下优于 String
  • StringBuilder

    • 可变 (Mutable):与 StringBuffer 类似,提供可变字符串操作。
    • 非线程安全:方法没有同步,因此在单线程环境下性能优于 StringBuffer
    • 性能:在单线程环境下需要频繁修改字符串时,是最佳选择。

选择建议

  • String:适用于字符串内容不会或很少变化的场景。
  • StringBuilder:适用于单线程环境下,需要频繁对字符串进行修改的场景。
  • StringBuffer:适用于多线程环境下,需要频繁对字符串进行修改的场景。

示例:字符串操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class StringBuildersDemo {
public static void main(String[] args) {
// String 的不可变性
String s1 = "Hello";
String s2 = s1 + " World"; // s1 内容不变,s2 是新对象
System.out.println("s1: " + s1); // Hello
System.out.println("s2: " + s2); // Hello World

// StringBuilder 的可变性 (单线程高效)
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ").append("Java");
sb.insert(6, "Beautiful "); // 在第6个字符后插入
System.out.println("StringBuilder: " + sb); // Hello Beautiful Java

// StringBuffer 的可变性和线程安全 (多线程安全,性能略低)
StringBuffer sbf = new StringBuffer();
sbf.append("Concurrency");
sbf.append(" ").append("is");
sbf.append(" ").append("fun.");
System.out.println("StringBuffer: " + sbf); // Concurrency is fun.
}
}

2.4 包装类 (Wrapper Classes)

Java 为八种基本数据类型提供了对应的包装类,用于将基本数据类型封装成对象,以便进行更复杂的操作,或在需要对象的地方使用 (如集合类)。

基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
boolean Boolean
char Character
void Void (特殊,无实例)
  • 作用
    • 作为基本数据类型和对象之间的桥梁。
    • 在集合框架 (ArrayList, HashMap 等) 中存储基本数据类型的值。
    • 提供了处理基本数据类型值的实用方法 (如字符串转换、解析)。
  • 自动装箱 (Autoboxing) 与自动拆箱 (Unboxing)
    • Java 5 引入的特性,允许基本数据类型和其对应的包装类之间自动转换。
    • 自动装箱:将基本数据类型自动转换为其包装类对象 (例如 intInteger)。
    • 自动拆箱:将包装类对象自动转换为其基本数据类型 (例如 Integerint)。

示例:包装类与自动装箱/拆箱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class WrapperClassDemo {
public static void main(String[] args) {
// 自动装箱
Integer i = 100; // int -> Integer
Double d = 3.14; // double -> Double
Boolean b = true; // boolean -> Boolean

System.out.println("Integer i: " + i);
System.out.println("Double d: " + d);
System.out.println("Boolean b: " + b);

// 自动拆箱
int intValue = i; // Integer -> int
double doubleValue = d; // Double -> double

System.out.println("int value: " + intValue);
System.out.println("double value: " + doubleValue);

// 包装类提供的方法
String strNum = "123";
int parsedInt = Integer.parseInt(strNum); // 字符串转 int
System.out.println("Parsed int: " + parsedInt);

String binaryStr = Integer.toBinaryString(10); // int 转二进制字符串
System.out.println("Binary of 10: " + binaryStr);
}
}

2.5 System

  • 定义:一个提供访问系统资源的 final 静态工具类。
  • 作用:提供了标准输入输出流、加载库、复制数组、获取系统时间、退出 JVM 等静态方法和字段。
  • 常用成员
    • static InputStream in:标准输入流 (通常是键盘)。
    • static PrintStream out:标准输出流 (通常是控制台)。
    • static PrintStream err:标准错误输出流 (通常是控制台)。
    • static long currentTimeMillis():返回当前时间的毫秒表示。
    • static long nanoTime():返回当前时间的纳秒表示 (用于精确测量时间间隔)。
    • static void exit(int status):终止当前正在运行的 Java 虚拟机。status 为非零表示异常退出。
    • static Properties getProperties():获取所有系统属性。
    • static String getProperty(String key):获取指定键的系统属性值。
    • static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):高效地复制数组。

示例:System 类的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.util.Properties;

public class SystemDemo {
public static void main(String[] args) {
// 标准输出
System.out.println("Hello from System.out!");
// 标准错误输出
System.err.println("This is an error message.");

// 获取当前时间戳
long startTime = System.currentTimeMillis();
System.out.println("Start time (ms): " + startTime);

// 获取系统属性
String javaVersion = System.getProperty("java.version");
String osName = System.getProperty("os.name");
System.out.println("Java Version: " + javaVersion);
System.out.println("OS Name: " + osName);

// 复制数组
int[] source = {1, 2, 3, 4, 5};
int[] destination = new int[5];
System.arraycopy(source, 0, destination, 0, source.length);
System.out.print("Copied array: ");
for (int i : destination) {
System.out.print(i + " ");
}
System.out.println();

// 模拟程序退出
// System.exit(0); // 正常退出
// System.exit(1); // 异常退出
}
}

2.6 Thread 类与 Runnable 接口

  • Thread
    • 定义:代表程序中的一个执行线程。
    • 作用:可以直接创建 Thread 对象来创建线程,并重写其 run() 方法来定义线程的执行逻辑。
  • Runnable 接口
    • 定义:一个函数式接口,包含一个 void run() 方法。
    • 作用:用于定义线程的执行逻辑。通过实现 Runnable 接口,可以将线程的执行逻辑与线程对象本身解耦,更灵活地创建线程。

创建线程的两种方式

  1. 继承 Thread
    1
    2
    3
    4
    5
    6
    7
    class MyThread extends Thread {
    @Override
    public void run() {
    System.out.println("Thread extending Thread is running.");
    }
    }
    // 使用:new MyThread().start();
  2. 实现 Runnable 接口 (推荐,更灵活,可避免单继承限制):
    1
    2
    3
    4
    5
    6
    7
    class MyRunnable implements Runnable {
    @Override
    public void run() {
    System.out.println("Thread implementing Runnable is running.");
    }
    }
    // 使用:new Thread(new MyRunnable()).start();

示例:线程创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class ThreadDemo {
public static void main(String[] args) {
// 方式一:继承 Thread 类
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("Thread A: " + i);
try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
}
MyThread threadA = new MyThread();
threadA.start(); // 启动线程

// 方式二:实现 Runnable 接口 (常用 Lambda 表达式)
Runnable myRunnable = () -> {
for (int i = 0; i < 3; i++) {
System.out.println("Thread B: " + i);
try { Thread.sleep(150); } catch (InterruptedException e) { e.printStackTrace(); }
}
};
Thread threadB = new Thread(myRunnable);
threadB.start(); // 启动线程

System.out.println("Main thread finished.");
}
}

2.7 Throwable 类及其子类

  • 定义Throwable 是所有错误 (Error) 和异常 (Exception) 的超类。只有当对象是 Throwable 的实例 (或子类实例) 时,才能通过 throw 语句抛出。
  • 作用:构成了 Java 强大的异常处理机制,允许程序在运行时报告和处理错误。

Throwable 的子类层次结构

  1. Error
    • 定义:表示应用程序无法处理的严重问题。通常是 JVM 内部错误或资源耗尽等。
    • 特点:非受检异常 (Unchecked Exception)。程序不应尝试捕获或处理 Error
    • 常见示例OutOfMemoryError, StackOverflowError
  2. Exception
    • 定义:表示应用程序可以捕获和处理的异常情况。
    • 特点
      • 受检异常 (Checked Exception):编译器会强制要求捕获 (try-catch) 或声明抛出 (throws)。例如 IOException, SQLException
      • 非受检异常 (Unchecked Exception):继承自 RuntimeException 的异常。编译器不会强制处理。
      • 常见示例NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException (非受检);IOException (受检)。

示例:异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ExceptionDemo {
public static void main(String[] args) {
// 运行时异常 (非受检异常) 示例
try {
String s = null;
System.out.println(s.length()); // NullPointerException
} catch (NullPointerException e) {
System.err.println("Caught RuntimeException: " + e.getMessage());
}

try {
int[] arr = new int[5];
System.out.println(arr[10]); // ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println("Caught RuntimeException: " + e.getMessage());
}

// 受检异常 示例 (FileNotFoundException 是 IOException 的子类)
FileInputStream fis = null;
try {
fis = new FileInputStream("nonexistent.txt"); // 这里会抛出 FileNotFoundException
int data = fis.read();
System.out.println("Read data: " + data);
} catch (FileNotFoundException e) {
System.err.println("Caught Checked Exception (File not found): " + e.getMessage());
} catch (IOException e) { // 更通用的 IOException
System.err.println("Caught Checked Exception (IO error): " + e.getMessage());
} finally {
if (fis != null) {
try {
fis.close(); // 确保流被关闭
} catch (IOException e) {
System.err.println("Error closing file: " + e.getMessage());
}
}
}

// Java 7+ try-with-resources 自动关闭资源,推荐使用
try (FileInputStream autoFis = new FileInputStream("nonexistent.txt")) {
int data = autoFis.read();
System.out.println("Read data with auto-close: " + data);
} catch (IOException e) {
System.err.println("Caught Checked Exception with try-with-resources: " + e.getMessage());
}
}
}

2.8 其他重要类和接口

  • Enum:所有枚举类型的公共基类。
  • Math / StrictMath:提供了各种数学函数,如 abs, sqrt, pow, random 等。StrictMath 保证跨平台结果一致性。
  • Comparable 接口:定义了对象的自然排序方式,包含 int compareTo(T o) 方法。
  • CharSequence 接口:表示一个字符序列,String, StringBuffer, StringBuilder 都实现了此接口。
  • Runtime:每个 Java 应用程序都有一个 Runtime 类实例,允许应用程序与运行它的环境进行交互,如执行外部命令 (exec())。
  • ProcessRuntime.exec() 方法返回一个 Process 对象,代表一个外部进程。
  • Void:一个不可实例化的占位符类,用于表示 void 类型,主要用于反射机制。
  • 核心注解@Override (表明方法重写)、@Deprecated (标记不推荐使用)、@SuppressWarnings (抑制编译器警告)。

三、总结

java.lang 包是 Java 语言的基石,它提供了构建任何 Java 应用程序所必需的最基本和最核心的功能。从 Object 类奠定的面向对象基础,到 String 提供的强大字符串处理,再到 ThreadThrowable 带来的并发和健壮性,以及 SystemRuntime 对系统资源的访问,理解 java.lang 包是深入学习 Java 的第一步,也是编写高质量、高效 Java 代码的关键。由于其重要性,JVM 会自动导入此包,使得这些核心类和接口始终触手可及。