JAVA的源程序是怎样被编译和运行的

JAVA的源程序是怎样被编译和运行的,第1张

java

程序

编译是根据“类库”

也就是

jvm了

解释编译。

在用到的时候必须要有识别“解释后的java程序的类库

两个过程

java原程序-----javaclass

文件====

解释执行

这两个过程中都要用到

类库

1,如果java文件没有package,就默认给文件加上"无名"package;

2,默认导入javalang包,所以我们的java程序中可以使用Sting,Math,Integer等类,包括一些异常类;

3,如果生成的类没有父类,则为这个类隐式加上父类:Object;因此,包括Object中的许多方法可以使用;

4,字段的初始化;

二,我们所看的到的:

既然看的到,就先看程序运行结果:

public class JRun1 {

public JRun1() {

Systemoutprintln(" 构造函数");

}

static

{

Systemoutprintln("static{}");

}

{

Systemoutprintln("{}");

}

public static void main(String[] args) {

Systemoutprintln("main()");

}

}

运行结果:

static{}

main()

显然,程序运行时,先运行:

static

{

Systemoutprintln("static{}");

}

再调用main();

如果我们在类中建立一个对象:

public class JRun1 {

public JRun1() {

Systemoutprintln(" 构造函数");

}

static

{

Systemoutprintln("static{}");

}

{

Systemoutprintln("{}");

}

public static void main(String[] args) {

Systemoutprintln("main()");

new JRun1();

}

}

运行结果:

static{}

main()

{}

构造函数

从而,我们得出:

建立一个非主类对象,顺序为:静态初始化块static{}-->初始化块{}-->构造函数constructor;

那么,牵涉到继承,运行流程又如何

看程序:

class JRun1Father{

JRun1Father(){

Systemoutprintln("父类构造函数");

}

static{

Systemoutprintln("父类静态初始化块");

}

{

Systemoutprintln("父类初始化块");

}

}

public class JRun1 extends JRun1Father{

public JRun1() {

Systemoutprintln("子类构造函数");

}

static

{

Systemoutprintln("子类静态初始化块");

}

{

Systemoutprintln("子类初始化块");

}

public static void main(String[] args) {

//Systemoutprintln("主方法)");

new JRun1();

}

}

运行结果:

父类静态初始化块

子类静态初始化块

父类初始化块

父类构造函数

子类初始化块

子类构造函数

所以,牵涉到父类:父静态-->子静态-->父初始化及构造-->子初始化及构造;

注意:初始化块和构造是接连运行的,不会父类子类交替

比如说保存为"d:\java\testjava",然后转换目录到那里"cd

d:\java",编译这个java文件"javac

testjava"这个javac的命令一定要记住,这是jdk里面最为常用的之一,是个java的编译器,具体参数你自己研究吧,很多,配合使用会得到意想不到的结果。这时候应该在"d:\java\"目录下面生成了一个testclass文件,这个就是一个二进制文件,就像windows下面常见的exe文件一样,只不过这个二进制文件是java虚拟机的(具体java的运行机制书上都会讲,自己研究吧)。这样就可以运行了,"java

test",java是jdk的另一个最为常用的命令,启动java虚拟机,后面的参数书你的程序编译出来的class文件,但是千万别再后面加上"class",java命令也还是有很多的参数,还是自己看吧

idea运行java程序的关键 *** 作是关联本地JDK和设置程序运行入口。详细步骤如下:

1  关联本地JDK,已关联的可以跳过此步。

11  首次启动idea时,依次选择Configure--->Project Defaults--->Project Structure,进入项目结构设置面板,图示如下:

12  选择SDK,单击绿色的加号,在d出的列表中选择添加JDK,图示如下:

13  定位到本地JDK安装目录,单击OK确认。

14  设置完成后,本地JDK就被关联到idea了,单击OK或Apply确认更改。

2  设置程序运行入口

21  首次创建项目后,工具栏的运行按钮显示为不可用。单击工具栏灰色三角箭头,编辑参数配置面板如下图:

23  设置应用名称Name,在Main class处打开主类选择面板,切换到Project页面,定位到拥有主类的文件(含有main方法的文件),选择完成后单击OK确认。 *** 作如下图所示:

3  注意事项

31  当一个项目中有多个主类并存时,需要明确指定以哪一个主类做运行入口。

32  对于非新建的项目,idea会自动识别主类,设置程序入口。如果识别失败,仍需要按照第2步进行手动配置。

33  在主类选择面板,第一个Search by Name页面可以自动搜索出已编译过的主类。如果此java程序从未编译,则必须在Project页面手动指定。

34  注意到含有主类文件的类名定义行和主函数定义行左侧均有一个绿色的箭头,单击任意一个箭头,选择在下拉列表里选择第一项Run,就可以快捷地运行java程序了, *** 作如下图所示:

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解释器程序的平台下运行。

第一步:下载并安装JDK 60,安装路劲为: C:\java\jdk16

第二步:对“我的电脑”按右键,选“属性”,在“系统属性”窗口中选“高级”标签,再按“环境变量”按钮,d出一个“环境变量”的窗口,在系统变量中新建一个变量,变量名为“JAVA_HOME“,变量值为"C:\java\jdk16";如果存在"PATH"变量名,按编辑,在变量值最前面输入"C:\java\jdk16\bin;"(注意以分号结尾,没有引号如果没有"PATH",点击新建一个"PATH"变量名,变量值一样)

第三步:单击Windows xp的“开始”->“运行”,在d出的运行窗口中输入cmd,按回车,打开一个命令行窗口,输入javac,将会看见一系列javac常用参数选项 恭喜你java环境安装成功了

第四步:开始编程(注意先双击打开"我的电脑",在"工具" ->"文件夹选项" -> 点击"查看"选项 ->在"高级设置"中找到"隐藏已知文件类型的扩展名"前面的小勾去掉)。在C盘的根目录中新建一个子目录,名为"JavaTest”,以作为存放 Java源代码的地方。在JavaTest文件夹中,新建文本文档, 把“新建 文本文档txt”改为"HelloWorldjava"。用记事本打开"HelloWorldjava", 输入:

public class HelloWorld {

public static void main(String[] args) {

Systemoutprintln("Hello, world!");

Systemoutprintln("恭喜你成功运行了第一个java应用程序!");

}

}

注意源文件名必须与类名相同,且类修饰符为public,文件名后缀为"java"保存文件

第五步:在命令行窗口中输入 cd C:\JavaTest,将当前路径转入JavaTest目录中。然后,输入 javac HelloWorldjava,JDK就在JavaTest文件夹中编译生成一个HelloWorldclass的类文件。

第六步:在命令行窗口中输入 java HelloWorld,(注意没有class后缀)屏幕出现了

Hello world!

恭喜你成功运行了第一个java应用程序!

表示成功了,也就顺利地编译及运行了第一个Java应用程序。

以上就是关于JAVA的源程序是怎样被编译和运行的全部的内容,包括:JAVA的源程序是怎样被编译和运行的、简述JAVA程序运行过程、如何直接运行JAVA程序等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/9972604.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-03
下一篇 2023-05-03

发表评论

登录后才能评论

评论列表(0条)

保存