可能没有老师指导学习过java语言,导致自己对java一直以来就是拿过来用的态度,而从来没有分析过为什么要这样。最近学习JVM,刚读到java体系结构介绍,就产生了一大堆疑问。

 

1.既然java是跨平台的语言,为什么jdk版本会存在win32/win64/linux系统之分?

2.为什么编译运行java程序,要安装jdk,设置环境变量?

3.java虚拟机是将字节码文件编译/解释成机器码运行吗?

 

对于第一个问题和第三个问题,我个人理解如下:java是跨平台语言,但是其必须要运行在java虚拟机上才能真正实现跨平台。java虚拟机在载入编译后的字节码文件(.class)后,其执行引擎会将字节码文件,通过JNI(java本地机器语言接口)调用本地机器的系统方法。而JNI接口,大部分都是由C/C++编译成的动态链接库,在jdk的安装目录下,我们不难找到.dll文件(在linux上jdk安装目录下则表现为.so文件)。这些文件本身是已经编译完成了的本地机器码,是java程序与本地机器交互的接口。而对于不同的系统,其动态链接库(dll文件)的实现是不一致的,其实这就是C/C++不能跨平台的体现。在不同系统中,java与本地机器交互的JNI的实现,都需要用C/C++或者其他语言对应不同系统实现,所以jdk安装文件会存在系统差异。其实说到底,java程序不直接编译成机器码,而是通过JNI,调用其他语言写好的机器码程序模块,实现与本地机器的交互。

 

比如,java.lang.System类的一些本地方法,他们在System.java中只有定义,而最终的实现,在对应的dll动态库中。

public static native long currentTimeMillis();

  public static native long nanoTime();

  public static native void arraycopy(Object paramObject1, int paramInt1, Object paramObject2, int paramInt2, int paramInt3);

  public static native int identityHashCode(Object paramObject);

  private static native Properties initProperties(Properties paramProperties);

 

 

为了实现java的跨平台,一般,我们不会在程序中自定义JNI。

 

以下内容为目前猜测:

其实大多数java虚拟机都是C/C++程序写的,在调用java.exe执行java程序的时候,其实就是跑在一个C语言程序中(俗称java虚拟机),该程序实现:载入java字节码文件,然后这个程序解读字节码,再调用jdk自带的动态链接库实现与本地机器交互。目前对java虚拟机的概念比较空泛,暂时认为它是一个C/C++程序。是否有错,相信读完深入java虚拟机这本书会有答案。

 

为什么要设置java环境变量?其实这个就是一个习惯性动作,我不设置java环境变量,照样可以在装有jdk的机器上编译执行java程序。

设置 JAVA_HOME 变量是为了设置classpath和path变量,其实这个变量完全可以省略,改而在classpath和path变量中设置jdk bin的绝对路径。设置这个变量,只是为了统一管理jdk安装目录,一旦jdk目录改变,方便修改。

设置 PATH变量,是为了在CMD命令行中可以随时随地的运行java可执行程序,这些程序原本在jdk\bin目录中,常见的有java.exe javac.exe。如果写入path变量中,在CMD中运行java命令时,首先会去当前目录中寻找是否有java.exe可执行文件。如果没有,会去path变量配置的目录下找。如果不设置path变量,其实进入jdk\bin目录下,照样可以执行java.exe javac.exe 这些命令。

设置classpath变量,是为了在执行java TEST这个命令, 运行TEST类的时候,让虚拟机的系统级classloader可以找到TEST类以及TEST类中所引用的类。如果你把TEST.class文件放在jdk\bin目录下,java TEST其实是可以运行的,也就是默认会找当前目录。而如果class类包含包名,比如 java com.lizhaog.TEST,那么必须设置claspath=.;才能运行。如果TEST类中引用了其他类,则必须要把其他类的路径也配置在classpath下,才能找到这些引用类,classloader才能将其加载入虚拟机运行。

如果不想配置任何环境变量,只需要进入jdk\bin目录下,写的类必须是无包名的类。在该目录下运行javac XXX.java,java XXX即可成功运行。

 

接下来的问题:

1.如果配置了path和classpath=.;即便不在jdk\bin目录下运行java XXX,即便XXX.java中引用了rt.jar中的类,其实也是可以跑程序的。那么,classloader是如何找到rt.jar中的类的呢?

 

2.在windows下使用eclipse indigo版本的时候无需配置任何环境变量,为何可以编译运行呢?eclipse又是如何加载所要使用的类,如何找到jdk中的java.exe等可执行文件呢?