Java虚拟机(JVM)是可运行Java代码的假想计算机。
只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何Java代码能够在该系统上运行。
本文首先简要介绍从Java文件的编译到最终执行的过程,随后对JVM规格描述作一说明。
一Java源文件的编译、下载、解释和执行
Java应用程序的开发周期包括编译、下载、解释和执行几个部分。
Java编译程序将Java源程序翻译为JVM可执行代码字节码。
这一编译过程同C/C++的编译有些不同。
当C编译器编译生成一个对象的代码时,该代码是为在某一特定硬件平台运行而产生的。
因此,在编译过程中,编译程序通过查表将所有对符号的引用转换为特定的内存偏移量,以保证程序运行。
Java编译器却不将对变量和方法的引用编译为数值引用,也不确定程序执行过程中的内存布局,而是将这些符号引用信息保留在字节码中,由解释器在运行过程中创立内存布局,然后再通过查表来确定一个方法所在的地址。
这样就有效的保证了Java的可移植性和安全性。
运行JVM字节码的工作是由解释器来完成的。
解释执行过程分三部进行:代码的装入、代码的校验和代码的执行。
装入代码的工作由"类装载器"(classloader)完成。
类装载器负责装入运行一个程序需要的所有代码,这也包括程序代码中的类所继承的类和被其调用的类。
当类装载器装入一个类时,该类被放在自己的名字空间中。
除了通过符号引用自己名字空间以外的类,类之间没有其他办法可以影响其他类。
在本台计算机上的所有类都在同一地址空间内,而所有从外部引进的类,都有一个自己独立的名字空间。
这使得本地类通过共享相同的名字空间获得较高的运行效率,同时又保证它们与从外部引进的类不会相互影响。
当装入了运行程序需要的所有类后,解释器便可确定整个可执行程序的内存布局。
解释器为符号引用同特定的地址空间建立对应关系及查询表。
通过在这一阶段确定代码的内存布局,Java很好地解决了由超类改变而使子类崩溃的问题,同时也防止了代码对地址的非法访问。
随后,被装入的代码由字节码校验器进行检查。
校验器可发现 *** 作数栈溢出,非法数据类型转化等多种错误。
通过校验后,代码便开始执行了。
Java字节码的执行有两种方式:
1即时编译方式:解释器先将字节码编译成机器码,然后再执行该机器码。
2解释执行方式:解释器通过每次解释并执行一小段代码来完成Java字节码程序的所有 *** 作。
通常采用的是第二种方法。
由于JVM规格描述具有足够的灵活性,这使得将字节码翻译为机器代码的工作
具有较高的效率。
对于那些对运行速度要求较高的应用程序,解释器可将Java字节码即时编译为机器码,从而很好地保证了Java代码的可移植性和高性能。
二JVM规格描述
JVM的设计目标是提供一个基于抽象规格描述的计算机模型,为解释程序开发人员提很好的灵活性,同时也确保Java代码可在符合该规范的任何系统上运行。
JVM对其实现的某些方面给出了具体的定义,特别是对Java可执行代码,即字节码(Bytecode)的格式给出了明确的规格。
这一规格包括 *** 作码和 *** 作数的语法和数值、标识符的数值表示方式、以及Java类文件中的Java对象、常量缓冲池在JVM的存储映象。
这些定义为JVM解释器开发人员提供了所需的信息和开发环境。
Java的设计者希望给开发人员以随心所欲使用Java的自由。
JVM定义了控制Java代码解释执行和具体实现的五种规格,它们是:
JVM指令系统
JVM寄存器
JVM栈结构
JVM碎片回收堆
JVM存储区
21JVM指令系统
JVM指令系统同其他计算机的指令系统极其相似。
Java指令也是由 *** 作码和 *** 作数两部分组成。
*** 作码为8位二进制数, *** 作数进紧随在 *** 作码的后面,其长度根据需要而不同。
*** 作码用于指定一条指令 *** 作的性质(在这里我们采用汇编符号的形式进行说明),如iload表示从存储器中装入一个整数,anewarray表示为一个新数组分配空间,iand表示两个整数的"与",ret用于流程控制,表示从对某一方法的调用中返回。
当长度大于8位时, *** 作数被分为两个以上字节存放。
JVM采用了"bigendian"的编码方式来处理这种情况,即高位bits存放在低字节中。
这同Motorola及其他的RISCCPU采用的编码方式是一致的,而与Intel采用的"littleendian"的编码方式即低位bits存放在低位字节的方法不同。
Java指令系统是以Java语言的实现为目的设计的,其中包含了用于调用方法和监视多先程系统的指令。
Java的8位 *** 作码的长度使得JVM最多有256种指令,目前已使用了160多种 *** 作码。
22JVM指令系统
所有的CPU均包含用于保存系统状态和处理器所需信息的寄存器组。
如果虚拟机定义较多的寄存器,便可以从中得到更多的信息而不必对栈或内存进行访问,这有利于提高运行速度。
然而,如果虚拟机中的寄存器比实际CPU的寄存器多,在实现虚拟机时就会占用处理器大量的时间来用常规存储器模拟寄存器,这反而会降低虚拟机的效率。
针对这种情况,JVM只设置了4个最为常用的寄存器。
它们是:
pc程序计数器
optop *** 作数栈顶指针
frame当前执行环境指针
vars指向当前执行环境中第一个局部变量的指针
所有寄存器均为32位。
pc用于记录程序的执行。
optop,frame和vars用于记录指向Java栈区的指针。
23JVM栈结构
作为基于栈结构的计算机,Java栈是JVM存储信息的主要方法。
当JVM得到一个Java字节码应用程序后,便为该代码中一个类的每一个方法创建一个栈框架,以保存该方法的状态信息。
每个栈框架包括以下三类信息:
局部变量
执行环境
*** 作数栈
局部变量用于存储一个类的方法中所用到的局部变量。
vars寄存器指向该变量表中的第一个局部变量。
执行环境用于保存解释器对Java字节码进行解释过程中所需的信息。
它们是:上次调用的方法、局部变量指针和 *** 作数栈的栈顶和栈底指针。
执行环境是一个执行一个方法的控制中心。
例如:如果解释器要执行iadd(整数加法),首先要从frame寄存器中找到当前执行环境,而后便从执行环境中找到 *** 作数栈,从栈顶d出两个整数进行加法运算,最后将结果压入栈顶。
*** 作数栈用于存储运算所需 *** 作数及运算的结果。
24JVM碎片回收堆
Java类的实例所需的存储空间是在堆上分配的。
解释器具体承担为类实例分配空间的工作。
解释器在为一个实例分配完存储空间后,便开始记录对该实例所占用的内存区域的使用。
一旦对象使用完毕,便将其回收到堆中。
在Java语言中,除了new语句外没有其他方法为一对象申请和释放内存。
对内存进行释放和回收的工作是由Java运行系统承担的。
这允许Java运行系统的设计者自己决定碎片回收的方法。
在SUN公司开发的Java解释器和HotJava环境中,碎片回收用后台线程的方式来执行。
这不但为运行系统提供了良好的性能,而且使程序设计人员摆脱了自己控制内存使用的风险。
25JVM存储区
JVM有两类存储区:常量缓冲池和方法区。
常量缓冲池用于存储类名称、方法和字段名称以及串常量。
方法区则用于存储Java方法的字节码。
对于这两种存储区域具体实现方式在JVM规格中没有明确规定。
这使得Java应用程序的存储布局必须在运行过程中确定,依赖于具体平台的实现方式。
JVM是为Java字节码定义的一种独立于具体平台的规格描述,是Java平 立性的基础。
目前的JVM还存在一些限制和不足,有待于进一步的完善,但无论如何,JVM的思想是成功的。
对比分析:如果把Java原程序想象成我们的C++原程序,Java原程序编译后生成的字节码就相当于C++原程序编译后的80x86的机器码(二进制程序文件),JVM虚拟机相当于80x86计算机系统,Java解释器相当于80x86CPU。
在80x86CPU上运行的是机器码,在Java解释器上运行的是Java字节码。
Java解释器相当于运行Java字节码的“CPU”,但该“CPU”不是通过硬件实现的,而是用软件实现的。
Java解释器实际上就是特定的平台下的一个应用程序。
只要实现了特定平台下的解释器程序,Java字节码就能通过解释器程序在该平台下运行,这是Java跨平台的根本。
当前,并不是在所有的平台下都有相应Java解释器程序,这也是Java并不能在所有的平台下都能运行的原因,它只能在已实现了Java解释器程序的平台下运行。
Java程序使用下列文件后缀:
文件类别
文件后缀
Java源文件
java
Java字节码文件
class
22 常用文件名(CommonFile Names)
常用的文件名包括:
文件名
用途
GNUmakefile
makefiles的首选文件名。我们采用gnumake来创建(build)软件。
README
概述特定目录下所含内容的文件的首选文件名。
3 文件组织(FileOrgnization)
一个文件由被空行分割而成的段落以及标识每个段落的可选注释共同组成。超过2000行的程序难以阅读,应该尽量避免。“Java源文件范例”提供了一个页面布局合理的Java程序范例。
特点:C是中级语言把高级语言的基本结构和语句与低级语言的实用性结合起来。C语言可以像汇编语言一样对位、字节和地址进行 *** 作,而这三者是计算机最基本的工作单元。
C是结构式语言。结构式语言的显著特点是代码及数据的分隔化,即程序的各个部分除了必要的信息交流外彼此独立。这种结构化方式可使程序层次清晰,便于使用、维护以及调试。
程序设计语言具有心理工程及技术等特性。
(1)心理特性:歧义性、简洁性、局部性、顺序性、传统性。
(2)工程特性:可移植性,开发工具的可利用性,软件的可重用性、可维护性。
(3)技术特性:支持结构化构造的语言有利于减少程序环路的复杂性,使程序易测试、易维护。
百度百科-程序设计语言
1源程序文件的构成
要编写Java程序,首先应该知道Java程序文件中必须包括什么内容,Java程序的源程序文件结构如下:
package语句,0~1句,必须放在文件开始,作用是把当前文件放入所指向的包中。import语句,0~多句,必须放在所有类定义之前,用来引入标准类或已有类。public classDefinition,0~1句,文件名必须与类的类名完全相同。classDefinition,0~多句,类定义的个数不受限制。
interfaceDefinition,0~多句,接口定义的个数不受限制。Java程序的源代码文件要求包含三个要素:
1)以package开始的包声明语句,此句为可选。若有,且只能有一个package语句且只能是源程序文件的第一个语句,若没有,此文件将放到默认的当前目录下。
2)以import开始的类引入声明语句,数量可以是任意个。
3)classDefinition和interfaceDefinition分别代表类和接口的定义。由public开始的类定义只能有一个,且要求源程序文件名必须和public类名相同,Java语言对字符的大小写敏感,因此文件名相同意味着字母大小写也完全相同。如果源程序文件中有主方法main(),它应放在public类中。 这三个要素在程序中必须严格按上述顺序出现。
2类的构成
Java程序都是由类(class)所组成的,类的概念的产生是为了让程序语言能更清楚地表达出现实事物的本性。在Java中,类就是用于创建对象的模板,包含了特定对象集合的所有特性。Java类由两种不同的信息构成:属性和行为。
属性由一系列区别对象的数据组成,可用于确定属于类的对象的外观、状态和其他性质。在Java程序中,属性往往以类的成员变量形式出现。
行为指类对象对本身和其他对象所可以完成的事情,可以用于修改对象的属性,接收来自其他对象的信息和向其他要求执行任务的对象发送信息。在Java中,行为往往以一段小程序的形式出现,Java称这种小程序为“方法”(method)。统称为类的成员方法。
Java中类定义的语法形式为:
修饰符 class <类名> [extend<父类名>]{ type类变量1;type类变量2;
成员变量 修饰符 type<类方法名1>(参数列表){ type局
部变量; 方法体
}修饰符 type<类方法名2>(参数列表){ type局部变量; 方法体
} 成员方法}
其中class是Java的关键字,表明其后定义的是一个类。class前面的修饰符用来限定所定义的类的使用方式。类名是用户为该类起的名字,应该是一个合法的标识符。紧接着类定义语句的大括号之间的内容称为类主体。type指的是变量或方法的数据类型。类主体由成员变量和成员方法两部分组成。
以上所有提到或未提到的概念,在后面的章节中将详细为大家介绍。
3注释语句的添加
在开发Java程序的过程中,经常需要在适当的地方加上注释语句,以便其他人阅读
程序,一般来说,Java语言的源文件中,任何地方都可以加注释语句,一个好的程序应该在
其需要的地方适当地加上一些注释,以便于其他人阅读并理解程序。
注释语句有三种格式:
1)//注释内容 用于注释一行语句。
2)/ˇ注释内容ˇ/ 用于注释一行或多行语句。
3)/ˇˇ注释内容ˇˇ/ 用于注释一行或多行语句且注释语句中的内容可以通过使用Javadoc生成API文档,实现文档与程序同步实现的功能。
import javaawt;
import javaxswing;
import javaawtevent;
import javaxswingevent;
import javautil; //Date needed
import javaioPrintWriter;
public class NotePad extends JFrame
{
JTextArea jta;
class newl implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
jtasetText("");
}
}
class openl implements ActionListener
{ public void actionPerformed(ActionEvent e)
{
JFileChooser jf=new JFileChooser();
jfshowOpenDialog(NotePadthis);
}
}
//保存文件的监听
class savel implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
JFileChooser jf = new JFileChooser();
jfshowSaveDialog(NotePadthis);
}
}
//打印的监听
class printl implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
// PrintWriter p = new PrintWriter(NotePadthis);
}
}
//退出记事本的监听
class exitl implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Systemexit(0);//退出
}
}
//拷贝的监听
class copyl implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
jtacopy();
}
}
//粘贴的监听
class pastel implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
jtapaste();
}
}
//剪切的监听
class cutl implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
jtacut();
}
}
//查找的监听
//添加日期的监听
class datel implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Date d=new Date();
jtaappend(dtoString());
}
}
//构造函数
public NotePad()
{
jta=new JTextArea("",24,40);
JScrollPane jsp=new JScrollPane(jta);
JMenuBar jmb=new JMenuBar();
JMenu mFile=new JMenu("File");
JMenu mEdit=new JMenu("Edit");
JMenuItem mNew=new JMenuItem("New",KeyEventVK_N);
mNewaddActionListener(new newl());
mFileadd(mNew);
JMenuItem mOpen=new JMenuItem("Open",KeyEventVK_O);
mOpenaddActionListener(new openl());
mFileadd(mOpen);
JMenuItem mSave=new JMenuItem("Save");
mSaveaddActionListener(new savel());
mFileadd(mSave);
mFileaddSeparator(); //添加分割线
JMenuItem mPrint = new JMenuItem("Print");
mPrintaddActionListener(new printl());
mFileadd(mPrint);
mFileaddSeparator(); //添加分割线
JMenuItem mExit=new JMenuItem("Exit");
mExitaddActionListener(new exitl());
mFileadd(mExit);
mFilesetMnemonic(KeyEventVK_F);
//编辑菜单的子菜单的处理
JMenuItem jmi;
jmi=new JMenuItem("Copy");
jmiaddActionListener(new copyl());
mEditadd(jmi);
jmi=new JMenuItem("Cut");
jmiaddActionListener(new cutl());
mEditadd(jmi);
jmi=new JMenuItem("Paste");
jmiaddActionListener(new pastel());
mEditadd(jmi);
mEditaddSeparator(); //添加分割线
jmi=new JMenuItem("Find");
mEditadd(jmi);
jmi=new JMenuItem("FindNext");
mEditadd(jmi);
mEditaddSeparator();
jmi=new JMenuItem("Select All");
mEditadd(jmi);
jmi=new JMenuItem("Date/Time");
jmiaddActionListener(new datel());
mEditadd(jmi);
jmbadd(mFile);
jmbadd(mEdit);
thissetJMenuBar(jmb);
thisgetContentPane()add(jsp);
thissetSize(200,200);
thissetVisible(true);
}
//主函数,程序入口点
public static void main(String s[])
{
new NotePad();
}
}
一、什么是编译1、利用编译程序从源语言编写的源程序产生目标程序的过程。
2、用编译程序产生目标程序的动作。
编译就是把高级语言变成计算机可以识别的2进制语言,计算机只认识1和0,编译程序把人们熟悉的语言换成2进制的。
编译程序把一个源程序翻译成目标程序的工作过程分为五个阶段:词法分析;语法分析;语义检查和中间代码生成;代码优化;目标代码生成。
主要是进行词法分析和语法分析,又称为源程序分析,分析过程中发现有语法错误,给出提示信息。
二、什么是反编译计算机软件反向工程(Reverseengineering)也称为计算机软件还原工程,是指通过对他人软件的目标程序(可执行程序)进行“逆向分析、研究”工作,以推导出他人的软件产品所使用的思路、原理、结构、算法、处理过程、运行方法等设计要素,某些特定情况下可能推导出源代码。
反编译作为自己开发软件时的参考,或者直接用于自己的软件产品中。
三、Java类的编译与反编译我们在最初学习Java的时候,会接触到两个命令:javac和java,那个时候我们就知道,javac是用来编译Java类的,就是将我们写好的helloworldjava文件编译成helloworldclass文件。
class文件打破了C或者C++等语言所遵循的传统,使用这些传统语言写的程序通常首先被编译,然后被连接成单独的、专门支持特定硬件平台和 *** 作系统的二进制文件。
通常情况下,一个平台上的二进制可执行文件不能在其他平台上工作。
而Javaclass文件是可以运行在任何支持Java虚拟机的硬件平台和 *** 作系统上的二进制文件。
那么反编译呢,就是通过helloworldclass文件得到java文件(或者说是程序员能看懂的Java文件)四、什么时候会用到反编译1、我们只有一个类的class文件,但是我们又看不懂Java的class文件,那么航天桥java培训>
以上就是关于谁能简单阐述下java编译执行的过程全部的内容,包括:谁能简单阐述下java编译执行的过程、java源程序什么格式、程序设计语言分别有哪些特点等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)