J2SDK(Software Development Kit for Java 2) ,简称JDK.它包括了JDK(Java Development Kit),JRE(Java Runtime Enviroment),Java Plug-in.
JDK (Java Development Kit), Java开发工具包(C:\Java\jdk1.6.0_18\).JDK是一组API,也可以说是一些java Class。JDK是一切java应用程序的基础,所有的java应用程序是构建在这个之上的。
JRE (Java Runtime Environment),Java运行环境. 说明:当安装过JDK之后会在c:\windows\system32下有一个java.exe,而系统的环境变量中%SystemRoot%\system32;是默认添加上的,而%SystemRoot%实际上就是C:\WINDOWS。
电脑有两套JRE,一套位于%JAVA_HOME%\jre另外一套位于C:\Java\jre6目录下。我们编写的Java程序要JRE才能运行,当你装完JDK后硬盘上的两套JRE都具有运行Java程序的功能,只是后者比前面那套少了Server端的VM,但是JDK里面的工具只能由"<JDK安装目录>\jdk1.6.0_18\"目录下的JRE来执行。server与client选项的差别在于所使用的VM不同,执行Java程序时默认会使用client VM。若使用server VM,会花费较长的启动时间及消耗较多的内存,为的是启动Java程序后可以获得较好的执行效能。
为什么会有两套JRE呢? 因为JDK里面有很多用Java所编写的开发工具(如javac.exe、jar.exe等),而且都放置在 <JDK安装目录>\lib\tools.jar里,它们本身运行的时候也需要一套 JRE,也就是前者(%JAVA_HOME%\jre);而后者(C:\Java\jre6)的JRE是用来执行我们自己编写的JAVA程序。
设置JAVA_HOME,CLASSPATH,PATH的目的:
1.设置JAVA_HOME(C:\Java\jdk1.6.0_18):
一、方便引用,要使用这个路径的时候, 只需输入%JAVA_HOME%即可;
二、修改简单, 当JDK路径改变的时候, 仅需更改JAVA_HOME的即可;
三、第三方软件会引用约定好的JAVA_HOME变量
2.设置PATH(%JAVA_HOME%\bin):
让Java执行环境找到指定的工具程序如Java、javac,系统会在当前目录下查找,若没有找到会到系统PATH中查找。
3.设置CLASSPATH:
让Java执行环境找到指定的Java程序(也就是.class文件)。
Java运行时环境(JRE)查找启动类,并加载其他使用到的类(即当加载A时,发现A应用了B则再去加载B),从三个地方加载需要的类:bootstrap class path, the installed extensions, and the user class path。
JDK5.0默认会在当前工作目录以及JDK安装目录/lib中寻找Java程序,若Java程序在这两个目录中则不用设置classpath。classpath在编译和运行时都要用到的参数。当没有这个参数时,java 和 javac 命令会取环境变量 CLASSPATH 来代替。
package com.tools.lcr; public class AppLauncher { public static void main(String [] args) { System.out.println("Hello World " + args[0]); } }
javac -classpath . AppLauncher.java
那么 javac 便会以当前目录(.)作为 classpath。你也可以先将环境变量 CLASSPATH 的值增加当前目录“.”,然后执行效果是一样的。
set CLASSPATH=.;%CLASSPATH% javac AppLauncher.java
当 classpath 很长的时候,为了运行方便(package com.tools.lcr.AppLauncher),java 程序通常都会提供一个批处理文件(如 run.bat)。
rem 环境变量中已设置了JAVA_HOME set JAVA=%JAVA_HOME%\bin\ set LIB=lib/json.jar;lib/saaj.jar;lib/log4j.jar;lib/jaxrpc.jar;lib/dom4j.jar set name=luchunli %JAVA%\javac -d . AppLauncher %JAVA%\java -Xms64m -Xmx256m -Duser.locale=zh_CN -classpath %LIB% com.tools.lcr.AppLauncher %name%
那么就算 classpath 再长,也可以化整为零,比用环境变量方便的多,建议不要依赖于 CLASSPATH 环境变量。编译或运行时将这个变量赋给 classpath 参数即可。
rt.jar是JAVA基础类库,默认就在根classloader的加载路径里面(%JAVA_HOME%\jre\lib和C:\Java\jre6\lib)
tools.jar JDK类库中提供的一些工具类集合的jar文件,是一个工具包(javac等工具)
javac XXX.java 实际上就是运行 java -Calsspath=%JAVA_HOME%\lib\tools.jar xx.xxx.Main XXX.java javac就是对上面命令的包装器(wrapper),其目的是避免开发者输入过长的指令。
dt.jar是关于运行环境的类库,主要是swing的包(%JAVA_HOME%\lib)
将tools.jar改成tools_bak.jar C:\src>javac AppLauncher.java Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/tools/javac/Main Caused by: java.lang.ClassNotFoundException: com.sun.tools.javac.Main at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:307) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:248) Could not find the main class: com.sun.tools.javac.Main. Program will exit. 将tools.jar改回,将rt.jar改名为rt_bak.jar C:\src>javac AppLauncher.java Error occurred during initialization of VM java/lang/NoClassDefFoundError: java/lang/Object 将rt.jar改名为rt_bak.jar C:\src>java AppLauncher Error occurred during initialization of VM java/lang/NoClassDefFoundError: java/lang/Object 改变tools.jar对java执行没有影响 C:\src>java AppLauncher luchunli Hello World luchunli
既然电脑上有两套JRE,那么由谁来决定用那一套JRE呢?java.exe的工作就是找到合适的JRE来运行Java程序。
java.exe依照底下的顺序来查找JRE:
自己的目录下有没有JRE;
父目录有没有JRE
查询注册表: [HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment]
所以java.exe的运行结果与你的电脑里面哪个JRE被执行有很大的关系。
环境变量PATH此时为%SystemRoot%\system32
C:\Documents and Settings\Administrator>java -verbose [Opened C:\Java\jre6\lib\rt.jar] [Loaded java.nio.charset.Charset$3 from C:\Java\jre6\lib\rt.jar] [Opened C:\Java\jre6\lib\charsets.jar] [Loaded sun.nio.cs.AbstractCharsetProvider from C:\Java\jre6\lib\rt.jar] [Loaded sun.nio.cs.ext.ExtendedCharsets from C:\Java\jre6\lib\charsets.jar]
将system32下的java.exe修改成java_lcr.exe,添加环境变量%JAVA_HOME%\bin,环境变量此时为%SystemRoot%\system32;%JAVA_HOME%\bin;
C:\Documents and Settings\Administrator>java -verbose [Opened C:\Java\jdk1.6.0_18\jre\lib\rt.jar] [Loaded java.nio.charset.Charset$3 from C:\Java\jdk1.6.0_18\jre\lib\rt.jar] [Opened C:\Java\jdk1.6.0_18\jre\lib\charsets.jar] [Loaded sun.nio.cs.AbstractCharsetProvider from C:\Java\jdk1.6.0_18\jre\lib\rt.jar] [Loaded sun.nio.cs.ext.ExtendedCharsets from C:\Java\jdk1.6.0_18\jre\lib\charsets.jar] //......
实际上此时我们查询注册表可以看到RunTimeLib指示的路径为:C:\java\jre6\bin\client\jvm.dll
java.exe程序只是一个执行的外壳,它会:
1.创建JVM装载环境和配置
2.装载JVM.dll
3.初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例
4.调用JNIEnv实例装载并处理class类。
java.exe创建JVM装载环境的时候会自动查找JRE,然后装入jvm.cfg([%JAVA_HOME%\jre|c:\Java\jre6]/lib/i386/jvm.cfg),而Java正是通过这个jvm.cfg配置文件来管理不同版本的JVM.dll的。通过这些文件我们可以定义目前JDK支持那些JVM,前面部分(client)是JVM名称,后面是参数:
-client KNOWN -server KNOWN -hotspot ALIASED_TO -client -classic WARN -native ERROR -green ERROR KNOWN表示JVM存在,ALIASED_TO表示给别的JVM取一个别名,WARN表示不存在时找一个JVM替代,ERROR表示不存在抛出异常。
Java通过LoadJavaVM来装入JVM.dll文件.动态连接库JVM.dll才是java虚拟机的实际操作处理所在,装入工作很简单就是调用Windows API函数:
LoadLibrary装载JVM.dll动态连接库.然后把JVM.dll挂界到JNIENV(JNI调用接口)实例(把导出函数JNI_CreateJavaVM和 JNI_GetDefaultJavaVMInitArgs挂接到InvocationFunctions变量的CreateJavaVM和 GetDefaultJavaVMInitArgs函数指针变量)上。JVM.dll的装载工作宣告完成。
调用InvocationFunctions->CreateJavaVM也就是JVM中JNI_CreateJavaVM方法获得JNIEnv结构的实例,然后就可以调用JNIEnv实例装载并处理class类。
Java程序有两种方式(jar包和class文件)
如果是执运行jar。 java -jar XXX.jar运行的时候,Java.exe调用GetMainClassName函数,该函数先获得JNIEnv实例然后调用Java类 Java.util.jar.JarFileJNIEnv中方法getManifest()并从返回的Manifest对象中取 getAttributes("Main-Class")的值,即jar包中文件:META-INF/MANIFEST.MF指定的Main-Class的主类名作为运行的主类。之后main函数会调用java.c中LoadClass方法装载该主类(使用JNIEnv实例的FindClass)。main 函数直接调用java.c中LoadClass方法装载该类。
如果是执行class方法。main函数直接调用java.c中LoadClass方法装载该类。然后main函数调用JNIEnv实例的GetStaticMethodID方法查找装载的class主类中
“publicstaticvoidmain(String[]args)”方法,并判断该方法是否为public方法,然后调用JNIEnv实例的CallStaticVoidMethod方法调用该Java类的main方法。