JAVA语言——体系结构

Posted by 冷眼樵夫 on 12-20,2018

Java技术的核心就是Java虚拟机——所有Java程序都在其上运行,需要Java虚拟机、Java应用编程接口(API)和Java程序设计语言、Java.class文件四个部分的配合。

Java体系结构包括四个独立但相关的技术:

    > Java程序设计语言
    > Java.class文件格式
    > Java虚拟机
    > Java应用编程接口(API)

四者关系如下:
编写并运行一个Java程序时,就可以同时体验这四种技术,用Java程序设计语言编写源代码;通过jre(java运行环境)把它编译成Java.class文件;然后在Java虚拟机中运行class文件;当编写程序时通过调用类(这些类实现了Java API)中的方法来访问系统资源(比如I/O),当程序运行的时候,它通过调用class文件实现了Java API的方法来满足程序的Java API调用。

Java虚拟机

Java的核心就是Java虚拟机,它支持Java面向体系结构三大支柱的所有方面:平台无关性、安全性和网络移动性。

Java虚拟机的主要任务是装载class文件并且执行其中的字节码。

1、不同的Java虚拟机中执行引擎不同:

第一种引擎属于最简单的执行引擎,在由软件实现的虚拟机中,一次性解释字节码;

第二种引擎更快,但是也消耗内存,叫做“即时编译器”,这种情况下,第一次被执行的字节码会被编译成本地机器代码,编译出的本地机器会被缓存,当方法以后被调用的时候可以重用;

第三种引擎是自适应优化器,在这种场景下,虚拟机开始的时候解释字节码,但是会监视运行中程序的活动,并且记录下使用最频繁的代码段;
当Java虚拟机是由主机操作系统上的软件实现的时候,Java程序通过调用本地方法(native method)和主机交互。

2、Java中有两种方法:Java方法和本地方法

Java方法使用Java语言编写,编译成字节码文件,存储在.class文件中;
本地方法是由其他语言(比如C,C++,或者汇编语言)编写的,编译成和处理器相关的机器代码;

区别:本地方法保存在动态链接库中,格式是各个平台专有的。Java方法是与平台无关的,运行中的Java程序调用本地方法时,虚拟机装载包含这个本地方法的动态库并调用这个方法
本地方法的作用:使用本地方法还可能把程序变得和特定的Java平台实现相关。一个本地方法接口——Java本地接口——使得本地方法可以在特定主机系统的任何一个Java平台实现上运行;

所以编写实现代码时,如果希望保证程序的平台无关性,那只能通过Java API来访问底层系统资源。

类装载器的体系结构

Java虚拟机中存在着多个类装载器,因而类装载器实际上是一个可能包含多个类装载器的子系统,类装载器的体系结构是Java虚拟机在安全性和网络移动性上发挥重要作用的一个方面。类装载器主要分成两个部分:

启动类装载器:
例如:如果Java虚拟机在已有操作系统上实现为C程序,那么启动类装载器就会是此C程序的一个部分,启动类装载器通常使用某种默认方式从本地磁盘中装载类,包括Java API的类(启动装载器也称为原始类装载器、系统类装载器或者默认类装载器)

用户定义的类装载器:
Java应用程序能够在运行时安装用户定义的类装载器,这是以自定义方式装载类
例如:从网络下载class文件,尽管启动类装载器是虚拟机实现的本质部分,而用户定义的类装载器不是;但用户定义的类装载器能够用Java编写,能够被编译为class文件,能够被虚拟机装载,还能够像其它对象一样实例化。

每一个类被装载的时候,Java 虚拟机都监视着这个类,看它到底是被启动类装载器还是被用户类装载器装载,当被装载的类引用了另一个类时,虚拟机就会使用装载第一个类的类装载器装载被引用的类。
例如:如果虚拟机使用一个特定的类装载器装载Volcano这个类,它就会使用这个类装载器装载Volcano类使用的所有类。如果Volcano的同一个使用了一个叫做Lava的类,比方说,可能是调用了Lava类的一个方法,那么虚拟机将会使用装载Volcano的同一个类装载器装载Lava,这样,被这个类装载器返回的Lava类就动态与Volcano类建立起了联系。

Java.class文件

Java.class文件主要在平台无关性和网络移动性方面使Java更适应于网络。
在平台无关性方面的主要任务是:为Java程序提供独立底层主机的二进制形式的服务,Java.class文件是可运行在任何支持Java虚拟机的硬件、硬件平台和操作系统上的二进制文件。
在网络移动性的主要任务是:首先.class文件设计紧凑,有助于在快速在网上传送,其次,由于Java程序是动态连接和动态扩展的,.class文件可以在需要的时候才下载,可以最大限度的减少终端用户的等待时间。

Java API

Java API是运行库的集合,它提供一套访问主机系统资源的标准方法。编写Java程序时,可以假设在任何可运行程序的Java虚拟机上都能够获取Java API .class文件,所有被装载的class文件(包括从应用程序和从Java API中提取的)和所有已经装载的动态库(包含本地方法)共同组成了在Java虚拟机上运行的整个程序。

Java API的class文件天生就与主机平台密切相关,而Java API的内部设计也和平台无关性相关。

例如:Java API的用户图形界面库——即AWT(Abstract Windows Toolkit,抽象窗口工具箱)和Swing的设计目的是使用户设计的界面能够在所有平台上运行。由于不同平台上用户界面的外观风格具有相当大的差异,创建平台无关的用户界面是一件很困难的。AWT类库体系结构并没有强制Java API把所有平台上的Java程序用户界面都做成一个模式。恰恰相反,AWT类库体系结构鼓励在外观风格上适应于相应的底层平台。Swing类库甚至提供了更加灵活的方式:允许程序员自己选择外观风格。而且由于平台与平台之间字体大小、按钮和其他用户界面控件存在相当大的差异,AWT和Swing都包含了运行时定位窗体或对话框成员的布局管理器,布局管理器在不同平台上采用了些许不同的方式来定位对话框控件。除此之外,还有一些方面,Java API的内部系统结构把推动Java程序平台无关性的发展作为一个设计目的。

Java API在Java安全模型方面做出了贡献:通过强制执行安全管理器和访问控制器建立的安全环境的建立,在这种安全环境中,可以运行具有潜在危险的代码。

Java程序设计语言

Java技术非常适用于网络,但Java程序设计语言是相当通用的。使用Java语言编写程序,能够充分利用如下的许多软件技术:

面向对象
多线程
结构化错误处理
垃圾收集
动态连接
动态扩展
使用Java语言最引人注目的原因之一是:他能够提高开发者的效率;而它最主要的缺点在于执行速度较慢。

Java是一门面向对象语言。
面向对象技术的承诺之一是提升代码的重用率,提高开发者的效率。
与C++不同,在Java中没有通过使用强制转换指针类型或者通过进行指针运算直接访问内存的方法。
在Java中使用对象时,需要严格地遵守类型规则。

Java避免无意破坏内存的另一个方法是自动垃圾收集。
Java和C++一样,有一个new操作符,可以通过它来为新对象在堆中分配内存。
但是和C++不一样的是,Java并没有与new相对应的delete操作符,C++程序员常常使用delete来清除程序中不再需要的对象;
而Java中只需要停止对一个对象的使用,一段时间后,垃圾收集器会自动回收这个对象所占据的内存。

Java在运行时保护内存完整性的第三个办法是数组边界检查。
在C++中数组操作实际上就是指针运算,这会带来潜在的内存冲突。
在Java中数组是发展完备的对象,在每次使用数组的时候,Java都会检查数组边界,Java绝对不允许数组操作超出边界,从而导致内存冲突。

最后一个关于Java确保程序健壮性的例子是对对象引用的检查。
每次使用的时候,Java都会确保这些引用不为空值。
在C++中,使用一个空指针通常会导致程序崩溃。在Java中,使用一个空的引用会导致一个异常被抛出。

使用Java语言能够提高生产效率,效率提升就带来了开发周期的缩短和开发费用的降低。如果利用到Java程序潜在的平台无关性,就会使费用进一步降低。

Java体系结构的代价

和其他技术(诸如C++)相比·,Java程序中的执行速度可能比较低,这是Java在面向对象网络特性上所付出的最主要的代价之一。

第一个Java虚拟机诞生于1995年,它可以在一个解释器上执行字节码,这是一项较为简单的技术,性能不高。
不久,它的编译器诞生了。和解释器相比,它极大的提高了Java的性能。
随着最近虚拟机技术的发展,即使不能说Java速度上的缺陷完全消失了,但也有显著的改善。
适应性优化等先进技术使Java程序能够以和本地编译的C程序相媲美的速度运行。

Java开发者所面对的困难一是:即使特定的Java虚拟机能够提供相当好的性能,但一般情况下,开发者无法选择他们的程序将会在哪一种Java虚拟机上运行。

Java是一个非常灵活的工具,它提供许多方法去解决潜在的性能问题,
例如:如果需要提供的仅仅是一个单独的可执行文件,就可以:随程序附带一种虚拟机。把程序中对时间要求严格的部分作为本地方法实现。
把整个程序编译成一个单独的可执行文件,就像C和C++一样。
把Java程序编译成单独的可执行程序的方法能够改善性能,但这通常是以牺牲Java的动态扩展能力为代价的,然而,当开发的不是一个单独的应用程序,而是一个分布式系统,特别是代码和对象需要在虚拟机之间移动的时候,性能管理就会变得十分困难。

虽然使用Java时,程序的速度是令人担忧的事情,但是还是有很多方法可以弥补这一点。通过适当使用开发、发布和执行Java程序的各种技巧,大多数情况下还是能够取得令终端用户满意的速度,只要能够成功的解决速度问题,就能够使用Java语言并认识到它的益处——提高开发者的效率,为终端用户增强程序的健壮性。

困难二:在内存管理和线程调度上的缺陷
垃圾收集器可以使得许多程序更加健壮,这也是网络中很有价值的安全性保障措施。但是垃圾收集器也给程序运行时的性能加入了一些不确定性,你无法确认垃圾收集器什么开始收集垃圾,无法确认垃圾收集器是否开始收集垃圾,也无法确认垃圾收集到底要持续多长时间。

困难三:为实现平台无关性,出现了最小公分母问题
这是在任何尝试提供跨平台功能的API上都会出现的固有困难,最小公分母问题不仅折磨平台无关性API的设计者,而且还影响到了使用这种API的程序的开发者

困难四:当Java.class文件与Java编程语言之间紧密联系和Java天生的动态连接特性联系到一起的时候,还要付出一个代价,因为Java程序是多态连接的,从一个类到另一个类的引用是符号化的。
Java.class文件不仅仅包含对其他类字段和成员方法的符号引用,他还包含对自己的字段和成员方法的符号引用。将Java.class文件逆向编译为Java源码文件相当容易,但逆向编译静态连接的二进制可执行文件是相当困难的,这并不仅仅因为缺失了符号信息(最初的类、字段、方法和局部变量名),还因为通常静态连接库的优化程度非常高。而静态连接二进制文件优化程度越高,它的初始源代码的符合程度就越小。

结论

Java能在极大程度上提高程序员得到效率,增强程序耳朵健壮性,与老的程序设计技术(如C和C++)相比,具有过的去的性能,为新兴的以网络为中心的计算提供了一种工具。


2评论
  • 冷眼

    好文,点赞୧(๑•̀⌄•́๑)૭

    • 冷眼樵夫 博主

      @冷眼 |´・ω・)ノ谢谢支持