您当前所在位置:首页软件教程软件编程Java命令行运行错误 找不到或无法加载主类问题的解决教程

Java命令行运行错误 找不到或无法加载主类问题的解决教程

归类:软件编程更新时间:2024-01-11 22:13:33作者:互联网人气:175

虽然学习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_HOMED:\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类加载路径参数中指明库的位置。

本文地址:http://9zoku.com/ruanjianbc/634.html
版权声明:本文内容来自互联网,该文版权归原作者所有。本站仅提供信息存储空间服务,不拥有文章所有权,不承担相关法律责任。若对本内容有异议或投诉请与管理员联系 5604882#qq.com(请将#换成@)。