关于Jdk1.8与其他版本共存时环境变量设置失灵的问题

如果大家看到这篇文章并且觉得好的话,请把它扩散出去,让更多的人看到它。引用时请注明出处,谢谢!

说明:网上很多文章写的时候都没有注明自己使用的版本,好多操作执行之后结果都不对,导致读者弄不清是否是版本原因所致。所以我在这里写明我用的版本,当大家看到这篇文章时可以参考,遇到问题也好检查是否是版本所致:

jdk版本:jdk1.6、jdk1.7u80、jdk8u162、jdk9.0.4

Windows操作系统:Windows 7 Service Pack 1 版本 6.1.7601

Mac操作系统: MAC OS Serria版本(不是High Serria)

参考文章:

关于Mac/Unix/Linux下环境变量的配置的知识:http://blog.csdn.net/u010416101/article/details/54618621

关于Windows下多版本jdk环境变量配置方法:http://blog.csdn.net/iamcaochong/article/details/56008545

解决无法删除/usr/bin目录下文件的问题:https://www.jianshu.com/p/22b89f19afd6

1. 扫盲(大神们请跳过本节)

1.1 环境变量的作用

(1)在命令行下避免频繁的目录切换操作

情景:有一个程序Java,需要读取某个文件(/data/file.txt)。,我们需要做如下的步骤:
cd 到Java的目录下;
执行Java命令;

当我们需要同时使用多个工具的时候,比如又有java、maven、git等等,而且是多台机器的时候,我们通常需要很多繁琐的cd操作。而配置环境变量 就可以使我们可以快速的运行这些脚本。

(2)方便同一程序的多版本切换
情景:在一台机器上同时装有JDK1.6、1.7和1.8,而且需要经常的切换,可以先配置局部变量:
export JDK1.7=/usr/apps/jdk1.7
export JDK1.8=/usr/apps/jdk1.8
export PATH=$JDK1.7/bin

这样,在改变的时候,就不需要去不到改变,而改变部分句可以了。

1.2 关于环境变量的基础知识

(1)Windows下的环境变量

 Windows下的环境变量分为系统变量和用户变量,且系统变量的优先级高于用户变量。环境变量是有优先级的,优先级低的环境变量不能覆盖优先级高的环境变量。为了不影响系统原有的配置(尤其是path,一旦改坏了很麻烦),我们尽量将其配置为用户变量而不是系统变量。

注意:在Windows环境变量中,要引用一个环境变量x,要在x的两边加上%,也就是%x%。同一环境变量中可能有多个值,这些值之间用分号(英文模式)分隔开。.表示当前目录。

(2)Mac/Unix/Linux下的环境变量

Mac/Unix下的环境变量主要配置在以下几个文件里面(Linux大同小异,可能文件名稍有差异,但原理是一致的),优先级如下(此处>为大于号,不是重定向的符号!)

/etc/profile   >   /etc/paths  >    ~/.bash_profile   >   ~/.bash_login   >    ~/.profile   >    ~/.bashrc

Mac中可供配置环境变量的地方主要是以下几处,我们一般会修改~/.bash_profile文件来设置环境变量

/etc/profile (建议不修改这个文件 ) 全局(公有)配置,不管是哪个用户,登录时都会读取该文件。

/etc/bashrc (一般在这个文件中添加系统级环境变量) 全局(公有)配置,bash shell执行时,不管是何种方式,都会读取此文件。

~/.bash_profile (一般在这个文件中添加用户级环境变量) 每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!

在Unix/Linux/Mac环境变量中,要引用一个环境变量x,要在x的前面加上$,也就是$x。同一环境变量中可能有多个值,这些值之间用冒号(英文模式)分隔开。.表示当前目录。

还有一种方式就是通过软链接方式来添加环境变量,使用ln命令生成软链接,再将其放入到/usr/bin目录下,这样在系统扫描环境变量时,这个变量就会被加载。

1.3 环境变量配置顺序和优先级对命令行运行结果的影响

环境变量的优先级即检索环境变量的优先顺序。环境变量的配置顺序和优先级非常重要,它关系到你设置的环境变量能否被检索到,因为系统在执行用户命令时,若用户未给出绝对路径,则首先在当前目录下寻找相应的可执行文件、批处理文件等。若找不到,再依次在PATH保存的这些路径中寻找相应的可执行程序文件。windows环境变量的查找顺序是按照文件的录入顺序从前往后寻找的,最前面一条的优先级最高,如果找到命令就不会再向后找了(若后面的环境变量指示的路径中存在与找到路径中相同的可执行文件,则后面路径中的可执行文件永远不会被检索到)。

2.问题描述

最近由于工作需要安装jdk,我在Windows、Mac两个平台上都安装了jdk1.6、jdk1.7和jdk1.8。并且配置了环境变量。但令人费解的是传统的配置环境变量的方法不好使。

2.1 Windows平台下多版本jdk环境变量传统配置方法

  jdk安装完成之后我们会在Windows下配置以下环境变量,所有环境变量均以用户变量的方式配置:

  JAVA_6_HOME = D:\dev\install\Java\jdk1.6.0_43       //jdk1.6的安装位置

  JAVA_7_HOME = D:\dev\install\Java\jdk1.7.0_80       //jdk1.7的安装位置

  JAVA_8_HOME = D:\dev\install\Java\jdk1.8.0_162     //jdk1.8的安装位置

  JAVA_HOME = %JAVA_7_HOME%       //设置默认jdk版本为1.7,以后如果想修改jdk版本,只修改这一项的数字就可以了(后面的会自动跟着变)

  classpath = .;%JAVA_HOME%\jre\lib\rt.jar;              //Windows操作系统设置类路径的方式

  path = %JAVA_HOME%\bin;                                   //配置path,使命令行能识别javac、java等命令

配置好之后,打开cmd窗口,输入以下两条命令看看jdk环境变量是否配置正确,我们默认配置了jdk1.7的版本。所以检测到的版本应该是1.7才对。命令如下:

javac -version     //版本应该是1.7

java -version      //版本应该是1.7

但是实际的结果却是这样的:


  显然:java命令输出的版本不对。这就是我们要说的问题:Jdk1.8安装后,环境变量配置失灵了!无论怎么改Java_HOME,java命令的版本号就是1.8,改不了!

2.2 Mac/Unix/Linux平台下多版本jdk环境变量传统配置方法

在用户的家目录(Unix/Linux中~表示用户的家目录)下找到.bash_profile文件,这个文件是隐藏文件(隐藏文件的前面有.号),要使用ls -a 方式才能看到。

 使用vi编辑这个文件,插入以下内容:

# 设置JAVA_HOME

export JAVA_6_HOME=`/usr/libexec/java_home -v 1.6`
export JAVA_7_HOME=`/usr/libexec/java_home -v 1.7`

export JAVA_8_HOME=`/usr/libexec/java_home -v 1.8`

# 设置默认的jdk版本

export JAVA_HOME=$JAVA_8_HOME

# 设置切换jdk版本的命令,指定别名
echo "If you want to change jdk version, please input jdk6, jdk7 or jdk8 to change jdk version"
alias jdk8="export JAVA_HOME=$JAVA_8_HOME"
alias jdk7="export JAVA_HOME=$JAVA_7_HOME"

alias jdk6="export JAVA_HOME=$JAVA_6_HOME"

# 设置classpath
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

export CLASSPATH

# 设置Path
PATH=$JAVA_HOME/bin:$PATH

export PATH

保存文件退出后,要刷新环境变量设置,否则新设置的环境变量不生效(两种方法任选一种)

(1)在终端中输入source ~/.bash_profile  命令,此方法不用重启终端即可生效(推荐)

(2)退出终端之后重启终端

 接下来验证环境变量是否设置成功,主要是检查javac和java命令是否可以识别,若可以识别,输出的版本是否是1.7,然后检查环境变量是否可以切换。测试命令如下:

javac -version   //输出当前javac的版本,应当是1.7

java -version    //输出当前java的版本,应当是1.7

jdk6   //切换为jdk1.6版本

javac -version  //输出当前javac的版本,应当是1.6

java -version  //输出当前java的版本,应当是1.6

实际测试的效果如下:


显然,无论版本怎么切换,javac和java的版本都不是我们想要的结果。

3. 探索问题产生的原因

3.1 Windows下的探索

通过检查其他环境变量,发现了一些目录下也含有java.exe,并且其所处的环境变量优先级比我们设置的Path要高,多数在系统环境变量path下面,共有以下几种情况:

1.发现系统变量的Path中配置有   C:\ProgramData\Oracle\Java\javapath;  ,进入该目录查看,发现:


2.发现系统变量的Path中配置有   %SystemRoot%\system32;   也就是:C:\Windows\System32 ,这个路径下也有java的文件:


按照环境变量的检索顺序,先检索系统变量,再检索用户变量系统变量Path中的这些路径扫描的顺序一定比我们设置的Path要靠前一旦检测到系统变量Path位置的java.exe后,就不会再扫描我们设置的Path。所以java的版本号不受我们配置的JAVA_HOME影响,无论怎么改JAVA_HOME都不能改变java的版本。但是因为这些目录下没有javac.exe,所以javac不受此影响,当切换JAVA_HOME时,javac的版本会按照我们预期的想法跟着变。

3.2 Mac下的探索

按照优先级由高到低的顺序(关于优先级请参考1.2小节(2)部分)依次检查环境变量配置文件,发现了一些目录下也含有java和javac,并且其所处的环境变量优先级比我们设置的Path要高:

在检查/etc/paths文件中配置的环境变量时,发现/usr/bin目录下有java和javac:


可以看到,这些文件都是以链接的形式存在的。这些文件的存在导致Mac检索不到我们设置的Path。

3.3 原因分析

jdk1.8以前的版本都是开发人员自己完成jdk的环境变量配置。jdk安装程序不会添加额外的环境变量。直到1.8某个版本之后,jdk的安装程序会自动在系统变量path中添加自己的路径。很多其他的程序设计语言SDK安装程序也会这么做,比如说Python。Oracle这样做的目的也是出于好心,为的是使开发人员减少环境变量的配置工作,简化jdk安装流程,方便程序的运行。在只安装一个版本的jdk情况下,这么做不但没错,而且很方便。但是一旦涉及多版本安装,这个好心的自动配置就会制造很多麻烦。

4.问题解决

4.1 Windows下的解决方案

去掉环境变量里面多余的的配置就行了。

1.系统-高级系统设置-环境变量 系统变量中的Path值最前面的  C:\ProgramData\Oracle\Java\javapath;  去掉;


2.找到目录C:\Windows\System32,将java.exe,javaw.exe,javaws.exe删除;

3.此时打开cmd,测试环境变量就没问题了。jdk版本也可以随意更换。


4.2 Mac下的解决方案

解决方法:删掉/usr/bin目录下所有以java开头的链接。

注:由于El Capitan(或者更高版本,包括Serria和High Serria)加入了Rootless机制,使得root用户不再能够随心所欲的读写很多路径了。Rootless机制是Mac的一种保护机制,它是对抗恶意程序的最后防线。

执行删除操作前,要先关闭 Rootless。重启按住 Command+R,进入恢复模式,打开终端。

关闭命令:csrutil disable

重新启动后然后切换到root用户,找出/usr/bin目录下所有以java开头的链接。命令如下:

su
Password:
cd /usr/bin/

ls -l | grep java

删除它们

rm -f java

rm -f javac
rm -f javadoc
rm -f javah
rm -f javap
rm -f javapackager 
rm -f javaws

删掉文件后最好启用Rootless以阻止恶意程序利用Root权限破坏系统。方法是重启按住 Command+R,进入恢复模式,打开Terminal

启用命令:csrutil enable

重启计算机。

按照网上的说法,这样的配置可以方便的实现jdk版本切换,即输入jdk7就让jdk1.7生效,输入jk8就让jdk1.8生效。但是在我机子上操作时却发现不是这样,网上的文章都是只配置了JAVA_HOME和classpath,没在PATH中加入$JAVA_HOME/bin这一项。在2.2小节中配置的环境变量在输入jdk6之后只是JAVA_HOME变成了jdk1.6的路径,但是path和classpath还是指向1.7,无论怎么切换都指向1.7,所以那段脚本不能正常的完成环境变量的切换,必需手工修改.bash_profile,然后用source使之生效才可以,因为它在修改$JAVA_HOME时没能动态修改classpath和path,所以导致javac -version命令的输出无论怎么切换都是1.7

知道了错误产生的原因就不难想出错误的解决方案了。只要在输入jdk6时,修改完JAVA_HOME后再想办法修改classpath和path就可以了。显然,alias一行命令完不成这么复杂的操作,所以我将它写到一个shell脚本中,然后执行这个脚本修改环境变量。

首先,修改.bash_profile中的alias部分,改为执行我们自己写的脚本:

# Setting PATH for Java jdk
export JAVA_6_HOME=`/usr/libexec/java_home -v 1.6`
export JAVA_7_HOME=`/usr/libexec/java_home -v 1.7`
export JAVA_8_HOME=`/usr/libexec/java_home -v 1.8`

# set default jdk version
export JAVA_HOME=$JAVA_7_HOME

# set alias for different jdk versions
echo "If you want to change jdk version, please input jdk6, jdk7 or jdk8 to change jdk version"
alias jdk8='source ~/changejdk.sh jdk8'
alias jdk7='source ~/changejdk.sh jdk7'
alias jdk6='source ~/changejdk.sh jdk6'


# set classpath for Java
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export CLASSPATH

# Setting PATH Variables for Mac

PATH=$JAVA_HOME/bin:$PATH

export PATH


保存退出后,在当前用户家目录下新建一个changejdk.sh文件,修改此文件权限为755,即赋予其可执行权限:

cd ~

touch changejdk.sh

chmod 755 changejdk.sh


然后用vi编辑这个文件,插入以下内容:

#!/bin/bash

#This is a shell script which is used to change jdk version
if [ $1 = "jdk6" ]
    then
        echo "change to jdk6"
        export JAVA_HOME=$JAVA_6_HOME
        export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
        export PATH=$JAVA_HOME/bin:$M2_HOME/bin:$PYTHON_HOME/bin:$PATH
fi
if [ $1 = "jdk7" ]
    then
        echo "change to jdk7"
        export JAVA_HOME=$JAVA_7_HOME
        export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
        export PATH=$JAVA_HOME/bin:$M2_HOME/bin:$PYTHON_HOME/bin:$PATH
fi
if [ $1 = "jdk8" ]
    then
        echo "change to jdk8"
        export JAVA_HOME=$JAVA_8_HOME
        export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
        export PATH=$JAVA_HOME/bin:$M2_HOME/bin:$PYTHON_HOME/bin:$PATH
fi


保存退出后,使用source ~/.bash_profile命令使配置的环境变量生效。

再来测试一下,现在就可以随意切换了。


现在如果想要加装jdk1.9非常方便,装好后我们只需要修改~/.bash_profile文件,加入jdk1.9的环境变量(写法与之前版本略有不同,用红色标注):

# Setting PATH for Java jdk

export JAVA_6_HOME=`/usr/libexec/java_home -v 1.6`
export JAVA_7_HOME=`/usr/libexec/java_home -v 1.7`
export JAVA_8_HOME=`/usr/libexec/java_home -v 1.8`
export JAVA_9_HOME=`/usr/libexec/java_home -v 9`

# set default jdk version
export JAVA_HOME=$JAVA_8_HOME

# set alias for different jdk versions
echo "If you want to change jdk version, please input jdk6, jdk7, jdk8 or jdk9 to change jdk version"
alias jdk9='source ~/changejdk.sh jdk9'
alias jdk8='source ~/changejdk.sh jdk8'
alias jdk7='source ~/changejdk.sh jdk7'
alias jdk6='source ~/changejdk.sh jdk6'


编辑完之后保存文件退出

改一下我们的脚本changejdk.sh:

!/bin/bash
#This is a shell script which is used to change jdk version
if [ $1 = "jdk6" ]
    then
        echo "change to jdk6"
        export JAVA_HOME=$JAVA_6_HOME
        export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
        export PATH=$JAVA_HOME/bin:$M2_HOME/bin:$PYTHON_HOME/bin:$PATH

fi

if [ $1 = "jdk7" ]
    then
        echo "change to jdk7"
        export JAVA_HOME=$JAVA_7_HOME
        export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
        export PATH=$JAVA_HOME/bin:$M2_HOME/bin:$PYTHON_HOME/bin:$PATH

fi

if [ $1 = "jdk8" ]
    then
        echo "change to jdk8"
        export JAVA_HOME=$JAVA_8_HOME
        export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
        export PATH=$JAVA_HOME/bin:$M2_HOME/bin:$PYTHON_HOME/bin:$PATH

fi

if [ $1 = "jdk9" ]
    then
        echo "change to jdk9"
        export JAVA_HOME=$JAVA_9_HOME
        export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
        export PATH=$JAVA_HOME/bin:$M2_HOME/bin:$PYTHON_HOME/bin:$PATH
fi


保存退出,再试一下,切换时没有问题:


  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值