Java命令行运行错误 找不到或无法加载主类问题的解决教程
虽然学习Java语言约有两年多,但在最近需要使用命令行工具编译并运行Java程序时,还是报错了。花费了一些时间,解决了该问题,发现解决方法在初学Java时使用过。一则,为了避免以后再出现同样的问题而浪费不必要的时间;二则,作为使用该语言的程序员,对于该语言的一些基本问题,应该有清晰的理解和认识;三则,网上的一些解决方案,不够完备。有的没有解释问题原因,直接给出答案;有的,未列举出某些常见情况的解决方案。因此,写此文章,让读者可以举一反三,深入理解问题。
一、 问题分析
找不到或无法加载主类,其主要原因有两个:
1. 类名错误
2. 类所在位置未添加至类加载路径中
二、 问题解决
本部分将针对在“一”中提出的两个问题发生原因,分别进行分析及处理。并且会介绍java的一些和处理问题相关的基本概念。
1. 类名错误
全限定类名:包名+类名。另外,当包名为空时(即代码不包含package语句),称类所在包为默认包
例如,以下代码的全限定类名为:“com.gzn.demo.HelloWorld”
1 2 3 4 5 6 7 | // 文件名HelloWorld.java package com.gzn.demo; public class HelloWorld { public static void main(String args[]) { System.out.println( "hello world" ); } } |
在运行java程序时,全限定类名可以唯一确定该文件,就像是文件系统中路径(相当包名)+文件名(相当类名)可以唯一确定一个文件一样。本质上包名发挥的作用和文件系统中的目录相同,有利于文件分隔避免重名。
现在存在一个问题,Java是如何识别一个类文件的包名的?
实际上,包名的识别是通过文件系统的目录实现的 。例如,上文提到的包名为“com.gzn.demo”的HelloWorld.java文件,该文件在文件系统中的位置为 “com\gzn\demo”,编译后的HelloWorld.class也在"com\gzn\demo"目录下,因此,在运行java程序后加载类时,只需在“com\gzn\demo”目录下,查看是否存在要查找的文件即可。简而言之,目录(或路径)名于包名存在一一映射的关系,可认为相等。
在Windows操作系统的命令行下,运行Java代码的语法格式为,注意,此时java命令位于目录com的上一级目录(一般为项目的目录名);类名不能包含扩展名.class:
Java 全限定类名
例如java com.gzn.demo.HelloWorld;包名为空则为java HelloWorld
Windows操作系统中还有另一种语法格式(其他系统未必可以),不常用,使用反斜杠代替了点好,之所以没用正斜杠,个人猜测是为了和系统的文件分隔符进行区分:
例如Java com/gzn/demo/HelloWorld; 包名为空则为java HelloWorld
可能出错情况一 :在命令行运行java程序时,类名包含了扩展名
在helloworld项目目录下运行java命令,HelloWorld.class文件在“com\gzn\demo”目录下,即包名为com.gzn.demo,上文已介绍,不在赘述。C:\Users\gzn\helloworld>java com.gzn.demo.HelloWorld.class
或者包名为空C:\Users\gzn\helloworld> java HelloWorld.class
上述写法,会出现报错,原因是它不符号java运行程序的语法格式,java可能把“HelloWorld.class”作为一个整体类名处理,那么要查找的文件可能是“HelloWorld.class.class”,显然是找不到的。
可能出错情况二 :运行Java命令时未指明全限定类名的包名部分或指明了包名但Java命令运行的位置不正确
假设HelloWorld.class,包名为com.gzn.demo,所在位置为: C:\Users\gzn\helloworld\com\gzn\demo
运行以下命令C:\Users\gzn\helloworld\com\gzn\demo>java HelloWorld
运行命令后,会在当前目录下,查找并读取该文件后,发现该类为“com.gzn.demo.HelloWorld”(全限定类名唯一确定一个类,上文已介绍)与我要运行的类“HelloWorld”并不是同一类,因此,找不到要运行的类。
于是,很自然的一个想法是运行以下命令C:\Users\gzn\helloworld\com\gzn\demo>java com.gzn.demo.HelloWorld
包名和文件名是一一映射的(上文已介绍),运行命令后,会从命令所在位置开始(即以命令所在位置为相对路径),查找“com\gzn\demo\”路径下的HelloWorld文件。由于“C:\Users\gzn\helloworld\com\gzn\demo”路径下根本不存在目录“com”(更不用说gzn\demo),因此,找不到运行的类。
正确的运行命令的方法,呼之欲出,只需改变命令的运行位置即可,如下所示C:\Users\gzn\helloworld>java com.gzn.demo.HelloWorld
运行命令后,会在“com\gzn\demo”路径下找到并读取HelloWorld文件,发现该类的全限定名为“com.gzn.demo.HelloWorld”,查找的类正是Java想要运行的类。
以上是比较初级的出错情况,下文将要介绍相对比较高级的出错情况,这也是其他博文未曾给出解决方案的情况。同时还会介绍classpath的概念,及使用方法。加油!
2. 类所在位置未添加至类加载路径中
类加载路径(Classpath):当你的程序依赖第三方或者自己写的类文件时,需要指出上述文件的所在位置,即类加载路径。Java虚拟机的类加载器会在你指定的路径中,查找你的程序所依赖的类文件(依赖的类文件 在import语句中指定)
classpath可以通过以下两种方式指定:
方式一:配置环境变量
这种方式是初学Java者肯定了解的方式,通常在下载完JDK后就会进行配置。然而在JDK1.5之后,官方已不建议使用这种方式来指定类加载路径,原因后文扩展部分会谈及。
说明:“.”表示在当前目录,即java等命令运行时所在目录;
dt.jar是关于运行环境的类库,主要是用于swing的包,如果不使用可以不配置;
tools.jar是工具类库,它在编译和运行一个类时被使用
方式二:java命令的-cp(或-classpath)参数指定(官方建议)
这种方式是JDK1.5后官方建议的方式。当你在命令行下运行java命令时,如果没有指定-classpath参数,那么默认使用环境变量中设置的ClASSPATH。官方建议,你在运行每个程序时,为其显示设置所依赖的类文件所在的位置,而不是使用“全局”性质的环境变量中CLASSPATH。一旦你运行程序时指定了-classpath参数,环境变量中的CLASSPATH就不会在使用,而是使用你参数的classpath。实际上,JDK1.5以后,官方已经不建议配置CLASSPATH环境变量。
语法格式如下:
java -cp <路径1;路径2;…> 全限定类名
路径:依赖的文件所在的绝对路径(或相对路径),如果类文件在jar包中,路径后还要写上jar包的名字,例如“C:\users\gzn\mylib\algs4.jar”
注意,“.”代表当前路径,即java命令运行时所在路径。
可能出错情况三 :存在依赖外部jar包时,命令行运行java命令,classpath参数中只是添加了外部jar包路径,没有添加当前目录“.”,导致要运行的类文件找不到。
或者,程序在IDE(eclipse、IDEA等)开发工具中可以运行,但是在命令行下不能运行,情况相同。
在某篇高赞博文中,依然存在的问题
下面,通过问题在现的方式,讲解解决方法。
项目简介:HelloWorld.java程序,位置“C:\Users\gzn\helloworld\com\gzn\demo”,依赖algs4.jar(位置C:\Users\gzn\helloworld)中的edu.princeton.cs.algs4.StdOut类,调用了该类的print函数,其API如下
public class StdOut
public static void print(String s); 打印输出指定的字符串
HelloWorld.java
1 2 3 4 5 6 7 8 | package com.gzn.demo; import edu.princeton.cs.algs4.StdOut; public class HelloWorld { public static void main(String args[]) { StdOut.print( "Hello World!" ); } } |
项目结构如下图所示:
在命令行运行程序时,存在外部依赖,不仅要在-cp (或-classpath)中指明依赖的路径,还有把当前路径加进去。因为当你指定了-classpath参数后,环境变量失效,于是环境变量CLASSPATHY中设置的当前目录“.”也就不能用了。虚拟机类加载器加载类的路径只能在classpath类加载路径指明的位置中查找,如果路径中没有添加当前目录“.”,也就是当前要运行的类所在位置没有添加到类加载路径中,显然会查找不到类。解决方法如下图所示:
三、扩展知识
1. JDK目录结构及环境变量配置介绍
JDK目录介绍
初学者环境变量配置如下:
变量名 | 值 |
---|---|
CLASSPATH | .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tool.jar (注,jdk1.5后无需配置) |
JAVA_HOME | D:\jdk8(JDK安装目录,视个人安装情况而定) |
Path | %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin |
Path为命令行工具指定命令的查找路径。命令的本质是可执行程序,设置后可以在命令行工具下运行java、javac、javah等常用的命令;
JAVA_HOME 指定了JDK(Java开发工具包)路径。设置后,无论是编译还是运行程序,类加载器都会从相应的目录中加载需要的类库。如运行javac编译命令,会从”%JAVA_HOME%\lib\tool.jar”加载需要的类;通过java命令运行程序,会从“%JAVA_HOME%\jre\lib\rt.jar”加载程序依赖的类;Java虚拟机会从“%JAVA_HOME%\jre\lib\ext\”加载依赖的类。
jdk中的函数库lib称为Java的标准库,指定了JAVA_HOME环境变量后就可以使用了,编译和运行会自动在相应位置查找依赖的类。而第三方库(如mysql-connector-java-5.1.40.jar)和用户自己定义的类库 在编译和运行时,需要在-cp类加载路径参数中指明库的位置。
版权声明:本文内容来自互联网,该文版权归原作者所有。本站仅提供信息存储空间服务,不拥有文章所有权,不承担相关法律责任。若对本内容有异议或投诉请与管理员联系 5604882#qq.com(请将#换成@)。