【问题记录】找不到或无法加载主类HelloWorld

背景

在写《【java基础(四)】hello, world》时,无意遇到的一个问题,对于一个老程序猿在hello, world中遇到的问题却想不出来一个所以然,所以专门补了补功课。

问题描述

使用记事本编程hello, world,手动javac编译,java执行。在未使用package时一切正常,使用package后,一下懵了。

问题重现

  • 使用记事本编程hello, world

源码:

public class HelloWorld {

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

}
  • 使用javac编译,java执行,一切正常。

  • 在源码上使用package。

源码:

package hello;

public class HelloWorld {

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

}
  • 使用javac编译,java执行,错误重现。

问题解决

从问题现象上来看,很明显可以看出是package的问题,但是我却不明白问题出在哪里,于是寻求答案。

参考文章:解决dos窗口下运行.class文件出现错误: 找不到或无法加载主类 HelloWorld

  • 解决方法一

去掉package。

扫描二维码关注公众号,回复: 11147700 查看本文章
  • 解决方法二

使用javac -d . HelloWorld.java编译。

使用java hello.HelloWorld执行。

javac -d . HelloWorld.java
java hello.HelloWorld

深度学习

虽说问题可以解决,但最终还是归咎与不理解package关键字。于是对package进行补课学习。

参考文章:java初学者,如何理解package和import?

  • 以下是对文章的关键部分的引用(重点在第5条):

作者:枫亦
链接:https://www.zhihu.com/question/278555424/answer/667214584
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1.java文件通过javac编译工具编译变成 class文件。

2.java执行工具可以执行class文件。

3.sourcepath定义了源码文件搜索的“根路径”,可以设置多条根路径。

4.classpath定义了class文件搜索的“根路径”,可以设置多条根路径。

5.package关键字指明当前源文件和此文件被编译成class后的文件所在“相对路径”, package和电脑文件系统的目录其实是一个意思,比如 com.xx.yy 对应 Linux的 com/xx/yy 对应windows的com\xx\yy。但是注意一个问题,这个路径是相对的,因为没有根,根需要从sourcepath或classpath里面去找。

 比如根 classpath = D:\A;D:\B。
 那么完整的物理路径就可能是 D:\A\com\xx\yy 也可能是 D:\B\com\xx\yy
 所以同属一个package的源码文件也即开头都用了 package com.xx.yy 的源码文件不一定非要在同一个物理目录下面。

6.javac编译过过程中遇到import语句,就会根据 “classpath + 相对路径”去找 class文件,根据“sourcepath+相对路径“去找源文件。规则是这样的:

  • 如果只有class文件,就直接用class文件。
  • 如果只有源文件,就把源文件编译成class文件。
  • 如果既有class文件又有源文件,就会检查文件修改的时间戳,如果class文件晚于源文件,就直接用class文件,如果早于源文件,就重新编译源文件。

另外关于找到的标准要满足两条:

  • 文件名必须跟类名一样。
  • 文件里面package定义的相对路径必须和import定义的相对路径一样。

7.简单说一下class文件,前面提到的相对路径信息在源码中是package关键字指明的,class文件中也有这些信息,只不过不是在文件头部指明,而是直接内化成类全称了,看个例子:

源码:
package A;
public class Hello{
  public static void main(String args[]){   
     System.out.println("Hello World!");
  }
}

class文件 反编译效果:
public class A.Hello {
  public A.Hello();
  public static void main(java.lang.String[]);
}

注意 Hello类直接变成了 A.Hello,也就是类名称自动包含了路径信息。

8.java执行class文件时,遇到 如new、getstatic 等等需要创建类实例的相关指令时,就会加载相关的class文件(也称动态加载),那么jvm会去哪里找class文件呢?跟javac类似还是通过“classpath + 相对路径”去找。

9.jar文件就是把class文件以及相对目录结构打包而成的文件,感兴趣可以直接解压看看。

思考

跟同年出道的朋友讨论此问题,发现对package一样的懵。我感觉产生这种问题的原因是:

  • 太过于依赖IDE。这也不能是一种错误,毕竟IDE带来的便利性是没有办法替代的。
  • 基础不扎实。很多问题都不喜欢追究溯源,只是到了解决问题的步骤就可以了。
  • 意想(瞎想)问题原因。我感觉这是现在人们的通病,自己本身不知道问题出在那里,单纯的根据现象猜测出现问题的原因,并且说的理直气壮,其实根本没有理论的支撑。就好像我朋友说这个问题是由于“引入了不存在的包”,这种“不存在的包”这种词语就属于意想出来的。
  • 不理解本质。想package的感念,很多人都理解为和文件目录一样,我感觉你可以这样理解package,但不可以把package和文件目录划等号,更好的理解应该是命名空间(本人能力有限,嘴皮也有限,不多陈述)。

捐赠

若你感觉读到这篇文章对你有启发,能引起你的思考。请不要吝啬你的钱包,你的任何打赏或者捐赠都是对我莫大的鼓励。

原创文章 27 获赞 18 访问量 3万+

猜你喜欢

转载自blog.csdn.net/b635781894/article/details/105785219