java语言的运行机制

在eclipse、netbeans、IntelliJ等IDE继承开发环境下,很多程序猿认为java语言不需要经过编译等过程,直接点击运行按钮就ok,其实这是错误的。IDE帮我们提高开发效率的同时,其实也屏蔽了很多java程序执行的细节,使得我们很多时候并不了解JVM内部的运行机制。这里结合我结合网上查找的一些资料和自己的实践体会,总结一下java语言的运行机制。


1. Java,你到底是怎么想的?

Java程序的运行必须经过编写、编译、运行三个步骤。

  1. 编写:是指在Java开发环境中进行程序代码的输入,最终形成后缀名为.java的Java源文件。
  2. 编译:是指使用Java编译器对源文件进行错误排查的过程,编译后将生成后缀名为.class的字节码文件,这不像C语言那样最终生成可执行文件(*.o)。
  3. 运行:是指使用Java解释器将字节码文件翻译成机器代码,执行并显示结果

Java语言这种“一次编写,到处运行(write once,run anywhere)”的方式,有效地解决了目前大多数高级程序设计语言需要针对不同系统来编译产生不同机器代码的问题,即硬件环境和操作平台的异构问题,大大降低了程序开发、维护和管理的开销。但是我们需要注意的是,Java程序通过JVM(Java虚拟机)才可以达到跨平台特性,但JVM是不跨平台的。也就是说,不同操作系统之上的JVM是不同的,Windows平台之上的JVM不能用在Linux上面,反之亦然

我们可以通过helloworld来理解这几个缩写词的具体含义:

运行
1
2
3
4
5
public  class  HelloWorld {
public  static  void  main(String[] args) {
  System.out.println( "helloworld" );
}
}

编译之后, 我们得到了HelloWorld.class

在HelloWorld里面, 我们调用了 JAVA API中的 java.lang.System这个类的静态成员对象 out, out 的静态方法:

  • public static void println(String string);

然后我们让虚拟机器来执行这个HelloWorld。

  1. 虚拟机会在classpath中找到HelloWorld.class。
  2. 虚拟机中的解释器(interpret)会把HelloWorld.class解释成字节码
  3. 把解释后的字节码交由execution engine执行。
  4. execution engine会调用native method(即平台相关的字节码)来在host system的stdout(显示器)的指定部分打印出指定的字符串。
  5. 这样,我们就看到"helloworld"字样了。

有了这个流程后,我们就好理解几个术语了:

JDK: java develop kit (JAVA API包)

SDK: software develop kit,以前JDK 叫做java software develop kit,后来出了1.2版本后,就改名叫jdk了,省时省力,节约成本。

JRE. java runtime environment我们的helloworld必须在JRE(JAVA运行环境,JAVA运行环境又叫JAVA平台)里面,才能跑起来。

JVM java virtual machine. 简单地讲, 就是把class文件变成字节码, 然后送到excution engine中执行。而为什么叫虚拟机,而不叫真实机呢?因为JVM本身是又不能运算,又不能让显示器显示"helloworld"的,它只能再调用host system的API,比如在w32里面就会调c++的API,来让CPU帮他做做算术运算,来调用c++里面的API来控制显示器显示显示字符串。而这些API不是JDK里面有的,我们平时又看不见的,所以我们就叫它native api了。

——————————————————————————

解决一个颇有渊源的问题: JVM、JDK、JRE, what the fuck?

JDK是整个Java的核心,包括了Java运行环境(jre)、一堆java工具和java的基础类库

JRE是java运行时环境。既然是运行时环境,不难理解意思就是没了这东西你java程序跑不起来呗。也就是说这个是java的运行平台,所有的程序都要在JRE下才能跑起来。它包括了JVM和java的核心类库,与jdk相比它不包含开发工具(编译器、调试器和其他工具)。jre文件夹下有两个子文件夹bin和lib,可以认为bin是JVM而lib则是JVM工作所需要的类库。所以,在你写完java程序编译成.class文件之后,你可以把这个.class文件和jre一起打包发给你的朋友,这样他就可以运行你写得程序了。

JVM就是java虚拟机,是JRE的一部分。是虚构出来的一个计算机。jvm有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有指令系统。它的主要工作就是解释自己的指令集并映射到本地的CPU指令集或者OS的系统调用。Java语言的跨平台特性就是不同的操作系统中,JVM的映射规则不同。另外,JVM对上层的java源文件不关心,只关心由源文件生成的类文件(*.class)。

╮(╯▽╰)╭ ok,总结一下,jdk是帮助你开发和编译用的。jre中的jvm运行你的程序,但是只有jvm还不行,还需要jre中的核心类库。


2. 那些该死的环境变量到底有什么用?

ok,很多书上讲”这个问题应该是每一个初学者总会遇到的问题“,但是其实本文在开始的时候就没遇到过。因为如果你上课没听讲,压根儿不知道什么环境变量这回事儿,也没做任何**的配置,那么你依然可以自如的编写自己的hello world,甚至编一个邮件接收客户端都是没问题的。

——WHY?

——因为有IDE。当你启动eclipse的时候IDE会自动加载系统中已经安装好的jdk,并且把第一次加载时jdk的环境设为IDE的默认环境。也就是说,你可以不配置环境变量,但是至少搞个jdk装上吧……

不配也行哎,完事大吉?

No,如果你想进阶,开发个web程序或者搞搞其他的东西,你就会发现,没有环境变量是不行的。例如,如果你运行tomcat,如果不配好环境变量的话,tomcat就跑不起来啦。

我们上网查阅资料后,总结一下,需要配置的环境变量有三个(其实也可以是两个啦,如果写绝对路径的话):

  • JAVA_HOME=C:\Program Files\Java\jdk1.7.0
  • PATH=.;%JAVA_HOME%\bin
  • CLASSPATH=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; (开始的 . 和最后的 ; 千万不能丢了╮(╯▽╰)╭)
在哪里配置?我的电脑-右击-高级-环境变量-系统变量里一一设置。然后打开命令行,输入java -version,如果是出现下面类似的信息,恭喜配置成功了!


JAVA_HOME:这个其实只是为了方便引用,当你需要使用到C:\Program Files\Java\jdk1.7.0这个路径的时候,只需要输入%JAVA_HOME%即可,避免了每次都输入相同的路径串,that's it。
PATH:我们看到PATH指向的是jdk目录下的bin,这个目录中的东西是用于编译开发用的,显然是为了当你cmd下使用javac和java命令的时候,避免还要输入绝对路径的麻烦,如果没有这东西,那么你每次想编译的时候,就要这样写了:%JAVA_HOME%bin/java *.java。
CLASS_PATH:看名字,猜一下?这个变量的设置时为了在程序运行的时候能够找到相应的.class文件的。举个例子: 你编译一个JAVA程序---A.java, 会得到一个A.class的类文件,你在当前目录下执行java A, 将会得到相应的结果(前提是你已经设置CLASSPATH为"."). 现在, 你把A.class移到别的目录下(例如:"e:\"), 执行java A, 将会有NoClassDefFindError的异常,原因就是找不到.class文件, 现在你把CLASSPATH增加为:".;e:\"再在任何目录下运行java A, 看看会有什么结果~~:)~~~, 一切正常, java命令通过CLASSPATH找到了.class文件! 

同样的解决几个问题:
1. 利用 -classpath 人为告诉JVM到哪里找到你的.class文件
总结下来就是:
(1).何时需要使用-classpath:当你要编译或执行的类引用了其它的类,但被引用类的.class文件不在当前目录下时,就需要通过-classpath来引入类
(2).何时需要指定路径:当你要编译的类所在的目录和你执行javac命令的目录不是同一个目录时,就需要指定源文件的路径(CLASSPATH是用来指定.class路径的,不是用来指定.java文件的路径的)
 
具体参见:http://blog.csdn.net/pengpenglin/article/details/1682858
2. CLASS_PATH设错了?
是的,如果你忘了加开始的那个点点,就错了!在不使用IDE的情况下,若要引用第三方jar包,需把这些jar包引入到classpath环境变量中。但若设置classpath时,没有包含当前目录(.),那么即使是在字节码文件所在的目录使用java命令运行此字节码文件,也会报java.lang.NoClassDefFoundError。这是因为若不设置classpath,则classpath自动包含当前目录;而若设置后,则不再自动包含当前目录,需要我们显式指定包含,这一点与path环境变量不同。

3.加载器种种

...

你可能感兴趣的:(java,java基础)