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存储区
2.1JVM指令系统
JVM指令系统同其他计算机的指令系统极其相似。
Java指令也是由操作码和操作数两部分组成。
操作码为8位二进制数,操作数进紧随在操作码的后面,其长度根据需要而不同。
操作码用于指定一条指令操作的性质(在这里我们采用汇编符号的形式进行说明),如iload表示从存储器中装入一个整数,anewarray表示为一个新数组分配空间,iand表示两个整数的"与",ret用于流程控制,表示从对某一方法的调用中返回。
当长度大于8位时,操作数被分为两个以上字节存放。
JVM采用了"bigendian"的编码方式来处理这种情况,即高位bits存放在低字节中。
这同Motorola及其他的RISCCPU采用的编码方式是一致的,而与Intel采用的"littleendian"的编码方式即低位bits存放在低位字节的方法不同。
Java指令系统是以Java语言的实现为目的设计的,其中包含了用于调用方法和监视多先程系统的指令。
Java的8位操作码的长度使得JVM最多有256种指令,目前已使用了160多种操作码。
2.2JVM指令系统
所有的CPU均包含用于保存系统状态和处理器所需信息的寄存器组。
如果虚拟机定义较多的寄存器,便可以从中得到更多的信息而不必对栈或内存进行访问,这有利于提高运行速度。
然而,如果虚拟机中的寄存器比实际CPU的寄存器多,在实现虚拟机时就会占用处理器大量的时间来用常规存储器模拟寄存器,这反而会降低虚拟机的效率。
针对这种情况,JVM只设置了4个最为常用的寄存器。
它们是:
pc程序计数器
optop操作数栈顶指针
frame当前执行环境指针
vars指向当前执行环境中第一个局部变量的指针
所有寄存器均为32位。
pc用于记录程序的执行。
optop,frame和vars用于记录指向Java栈区的指针。
2.3JVM栈结构
作为基于栈结构的计算机,Java栈是JVM存储信息的主要方法。
当JVM得到一个Java字节码应用程序后,便为该代码中一个类的每一个方法创建一个栈框架,以保存该方法的状态信息。
每个栈框架包括以下三类信息:
局部变量
执行环境
操作数栈
局部变量用于存储一个类的方法中所用到的局部变量。
vars寄存器指向该变量表中的第一个局部变量。
执行环境用于保存解释器对Java字节码进行解释过程中所需的信息。
它们是:上次调用的方法、局部变量指针和操作数栈的栈顶和栈底指针。
执行环境是一个执行一个方法的控制中心。
例如:如果解释器要执行iadd(整数加法),首先要从frame寄存器中找到当前执行环境,而后便从执行环境中找到操作数栈,从栈顶弹出两个整数进行加法运算,最后将结果压入栈顶。
操作数栈用于存储运算所需操作数及运算的结果。
2.4JVM碎片回收堆
Java类的实例所需的存储空间是在堆上分配的。
解释器具体承担为类实例分配空间的工作。
解释器在为一个实例分配完存储空间后,便开始记录对该实例所占用的内存区域的使用。
一旦对象使用完毕,便将其回收到堆中。
在Java语言中,除了new语句外没有其他方法为一对象申请和释放内存。
对内存进行释放和回收的工作是由Java运行系统承担的。
这允许Java运行系统的设计者自己决定碎片回收的方法。
在SUN公司开发的Java解释器和HotJava环境中,碎片回收用后台线程的方式来执行。
这不但为运行系统提供了良好的性能,而且使程序设计人员摆脱了自己控制内存使用的风险。
2.5JVM存储区
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解释器程序的平台下运行。
⑵ 如何在Windows上编译java程序
1、执行cmd命令javac后,显示如图所示编译成功,说明是java运行正常。
⑶ 如何用JDK编译JAVA程序
JAVA版hello
world全攻略侯光敏
看到很多技术网站的BBS上面充斥着java初学者的关于运行第一个java程序的求助信息,我觉得作为过来人很有写这篇文章的必要,因为他们遇到的都是些很低级的问题,但是让这些问题占据bbs上那么多宝贵的空间就太不应该了。
要搞清楚的基本概念
java是一种跨平台的网络语言,为了能够在不同平台上运行,它使用了虚拟机这个概念。后缀名为java的文件是源代码文件,它经过编译后生成的是class文件。虚拟机执行的就是这些class文件,将它们转化成为不同平台能够运行的命令。这就是为什么java的效率比较低的原因。也是因为这个原因,在java里没有其它语言的使用者熟悉的exe文件的概念。
执行hello
world的方法
切记:在命令行中输入
javac
源文件名.java
(编译)
java
源文件名
(执行,没有后缀)
这里说的是java
application,里面包括main函数。
如果hello
world是applet版的,在命令行中输入appletviewer
源文件名
(已经编译后的class文件)
如果class文件已经嵌入了html网页中,直接用IE打开就行了。
application经常出现的错误
系统提示Exception
in
thread
"main
"
java.lang.NoClassDefFoundError。出现这个提示的原因可能有:
1
你把文件名拼错了,java对大小写是敏感的。打错了当然找不到文件。
2
虚拟机没有找到必须的类库。你可能没有在autoexec.bat文件中设置classpath。进入windows的运行,输入sysedit,然后在autoexec.bat文件中加入这么一行:set
classpath=你的jdk的安装目录/lib;
例如set
classpath=c:/jdk1.3.0_02/lib;
保存退出后,你要在dos窗口的c根目录下执行一遍autoexec.bat文件已保证被设置了,当然,如果你愿意也可以重启机器。
系统提示HelloWorld.java:1:
Public
class
helloworld
must
be
defined
in
a
file
called
"HelloWorld.java
".
public
class
helloworld{^
一个Java源程序中可以定义多个类,但是,具有public
属性的类只能有一个,而且要与文件名相一致。还有,main方法一定要放在这个public
的类之中,这样才能运行这个类。
系统提示Exception
in
thread
"main
"
java.lang.NoSuchMethodError:
main
出现这个异常是因为你在抄书上的代码时抄错了。主函数一定要这么写:public
static
void
main(String
args[])
一个字都不能错,切记!!!
applet常出现的错误
IE显示applet已经启动,但是还是只显示灰色的一块。这种问题在使用jBuilder等集成开发工具是最容易出现,用appletviewer就没有问题。这是因为你在applet中使用了IE不支持的java版本。jBuilder在做applet是默认使用了swing组件,但是IE只支持jdk1.1,所以造成了这种情况。只要把导入swing的语句去掉就行了,然后按照提示修改一下代码,不要用swing组件的方法。如果你觉得swing组件很漂亮,打死都要用,那么就装一个java的plug-in这个东西在你装jdk的高版本时就自动装上了。看看你的控制面版中有没有那个红鼻子的小东西。但是切记,如果你要用它,那么你的html的文件的写法就和从前不一样了,不能简单的用CODE来指明类了。至于怎么写,不在这篇文章的讨论范围内了(你写一个hello
world还要用plug-in就搞大了)。网上有很多文章讲怎么写。
用惯了点击就执行的的exe文件自然就很不习惯打开dos窗口输入命令行,你可以把它做成jar文件,但是对hello
world来说有点麻烦,有个简单的傻办法:自己做一个批处理文件。例如:用记事本写一个run.txt文件,内容是:java
你的主文件名
,然后把后缀改成bat存到和主文件相同的目录下。呵呵,双击就运行了,够傻吧。
如果你非要用exe文件运行,jet等工具可以把class文件做成exe文件。但是这样也失去了java的跨平台性。
以上就是hello
world的全攻略了,如果你还看不到hello
world,我倒!你还是别学java了。
⑷ 编译java程序的命令是
javac是Java的编译盯樱命令,能将源代码编译成字节码,以。class扩展名存入Java工作目录中。Java是Java解释器,执行字节码程序,该程序是类名所指的类,必须是一个完整定义的名字。javadoc是Java文档生成器,对Java源文件和包以XML格式生成API文档。appletviewer是Java Applet浏览器。
Java是一种稿察编程语言,被特意设计用于互联网的分布式环境。Java具有类似于C++语言的“形式和感觉”,但它要比C++语言更易于使用,而且在编程时彻底采用了凯敬丛一种“以对象为导向”的方式。
使用Java编写的应用程序,既可以在一台单独的电脑上运行,也可以被分布在一个网络的服务器端和客户端运行。另外,Java还可以被用来编写容量很小的应用程序模块或者applet,做为网页的一部分使用。applet可使网页使用者和网页之间进行交互式操作。
⑸ 如何编译java
用命令提示符编译java程序的步骤:
1.先新建文本文档,输入自己的java程序。
这里我写一个简单的java程序,来做示范。
import java.util.*;
public class HelloDate{
public static void main(String[] args)
{
System.out.println("Hello,it's:");
System.out.println(new Date());
}
}
经验总结:运行一个java程序的大概的流程是:
书写源代码------>编译------->运行---->结束。
注意事项:
1.在输入的时候一定要注意区分大小写。
2.操作之前要保证自己的电脑配置了java的运行环境。
⑹ 如何编写你的第一个Java程序 3种方法来编写你的第一个Java程序
目录方法1:编写你的第一个Java程序1、要开始用Java编写程序,先设置你的工作环境。2、任何一种类似记事本的程序都能够用于Java编程。3、确保安装了Java软件开发工具包方法2:Hello World 程序1、我们将首先创建一个能打印"Hello World"的程序。2、声明类和main方法。3、编写将打印出"Hello World"的代码行。4、把这些都放在一起。5、保存文件,并打开命令提示符或终端来编译程序。6、运行程序。7、恭喜,你方法3:输入和输出1、我们现在将扩展我们的Hello World程序,以接受用户的输入。2、导入Scanner(扫描仪,由于编程时使用Scanner,故下文用Scanner)类。3、在main方法中,创建Scanner对象的一个新实例(instance)。4、提示用户输入。5、要求Scanner对象接受用户键入的下一行,并将其存储在变量中。6、向用户显示问候语。7、一起保存以上代码。8、编译并运行。Java是James Gosling于1995年创建的一种面向对象的编程语言,它用“字段”(fields,描述对象的属性),和“方法”(methods,对象可以执行的操作),将概念表示为“对象”(objects)。Java是一种“编写一次,就可以在任何地方运行”的编程语言,可以在任何装有Java虚拟机(JVM)的平台上运行。由于Java是一种用上大量英文单词的编程语言,母语为英语的初学者很容易学习和理解,非英语母语者只要下一番苦功也能很快上手。本教程介绍如何用Java编写程序。
方法1:编写你的第一个Java程序
1、要开始用Java编写程序,先设置你的工作环境。许多程序员使用集成开发环境(Integrated Development Environment,IDE)进行Java编程,比如Eclipse和NetBeans。但是不必使用臃肿的IDE,也可以编写Java程序并编译它。
2、任何一种类似记事本的程序都能够用于Java编程。高级程序员有时更喜欢使用终端内的文本编辑器,如Vim和Emacs。我们推荐一个可以安装在基于Windows和Linux系统(Mac、Ubuntu等)的文本编辑器:SublimeText。我们将在本教程中使用它。
3、确保安装了Java软件开发工具包。你要用它来编译程序。在基于Windows的操作系统中,如果环境变量不正确,则可能在运行javac时出错。有关JDK安装的详细信息,可以参阅如何安装Java软件开发工具包,以避免此错误。
方法2:Hello World 程序
1、我们将首先创建一个能打印"Hello World"的程序。在文本编辑器中,创建一个新文件,并将其另存为"HelloWorld.java"。HelloWorld是类名,你需要让类名与文件同名。
2、声明类和main方法。main方法 public static void main(String[] args)是程序运行时执行的方法。这个main方法在每个Java程序中都以相同方式调用。
public class HelloWorld { public static void main(String[] args) { }}
3、编写将打印出"Hello World"的代码行。
System.out.println("Hello World.");让我们看看这一行的组成成分:System 告诉系统执行某些操作。
out 告诉系统我们要输出一些内容。
println ?代表"打印行(print line)",我们用它告诉系统在输出中打印一行文字。
("Hello World.") 周围的圆括号表示方法 System.out.println()接受一个参数。在本例中,该参数是字符串"Hello World."
注意,Java中有一些我们必须遵守的规则:必须始终在每行末尾添加分号。
Java区分大小写,因此必须以正确的大小写写入方法名、变量名和类名,否则将出现错误。
某个方法或循环的特定代码块包含在花括号中。
4、把这些都放在一起。最后Hello World程序应如下所示:
public class HelloWorld { public static void main(String[] args) {System.out.println("Hello World."); }}
5、保存文件,并打开命令提示符或终端来编译程序。打开保存HelloWorld.java的文件夹,并键入javac HelloWorld.java。这告诉Java编译器你想要编译HelloWorld.java。如果有错误,编译器会告诉你做错了什么。否则,你不应该看到来自编译器的任何消息。如果现在查看helloworld.java所在的目录,应该会看到helloworld.class。这是Java用来运行程序的文件。
6、运行程序。我们终于可以运行我们的程序了! 在命令提示符或终端中,键入java HelloWorld。这是在告诉Java你想运行HelloWorld类。你应该看到控制台出现 "Hello World"。
7、恭喜,你完成了第一个Java程序!
方法3:输入和输出
1、我们现在将扩展我们的Hello World程序,以接受用户的输入。在我们的Hello World程序中,我们打印出一个字符串供用户查看,但是只有当程序能够接收用户输入信息,才能称之为程序的交互功能。我们现在将扩展程序,提示用户输入他或她的名字,然后用名字问候用户。
2、导入Scanner(扫描仪,由于编程时使用Scanner,故下文用Scanner)类。在Java中,我们有一些可以访问的内置库,但是我们必须导入它们。其中一个库是java.util,它包含我们获取用户输入所需的Scanner对象。为了导入Scanner类,我们在代码的开头添加了以下行。
import java.util.Scanner;这告诉程序我们想使用java.util包中的Scanner对象。
如果希望访问java.util包中的每个对象,只需在代码的开头编写import java.util.*; 即可。
3、在main方法中,创建Scanner对象的一个新实例(instance)。Java是一种面向对象的编程语言,因此它使用对象来表示概念。Scanner对象是含有字段和方法的对象。为了使用Scanner类,我们必须创建一个新的Scanner对象、它可以填充的字段和使用的方法。示例如下:
Scanner userInputScanner = new Scanner(System.in);userInputScanner是刚刚创建的Scanner对象实例的名称。注意名称是用骆驼体(每个单词首字母大写)写的,这是Java中变量命名的规定。
我们使用 new 运算符创建对象的新实例。因此在本例中,我们通过 new Scanner(System.in),创建了Scanner对象的新实例。
Scanner对象接受一个参数,该参数告诉对象要扫描什么。在本例中,我们输入System.in 作为参数。System.in告诉程序扫描来自系统的输入,这是用户将在程序中键入的输入。
4、提示用户输入。我们必须提示用户输入,以便用户知道何时在控制台中键入内容。这可以通过System.out.print或System.out.println实现。
System.out.print("What's your name? ");
5、要求Scanner对象接受用户键入的下一行,并将其存储在变量中。Scanner将始终接收用户键入的数据。下面的行将要求Scanner接受用户键入的姓名,并将其存储在变量中:
String userInputName = userInputScanner.nextLine();在Java中,使用对象方法的规定是objectName.methodName(parameters)。在userInputScanner.nextLine()中,我们使用刚才给出的名称调用Scanner对象,然后调用它的方法nextLine() ,该方法不接受任何参数。
注意,接下来程序将把下一行存储在一个"字符串"对象中。我们已将字符串对象命名为userInputName
6、向用户显示问候语。现在我们已经存储了用户名,我们可以打印一个问候语给用户。还记得我们在main类中编写的 System.out.println("Hello World."); 吗? 我们刚刚编写的所有代码都应该放在这一行上面。现在我们可以修改这一行,如:
System.out.println("Hello " + userInputName + "!");我们把"hello"、用户名和"!" 通过编写 "Hello " + userInputName + "!" 连起来的方式,称为字符串串联。
这里我们有三个字符串:"Hello "、userInputName和"!"。Java中的字符串是不可更改的。因此,当我们连接这三个字符串时,我们实际上创建了一个包含问候语的新字符串。
然后将这个新字符串作为参数输入System.out.println。
7、一起保存以上代码。我们的代码现在应该如下所示:
import java.util.Scanner;public class HelloWorld { public static void main(String[] args) {Scanner userInputScanner = new Scanner(System.in);System.out.print("What's your name? ");String userInputName = userInputScanner.nextLine();System.out.println("Hello " + userInputName + "!"); }}
8、编译并运行。进入命令提示符或终端,并运行与我们在第一次迭代HelloWorld.java时运行的命令。我们必须首先编译程序:javac helloworld.java。然后我们可以运行它:java HelloWorld。
小提示Java是一种面向对象的编程语言,建议你阅读更多关于面向对象编程语言的基础知识,非常有用。
面向对象编程有许多特征。其中三个主要特征是:封装:限制访问对象某些组件的能力。Java为字段和方法提供私有(private)、受保护(protected)和公共(public)三种修饰符。
多态:对象可以转换标识。在Java中,可以将一个对象转换为另一个对象,以使用另一个对象的方法。
继承:使用与当前对象位于同一层次结构中的另一个类的字段和方法的能力。
⑺ 编译Java程序的命令是:
javac {Java的类名}
如果Java类不在当前目录下的话,类名前面还需要有类所在的路径。
⑻ 如何编译java程序
三种方法:
1.在IDE中,如eclipse中写的Java程序,在点击保存后eclipse就会调用javac编译程序编译,编译文件在当前项目的bin目录下。
2.作为一个独立的文件且没有定义Java环境变量,需要在cmd窗口中切换到java bin目录下执行Javac程序,执行格式为javac 空格 Java源文件;如 javac C://hello.java;
3.作为一个独立的文件且定义了Java环境变量,打开cmd窗口,可以在任意目录输入javac java源文件,如javac D://hi.java。
Java也是一种高级语言,要让计算机执行你撰写的Java程序,也得通过编译程序的编译。但是Java编译程序并不直接将Java源代码编译为相依于计算机平台的0、1序列,而是将其编译为字节码。
Java源代码的扩展名为.java,经过编译程序编译之后生成扩展名为.class的字节码。