对JVM平台来说,java.lang包中的类至关重要,因为这个包中的很多类我们都经常用到,如:

  • Object类(java.lang.Object);
  • String类(java.lang.String);
  • 基本数据类型包装类(java.lang包中的Integer、Long、Short、Char、Float和Double);
  • 异常和错误(java.lang.Exception和java.lang.Error)。

下图是这些类之间的层级关系:

列出java.lang中所有的类 java.lang包中的类_JVM

Object类

java.lang包中的Object类是其他所有类的基类;在JVM中,只有它没有父类。在Java语言中,没有显式地继承其他类的类都隐式地继承java.lang.Object类。

  • Object类的重要方法
    java.lang.Object类中最常用的方法如下表所示

方法名

返回类型

描述

toString()

String

返回对象的文本描述

equals(Object object)

boolean

指出传入的对象是否与当前对象相等,它使用多种规则来判断相等性

hashCode()

int

计算当前对象的散列值

  • Object(以及每个JVM对象)提供的重要方法之一是toString(),它返回当前对象实例的文本描述。
  • Oracle提供的默认实现是返回全限定类名以及十六进制格式的hashCode()结果,但建议在自定义类中重写这个方法,以提供更易于理解的描述。
  • 集合API大量地使用了方法equals()和hashCode()。
  • 有关java.lang.Object类的完整方法列表,请参阅API文档。

String类(java.lang.String)

java.lang.String类表示JVM中的字符串。这是一种不可修改的对象,这意味着修改String对象时不会影响原始对象,而是生成一个包含修改后内容的新字符串。字符串在内部都是使用UTF-16编码存储的。

基本类型包装器类(java.lang包中的Integer、Long、Short、Char、Float、Double类)

并非所有的Java API都能够使用JVM的内置基本数据类型。如果需要的是基本类型包装类,而你传递的是基本数据类型变量,编译器将自动创建指定包装类的实例。反之亦然,即在需要的是基本数据类型变量,而你传递的是包装类对象时,编译器将把包装类对象的值赋给基本数据类型变量。这个过程被称为自动装箱(autoboxing)。

  • 自动装箱示例
    下面的代码将一个基本类型int值赋给一个java.lang.Integer引用变量:
int primitiveInt = 42;
Integer wrappedInteger = primitiveInt;

这将创建一个包装了int值42的Integer对象,与显式地创建一个Integer实例等效:

Integer wrappedInteger = new Integer(42);

下面的代码将两个Integer实例传递给一个将两个int值作为参数的API,结果符合预期:

System.out.println("Hello world".substring(new Integer(0),
                     new Integer(5)));

这将打印Hello。

异常和错误(java.lang.Exception和java.lang.Error)

JVM开发人员必须知道JVM是如何管理运行阶段错误的。鉴于所有的语言都有自己的运行阶段错误处理机制,这里不介绍错误是如何处理的,而只说说发生运行阶段错误时的情况。

在方法中发生运行阶段错误时,将创建并引发一个异常或Error对象。在Java语言中,这是使用关键字throw实现的。下面是一个引发通用异常Exception的示例:

throw new Exception("Oops!");

Java有很多继承Exception或Error类的内置类。创建自定义异常类时,应考虑可重用哪个既有的异常类。例如,如果方法要求传入的引用不能为空,应在传入的参数为空时引发异常java.lang.NullPointerException;所有Java API在用户将空引用传递给不支持它的方法时都这样做。

注意:如果你仔细看了文章开头的类层级关系图,将发现Exception和Error都继承了Throwable类。Throwable是可引发的对象,但通常使用Exception和Error的子类,因为它们使用起来更方便。

  • Exception和Error类的不同之处如下。
    在程序很可能能够妥善地处理错误并继续运行时引发异常。
    发现根本没有想到的问题时引发错误。很多错误都是由JVM本身引发的。
    异常或错误(以下简称异常)被引发时,JVM将查看引发异常的方法。如果它包含能够处理错误的错误处理程序,就把控制权交给错误处理程序。如果这个方法不能处理任何错误(或当前错误),就检查方法调用方是否包含错误处理程序。这个过程将不断重复,直到找到能够处理当前错误且不引发新错误的方法,或者进入第一个方法调用。在第二种情况下,JVM实例将崩溃并生成类似于下面的栈跟踪:
Exception in thread "main" java.lang.Exception: Oops 
 at ExceptionDemo.method3(ExceptionDemo.java:37)
 at ExceptionDemo.method2(ExceptionDemo.java:33)
 at ExceptionDemo.method1(ExceptionDemo.java:29)
 at ExceptionDemo.main(ExceptionDemo.java:25)

很多语言都在生成的Java字节码中包含源代码文件名和行号,这样可以在栈跟踪中包含源代码行号,让栈跟踪更容易理解。
Java有严格的异常引发规则,因此并非每个类都能够引发所有的异常;