您真的明白java环境变量的配置吗?

首先,我们来看一看当我们用命令执行javac和java的时候,系统做了些什么工作,假如我们现在有一个文件夹如下图1所示,有两个java文件。

图1:文件目录示意图

其中,Main.java的内容非常简单:

public class Main
{
         public static void main(String[] args)
         {
             System.out.println("hello world");
         }
}

我们先在cmd下把目录切换到,上图1所示的目录G:\oj\workdir\kown\test下:

图2:切换目录

发现一个好玩的事情,在用户(home)目录下直接切换,是不行的,必须有改变盘符的命令才能切换,如图2,可以交换第一句和第二句的顺序。当然更加快捷的方式是在图1所示的文件夹下按F4,输入cmd然后回车。

我们来编译一下Main.java 文件输入javac Main.java

图3:javac Main

CMD是怎样执行javac Main.java的呢?首先是解析命令字符串,有空格分隔。把第一个参数作为可执行程序,后面的参数作为可执行程序的参数。就像我们写c,c++等程序的main函数int main(int argc, char *argv[]),argc是参数个数,argv[]是参数。Javac是用c语言编写的,肯定也有main函数,我们的外部程序就可以通过argv[]这个参数把外部参数传递给javac,同样CMD也是一个可执行程序,他也有这样的输入参数。

所以整个过程,就是我们在CMD下输入javac Main.java 就是把javac Main.java作为参数通过argc这样的参数传递给CMD,CMD解析参数字符串,知道要执行javac程序,CMD首先会查找当前目录下有没有javac这样的可执行程序,你可以尝试在当前文件夹下加入一个javac.com, javac.bat或者javac.exe这样的可执行文件,重新运行javac Main.java试一试,就知道CMD首先查找的是当前目录了。

如果找到则执行,如果没有找到就开始查找系统环境变量path指定的目录。这就是我们要把类似于C:\Program Files\Java\jdk7\bin这样的目录加入到系统环境变量path中的原因了。

现在我们来执行java命令,先看一看我们的目录情况,只是多了一个编译Main.java产生的字节码文件Main.class:

图4:当前目录

执行java Main

图5:java Main

那么执行java和javac有什么相同和不同的地方呢?对于CMD过程都是一样,只是执行javac和java这两个程序本身不一样,javac只是编译java的源代码成为class的字节码。Java就是执行字节码。下面我们来看一看java的执行过程。

首先,通过path查找到java.exe,这是Windows下的可执行文件,在C:\Program Files\Java\jdk7\bin下可以找到。

java.exe会连接一个jvm.dll,dll文件是Windows的动态链接库,里面就是一些模块,函数,只不过他可以动态加载而已。而jvm.dll的作用有初始化一个JVM(java虚拟机),

然后、JVM初始化一个BootstrapLoader(启动类加载器)实例,Bootstrap Loader自动加载ExtendedLoader(标准扩展类加载器),并将其父Loader设为Bootstrap Loader。Bootstrap Loader自动加载AppClass Loader(系统类加载器),并将其父Loader设为Extended Loader。

有了类加载器,就要加载类了吧。首先是Bootstrap Loader加载,Bootstrap Loader加载类的路径写在有JRE环境变量中,JVM运行也被加在了系统环境变量中,可以通过System.getProperty("sun.boot.class.path")这样的方式得到。同理Extended Loader加载类的目录可以通过System.getProperty("java.ext.dirs")得到。AppClassLoader加载类的目录可以通过System.getProperty("java.class.path")得到。

看到AppClassLoader的java.class.path是不是有一点眼熟,这个就是java系统环境变量中的classpath。

运行一个class时,总是由AppClass Loader(系统类加载器)开始加载指定的类。但是每个类加载器会先将加载任务委托给其父加载器,如果其父找不到,再由自己去加载。

所以我们运行java Main的时候AppClassLoader会在BootstrapLoader指定的加载路径查找Main.class,然后在ExtendedLoader指定的路径查找Main.class,最后在AppClassLoader指定的classpath目录下查找。

值得注意的是当我们在当前目录下运行java Main能够加载到Main.class有两种可能的原因:

一是:AppClassLoader搜索了当前路径。

二是:JVM动态的把当前路径加入到了classpath中。

通过把当前文件夹下的OpenMain.class文件添加到classpath中,只是让他们的输出不同,测试后发现先执行的是classpath下的同名文件,我们知道应该是JVM动态的把当前路径添加到了classpath最后。

我们注意到Main.java是没有包名的,那么有包名的怎么办内?我们来看一看OpenMain.java

OpenMain.java的类容如下:

package kown.test;
public class OpenMain
{
         public static void main(String[] args)
         {
              System.out.println("hi world");
         }
}

编译OpenMain.java:

图6:javac -encoding

我们发现是编码不可映射错误,这是编码的问题,javac默认使用的系统环境变量默认的字符集(中文一般是GBK),因为上面的OpenMain.java文件是用utf-8编码。所以没有问题我们可以用:Javac –encoding utf-8 OpenMain.java来编译,也可以先把OpenMain.java另存为ANSI格式,再来编译,上面是采用改变了文件OpenMain.java的编码来处理。

运行:java OpenMain

图7:wrong name

发现wrong name:/kown/test/OpenMain,这是怎么回事呢?我们先来看一看上面图7和下面图8的区别。

图8:无法加载主类

图8这样的错误的原因是BootstrapLoader,ExtendedLoader和AppClassLoader加载的目录下根本就找不到OpenMain.class这个文件。而图7的错误原因是找到了OpenMain.class文件,但是没有找到OpenMain这个类。我们来分析一下图7中的错误,Exception in Thread main java.lang.NoClassDefFoundError:OpenMain······通过这个我们知道JVM已经启动了,并且已经加载了OpenMain.class字节码。但是给了我们一个wrong name :kown/test/OpenMain

我们知道kown/test是我们的包名,并且加了包名才产生了错误。

重新思考一下,java中为什么要引入包的概念,其实和命名空间一样是为了区分不同模块同名的问题,在想一想我们为什么在不同的包中就可以使用相同的类名呢?那是因为我们在类的名字前面加上包名来作为类的名称,因为报名不同,所以我们的类的名字其实是不同的。这就是为什么在java中我们经常要使用全限名例如我们用Class.forName(java.lang.String)我们要使用全限类名java.lang.String的原因。

我们在看下面图9和图10这两张图再继续分析:

图9:OpenMain.class所在的目录下运行

图10:包名的父目录下运行

情况一:图9:OpenMain.class所在的目录G:\oj\workdir\kown\test下分别运行了java OpenMain和java kown/test/OpenMain,一个是带上包名的,一个是没有带包名的。当我们不加包名的时候就告诉我们类名错误,当我加上包名的时候就告诉我们找不到类。

情况二:图10:包名的父目录G:\oj\workdir下分别运行了java OpenMain和java kown/test/OpenMain,也是一个是带上包名的,一个是没有带包名的,当我们不加包名的时候告诉我们找不到类,加了包名终于运行成功了。

为什么这么神奇,让我们来分析总结一下:

结合情况一和情况二,我们可以大胆的猜测java首先是通过他的参数来找class文件的,在情况一运行java OpenMain,因为当前目录有OpenMain.class文件,所以加载class文件阶段没有问题,然后加载类,java把参数OpenMain作为类名,用类似于Class.forName("OpenMain");这样的方式来加载OpenMain类,所以得到了java.lang.NoClassDefFoundError:OpenMain还有各个类加载器的Unknown Source错误,因为根本没有OpenMain这个类,而是kown.test.OpenMain这个类。

对于情况二,直接java OpenMain得到的错误其实应该是找不到主类,因为G:\oj\workdir根本没有这个类,之所以会出现像上面的情况,是因为我为了测试AppClassLoader搜索了当前路径,还是JVM动态的把当前路径加入到了classpath中。把OpenMain打了jar包加入了C:\Program Files\Java\jre7\lib\ext文件夹下。一定是jar包,而不是class文件才有效。

所以java会按参数指定的路径下来搜索class文件,然后加载class文件到内存,然后把路径加上文件名作为全限类名来加载类。

时间: 2024-08-10 15:08:52

您真的明白java环境变量的配置吗?的相关文章

Question20180106 Java环境变量的配置及为什么要配置环境变量

Question 1  Java环境变量的配置及为什么要配置环境变量 Q1.1为什么要配置环境变量 在学习JAVA的过程中,涉及到多个环境变量(environment variable)的概念,如PATH.正确地配置这些环境变量,是能够顺利学习.开发的前提.而经常出现的问题是:我们能够按照提示一步一步地正确配置,但时间一长就忘了,出现了问题也无从下手.究其原因,就是对这些概念没有理解,知其然但不知其所以然.下面的内容,就是帮助大家知其所以然. 基本原理 环境变量(environment vari

Java环境变量的配置及意义

配置环境:Windows XP 首先是配置参数,这个网站上很多.很多网站上说要配置三个参数,即Path,classpath,JAVA_HOME三个.   简要的介绍一下这三个环境变量. Path使得系统可以在任何路径下识别java命令. JAVA_HOME指明JDK安装路径.(设置这个参数是为了偷懒,呵呵..) classpath为java加载类(class or lib)路径,只有类在classpath中,java命令才能识别. 三个环境变量的具体使用. JAVA_HOME 指明JDK安装路径

【黑马程序员】--Java环境变量的配置步骤及JDK、JRE

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- ----- 我是Hakka_LGM,请多多指教 Java环境变量的配置步骤 工具 1.JDK1.8.0 2.WIN7 x64.win8 x64 步骤 安装JDK 选择安装目录 安装过程中会出现两次 安装提示 .第一次是安装 jdk ,第二

Question1 Java环境变量的配置及为什么要配置环境变量

在学习JAVA的过程中,涉及到多个环境变量(environment variable)的概念,如PATH.正确地配置这些环境变量,是能够顺利学习.开发的前提.而经常出现的问题是:有的学习者能够按照提示一步一步地正确配置,但时间一长就忘了,出现了问题也无从下手.究其原因,就是对这些概念没有理解,知其然但不知其所以然.下面的内容,就是帮助大家知其所以然. 一.基本原理 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:临时文件夹位置和系

JDK的安装与Java环境变量的配置详解

JDK作为JAVA开发的环境,必须在电脑上安装JDK. 1.下载jdk http://rj.baidu.com/soft/detail/14459.html?ald下载jdk最新版jdk-8u11-windows-i586.1406279697, 2.进入下载界面可根据自己需要选择需要的Java版本,分别 有j2ee,Javase,Javame, 3.然后点击accept,接着在下面的下载列表中选择自己的操作系统,以及34位还是64位的进行下载 4.然后双击安装包,点击下一步 5.接着点击下一步

win7下java环境变量的配置

在win7下配置java环境变量:自从JDK1.5以后就不需要再配置classpath了所以简单许多了 前提是你已经安装好了JDK 第一步把鼠标放到计算机上单击右键选中属性,看到如下界面 点击高级系统设置,出现下面界面 点击下面的环境变量出现下面界面 点击新建出现下面界面 变量名写上JAVA_HOME 变量值就是你的java安装路径,比如我的是在D:\java所以就写下如图所示的内容 之后点击确定,在系统变量对话框里变量列找到path如下图 在path变量值最前面添加%JAVA_HOME%\bi

Win10操作系统下,Java环境变量的配置

一:首先要下载并安装JDK (官方下载网址:http://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html) 二:配置环境变量及class,path的值 找到单击右键->属性,进入下图页面: 点击"高级系统设置",进入下图页面: 点击"环境变量",如下图: 点击“新建”,然后按下图所示,设置一个名为“JAVA_HOME"的变量名和变量值.(变量值是你自己安装J

Java环境变量的配置及使用

1.JRE=JVM+java类库,JDK=JRE+java工具. 2.java环境变量配置三个变量, JAVA_HOME=C:\Program Files\java\jdk1.7.0_75 支持tomcat等软件,    path=C:\Program Files\java\jdk1.7.0_75\bin 支持环境java工具,      classpath=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; JVM执行路径.

[原创]多版本Java环境变量的配置

起因:   偶然突发兴致, 收拾下自己的老T500电脑, 用来做个家庭开发用机. 应为每次装系统都有GHOST备份的习惯, 所以需要提前搭建好开发环境. 而且新装系统的目的之一, 也是想研究下Andriod开发的问题, 所以开始了Java环境的配置. 问题: 操作系统是64位.数据库软件也都是64位, 开发JSP程序时也使用64位的Java JDK;  但是开发Andriod程序时, Andriod 4.4以下需要Java JDK 6.0版本, 并且最好是32位的(客户机不一定是64位的, 为了