我们知道,要运行 java 程序,必须要配置 Java 开发环境,对吧。这次我们不使用开发工具,用命令行将HelloWorld编译运行出来,将其中的原理搞清楚。
1)将下载好的 JDK 无脑安装(即下一步、下一步)或者指定安装目录,不过自己要记得安装到哪了。
2)配置环境变量
JAVA_HOME(新建)
D:\JDK\jdk7
Path(追加)
%JAVA_HOME%\bin
CLASSPATH
.(注意这里配置了一个点)
3)HelloWorld的编写运行
我们新建这样的目录结构,我们知道 bin 目录是用来存放 .class文件(即字节码文件),src 目录是用来存放 .java 文件(即源码)。
编写
在 src 目录中新建 HelloWorld.java 文件。
我们知道一个 java 类应该有顶级三要素:
a. package
b.import
c.class
但有的可能没有 import ,不需要导包情况
1)需要的类当前类在同一个包下
2)需要的类位于 java.lang下
HelloWorld.java 如下
package com.briup.day;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
编译
打开 cmd,使用 javac 命令编译
-d 目录 将编译好的字节码文件放到指定目录
这时候 bin 目录下就会生成 .class 文件了。
运行
在 cmd 命令中使用 java 命令
这里解释这条命令的含义:
java [参数] 完整类名(包名+类名)
-classpath 路径
-cp 路径
指定类加载路径(CLASSPATH)
如 java -cp ./bin com.briup.day.HelloWorld
.代表当前目录,当前处于 test 目录下。
而 .class 文件处于 /test/bin 目录下,我们知道 java 运行的是 .class 文件。
所以找到 HelloWorld.class 只需要 ./bin
如果写成这样 java com.briup.day.HelloWorld 它会默认去 CLASSPATH 路径下去找,
当前 CLASSPATH 配置为 . 即当前目录,所以默认会去当前目录找。
当然现在这样是找不到,因为HelloWorld.class 在test/bin 目录下。
打包
在 cmd 下 输入
cd bin
java -cvf ../hello.jar *
java -cvf hello.jar *
-cvf : 表示打包
hello.jar : 给打包好后的 jar 起了个名字
* : 表示将当前目录下的所有文件打包。即 test/bin/下的所有文件。
使用好压将 hello.jar 打开
部署运行
将 hello.jar 复制到 E 盘。
在 cmd 命令下运行
E:
java -cp hello.jar com.briup.day.HelloWorld
这样是不是觉得很麻烦,每次都要先定位到打包好的 jar 包的位置,这样才能运行出来。
我们将 hello.jar 放到 JDK 的安装目录中的 jre/lib/ext/中。即D:\JDK\jdk7\jre\lib\ext
这样我们就可以任何地方运行了。
例如:我们在D盘运行
这样是不是很方便呢,那么这又是为什么呢?这是因为 java 的类加载机制。我们来了解下吧。
类加载器与双亲委派模型
类加载器
(1) Bootstrap ClassLoader(启动类加载器) : 将存放于<JAVA_HOME>\jre\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如 rt.jar 名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机内存中。启动类加载器无法被Java程序直接引用
(2) Extension ClassLoader(扩展类加载器) : 将<JAVA_HOME>\jre\lib\ext目录下的,或者被java.ext.dirs系统变量所指定的路径中的所有类库加载。开发者可以直接使用扩展类加载器。
(3) Application ClassLoader(系统类加载器) : 负责加载用户类路径(ClassPath)上所指定的类库,开发者可直接使用。
JVM的类加载是通过ClassLoader及其子类来完成的,类的层次关系和加载顺序可以由下图来描述:
双亲委派模型
工作过程:如果一个类加载器接收到了类加载的请求,它首先把这个请求委托给他的父类加载器去完成,每个层次的类加载器都是如此,因此所有的加载请求都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它在搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
好处:java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存放在rt.jar中,无论哪个类加载器要加载这个类,最终都会委派给启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果用户自己写了一个名为java.lang.Object的类,并放在程序的Classpath中,那系统中将会出现多个不同的Object类,java类型体系中最基础的行为也无法保证,应用程序也会变得一片混乱。
现在应该知道怎么回事了吧。