第1章 Java体系结构介绍
Java技术核心:Java虚拟机
Java:安全(先天防bug的设计、内存)、健壮、平台无关、网络无关(底层结构上,对象序列化和RMI为分布式系统中各个部分共享对象提供了基础)
1.3 体系机构
Java体系结构中的四个技术:
Java程序设计语言
Java class文件格式
Java应用编程接口API
Java虚拟机
Java虚拟机和Java API一起组成了Java平台
1.3.1 Java虚拟机
Java面向网络的核心是Java虚拟机:平台无关性、安全性和网络移动性
Java虚拟机是一台抽象的计算机,其规范定义了每个Java虚拟机都必须实现的特性,但为每个特定实现都留下了很多选择。
Java虚拟机的主要任务是装载class文件并执行其中的字节码。Java虚拟机包含一个类装载器,它可以从程序和API中装在class文件。Java API中只有程序执行时需要的那些类才会被装载,字节码由执行引擎执行,不同Java虚拟机中的执行引擎实现可能不同。
执行引擎:一次性解释字节码,即时编译器(执行速度快、消耗内存多),自适应优化器(监视运行中程序的活动,记录使用最频繁的代码。程序运行时,虚拟机只把活动最频繁的代码编译为本地代码,可使Java虚拟机在80%~90%的时间内执行被优化过的本地代码),硬件芯片构成的虚拟机(使用本地方法执行Java字节码,这种执行引擎实际上内嵌在芯片里)。
当Java虚拟机是由主机操作系统上的软件实现的时候,Java程序通过调用本地方法(native method)和主机交互。Java中的两种方法:Java方法和本地方法。本地方法由其他语言(如C、C++)编写,编译成和处理器相关的机器代码。本地方法保存在动态链接库中,格式是各个平台专有的。Java方法是平台无关的,但本地方法是本地相关的。运行中的Java程序调用本地方法时,虚拟机装在包含这个本地方法的动态库并调用这个方法。本地方法是联系Java程序和底层主机操作系统的连接方法。
通过本地方法,Java程序可以直接访问底层操作系统的资源,程序变为平台相关的。
1.3.2 类装载器的体系结构
在Java虚拟机中存在着多个类装载器,Java虚拟机拥有灵活的类装载器体系结构从而使Java应用程序得以用自定义的方式来实现类的装载。
一个Java应用程序可以使用两种类装载器:启动(bootstrap)装载器和用户定义的类装载器。启动类装载器(系统中唯一)是Java虚拟机实现的一部分。启动类装载器通常使用某种默认方式从本地磁盘中装载类,包括Java API的类(启动类装载器也称为原始类装载器、系统类装载器、默认类装载器)。
Java应用程序能够在运行时安装用户自定义的类装载器,这种类装载器能够使用自定义的方式来装载类(如从网络下载class文件)。尽管启动类装载器是虚拟机实现的本质部分,而用户定义的类装载器不是,但用户定义的类装载器能够使用Java编写,能够被编译为class文件,能够被虚拟机装载,像其他对象一样实例化。它们实际上只是运行中的Java应用程序可执行代码的一部分。
由于有用户定义类装载器,所有不必在编译的时候就知道运行中的Java应用程序中最终会加入的所有的类。用户定义的类装载器使得在运行时扩展Java应用程序成为可能。
每一个类被装载的时候,Java虚拟机都监视这个类,看它到底是本启动类装载器还是被用户自定义类装载器装载。当被装载的类应用了另外一个类时,虚拟机就会使用装载第一个类的装载器装载被应用的类。由于Java虚拟机采用这种方式进行类的装载,所以被装载的类默认情况下只能看到被同一个类装载器装载的其他类。通过这种方法,Java的体系结构允许在一个Java应用程序中建立多个命名空间。运行时的Java程序中的每一个类装载器都有它自己的命名空间。
一个Java应用程序能够从同一个类或者多个类中实例化多个用户定义的类装载器。因此,需要多少个(或多少种)用户自定义的类装载器,Java应用程序就可以创建多少个。被不同的类装载器装载的类存放的不同的命名空间中,它们不能互相访问,除非应用程序显示地允许这样做。在编写一个Java应用程序的时候,从不同源文件装载的类可以分隔在不同的命名空间中。通过这种方法,就能够使用Java类装载器的体系结构来控制任何从不同源文件中装载的代码之间的互相影响,特别是能够阻止恶意代码获取访问和破坏善意代码的权限。
1.3.3 Java class文件
Java class文件主要在平台无关性和网络移动性方面使Java更适应于网络。它在平台无关性方面的任务是:为Java程序提供独立于底层主机平台的二进制形式的服务,这是Java虚拟机所期望实现的。这种途径打破了C或C++等语言所遵循的传统,使用这些传统语言写的程序通常首先被编译,然后连接成为单独的、专门支持特定硬件平台和操作系统的二进制文件。Java编译器把Java源文件的指令翻译成字节码,这种字节码就是Java虚拟机的“机器语言”。除了特定处理器的机器语言之外,传统二进制可执行文件的另一个依赖于具体平台的属性石整数的字节顺序。如在执行X86系列处理器的二进制可执行文件中,字节顺序是地位在前,而对于PowerPC处理器则是高位在前。在Java class文件中字节顺序是高位在前,与使用何种平台无关。
除了对于平台无关性的支持,Java class文件还在支持网络移动性的Java体系结构中担当了至关重要的角色。首先,class文件设计得紧凑,因此它们可以快速地在网络上传送。其次,由于Java程序是动态链接和动态扩展的,class文件可以在需要的时候才下载。
1.3.4 Java API
Java API是运行库的集合,它提供一套访问主机系统资源的标准方法。运行Java程序时,虚拟机装载程序的class文件所使用的Java API class文件。所有被装载的class文件(包括从应用程序中和从Java API中提取的)和所有已经装载的动态库(包含本地方法)共同组成了在Java虚拟机上运行的整个程序。
Java API的class文件天生就与主机平台密切相关。在一个平台能够支持Java程序以前,必须在这个特定平台上明确地实现API的功能。为访问主机上的本地资源,Java API调用了本地方法。由于Java API class文件调用了本地方法,Java程序就不需要再调用它们了。通过这种方法,Java API class文件为底层主机提供了具有平台无关性的、标准接口的Java程序。
除了对平台无关性的推动之外,Java API在Java安全模型方面也做出了贡献。当Java API的方法进行任何有潜在危险的操作(比如进行本地磁盘写操作)之前,都会通过查询安全管理器来检验是否得到了授权。安全管理器是一个为应用程序提供自定义安全策略的特殊对象。在Java 1.2版本中,安全管理器的工作被访问控制器所取代。访问控制器是一个类,该类用来执行栈检验,已决定是否批准某种操作。通过强制执行安全管理器和访问控制器建立的安全策略,Java API促进了安全环境的建立,在这种安全环境中,可以运行具有潜在危险的代码。
1.3.5 Java程序设计语言
Java技术非常适用于网络,Java程序设计语言是相当通用的。Java语言支持的一些软件技术:
面向对象
多线程
结构化错误处理
动态连接
动态扩展
1.4 Java体系结构的代价
Java适合解决网络相关的问题和与平台无关的问题。和其他技术(如C++),Java程序的执行速度比较低,这是Java在面向网络特性上所付出的主要代价之一。最近随着虚拟技术的发展,Java运行速度上的缺陷有了显著改善,适应性优化等先进技术使Java程序能够以和本地编译的C程序相媲美的运行速度。开发者无法选择程序运行的Java虚拟机。
把Java程序编译成单独的可执行程序的方法(也成为“预编译”)能够改善性能,这通常以牺牲Java的动态扩展能力为代价。
除了性能以外,Java的面向网络体系结构所付出的另一个代价是,在内存管理和线程调度上的缺陷。
Java为了实现平台无关性,也要付出代价,即最小公分母问题,这是在任何尝试提供跨平台功能的API上都会出现的固有困难。当把Java class文件与Java编程语言之间的紧密联系和Java天生的动态连接特性联系到一起的时候还要付出一个代价。因为Java程序是动态连接的,从一个类到另一个类的引用是符号化的。在静态连接的可支持程序中,类之间的引用只是直接的指针或偏移量。相反,在Java class文件中,指向另一个类的引用通过字符串清楚地表明了所指向的这个类的名字。如果引用是指向一个字段的话,这个字段的名字和描述符(字段的类别)会被详细说明。如果引用指向一个成员方法,那么这个成员方法的名称和描述符(方法的返回类型、方法参数的数量和类型)也会被详细说明。而且Java的class文件不仅仅包含对其他类的字段和成员方法的符号引用,它们还包含对自己的字段和成员方法的符号引用。Java class文件还包含了可选的调试信息,这些调试信息包含局部变量的名称和类型。一个class文件的符号信息,以及字节码指令集和Java语言之间的密切关系,这些方面使得把Java class文件逆向编译为Java源码文件相当容易。