了解Java类路径:手动构建项目

This is the second post in a series looking to understand Java projects. Earlier, we looked at how Java actually gets installed onto a macOS system, and now we're going to build a basic app. Then we'll move on to incorporating the same app with help from Gradle, a popular build tool, and we'll finish by incorporating our project into the IntelliJ IDE.

Our directory structure

我们将编译一个完整的Hello World版本,我们夸大的示例将使用软件包,库和测试,因为它更能表明我们在野外发现的项目。 该项目面向那些使用Java做了一点工作并且不会在工具之外的语法上进行过多介绍的人。

We'll be loosely following the conventions of the Maven standard directory layout, which is admittedly a little overkill for our tiny app - but we're also going to charge ahead with it because it's indicative of the conventions we'll commonly run into when working with Java. Here's how that looks:

.
├── bin
├── lib
│   ├── jfiglet-0.0.8.jar
│   └── junit-platform-console-standalone-1.4.2.jar
└── src
    ├── main
    │   └── java
    │       └── space
    │           └── gaston
    │               ├── greeter
    │               │   └── Greeter.java
    │               ├── helloWorld
    │               │   └── HelloWorld.java
    │               └── textEffects
    │                   └── Bubble.java
    └── test
        └── java
            └── space
                └── gaston
                    ├── greeter
                    │   └── GreeterTest.java
                    └── textEffects
                        └── BubbleTest.java

让我们解压缩这里的内容:

  • bin will contain our compiled .class files
  • lib will hold our third-party libraries. In this case we're using JFiglet and the JUnit test runner, which we'll get back to later.
  • src will house our .java source code. Within src you have subdirectories main and test , which both have a java subdirectory to denote the language, and then the standard Java package hierarchy. Eventually, after months of digging, you finally stumble upon our actual .java files.

Ĵust a quick caveat: I haven't checked the lib folder into Git so you'll need to grab the JFiglet and JUnit .jar files from Maven if you're looking to build this project yourself. This is, partially, to expose how fiddly it is to manage dependencies manually and help us understand how, later on, how awesome it is that other tools can come to our rescue.

.java, .class and .jar

好的,那时候我扔了很多文件类型。 我认为被我们的IDE隐藏在许多这些细节中是完全普遍的,因此下面是这些类型的作用的快速摘要:

  • 一种.java文件是人类可读的Java源代码的纯文本文件-尽管可以肯定的是,就Java语法的某些方面而言,“可读”的名称还是有争议的。 基本上,.java文件是我们将人肉怪物悬吊在代码中的文件。一种。类文件是编译后的Java字节码,可由Java虚拟机(运行我们的Java程序的公认的时髦工具)执行。 这些冷的机械文件是计算机喜欢读取的文件。一种。罐文件是的档案。类为了方便起见,所有文件(和其他必要的资源)都整齐地压缩了。

javac and java

我们的两个JDK二进制文件负责编译和运行我们的代码:Java语言和爪哇。 简而言之,Java语言负责使我们.爪哇文件成。类那个文件爪哇能跑。

如果我们把所有的准系统放在一起HelloWorld.爪哇,然后我们可以将其作为参数Java语言并运行它爪哇:

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Oh no, not another Hello World example...");
  }
}

没有多重.java文件,外部库或输出目录,无需担心,编译和运行它就像将文件路径发送到Java语言然后运行输出:

$ javac HelloWorld.java
$ java HelloWorld
Oh no, not another Hello World example...

请注意。类该文件当前将与其配套源代码一起编译到同一目录中,我们称之为你好,世界直接与爪哇没有。类扩展名-后者会引发可怕的后果爪哇.lang.ClassNotFoundException错误,但这是另一回事了。 原来我们用爪哇运行Java类,而不是Java。类文件。

Classpath

我们现在可能会看到的另一个潜在错误是爪哇.lang.NoClassDefFoundError,通常是因为。类在编译时创建的文件(带有Java语言),但是当我们尝试使用爪哇。

警告那些体质脆弱的人,下一个词足以给您蒸气。 这个可怕的概念破坏了最强大的头脑,冒险家对事件的希望和梦想。 放弃所有希望进入的所有人...类路径。

让我们放大我们的主要.java文件:

.
├── greeter
│   └── Greeter.java
├── helloWorld
│   └── HelloWorld.java
└── textEffects
    └── Bubble.java

我们的招待员.java,你好,世界.java和气泡.java are all being stored in different packages (which,in Java,also means different directories)和have requirements of their own. 你好,世界同时包含招待员和a 气泡,with 气泡本身就是第三方的适配器FigletFontJFiglet中的类。罐在我们的LIB夹。

在我们的测试 folder we've got 测试s for 招待员和气泡,其中包括来自JUnit的类LIB以及要求实际招待员和气泡 classes to 测试.

欢迎朋友,到依赖项。

Java, while pretty smart, needs to know where to go sniffing for all these requirements - hence the classpath. We can get the scoop right from the horse's mouth:

类路径的默认值为“。”,表示仅搜索当前目录。 指定CLASSPATH变量或-cp命令行开关将覆盖此值。

也:

设置类路径可能很棘手,应谨慎执行。

真是迷人。 本质上,我们的类路径需要包含我们的路径。罐文件到包层次结构的顶部。 可以通过您不应该使用的环境变量进行设置,也可以使用更好的选项进行设置-cp旗。

它还有助于解释常见的Java陷阱,您可以在其中尝试运行爪哇没有光盘首先进入目录。

$ java bin.space.gaston.helloworld.HelloWorld
Error: Could not find or load main class bin.space.gaston.helloworld.HelloWorld
Caused by: java.lang.NoClassDefFoundError: space/gaston/helloworld/HelloWorld (wrong name: bin/space/gaston/helloworld/HelloWorld)

箱子您会看到,它不是Java包层次结构的一部分,但是如果您不在文件夹中,则确实需要将其放在类路径中。 因此,以下两项都可以工作:

$ cd bin
$ java space.gaston.helloworld.HelloWorld
$ java -cp bin space.gaston.helloworld.HelloWorld

Bringing it all together

考虑到所有这些,我们可以开始将文件编译为箱子目录。 从项目目录的顶部开始工作。

1. Compiling our main folder:
$ javac -d bin -cp lib/jfiglet-0.0.8.jar src/main/java/space/gaston/greeter/Greeter.java src/main/java/space/gaston/helloWorld/HelloWorld.java src/main/java/space/gaston/textEffects/Bubble.java

我们现在正在使用-d标志以指定我们的编译文件应在何处结束。 我们正在手动喂食我们的每一个.java文件到Java语言,所以我们不需要将它们添加到类路径中,但是我们确实需要添加JFiglet。罐文件,以便气泡可以编译。

2. Compiling our test folder:
$ javac -d bin -cp lib/junit-platform-console-standalone-1.4.2.jar:lib/jfiglet-0.0.8.jar src/main/java/space/gaston/textEffects/Bubble.java src/test/java/space/gaston/textEffects/BubbleTest.java src/main/java/space/gaston/greeter/Greeter.java src/test/java/space/gaston/greeter/GreeterTest.java

我们需要同时添加JFiglet和JUnit。罐文件添加到类路径中,现在我们还必须将每个测试文件及其测试文件提供给编译器。 我们可以有效地合并第1步和第2步,但是出于演示目的将其分解是很好的,因为我认为这有助于说明发生了什么。

现在,我们的bin文件将如下所示-请注意,我们的目录结构。类文件必须与.java源文件:

.
├── BubbleTests.class
├── GreeterTests.class
└── space
    └── gaston
        ├── greeter
        │   └── Greeter.class
        ├── helloworld
        │   └── HelloWorld.class
        └── textEffects
            └── Bubble.class
3. Running our tests:
$ java -jar lib/junit-platform-console-standalone-1.4.2.jar -cp bin:lib/jfiglet-0.0.8.jar --scan-class-path
╷
├─ JUnit Jupiter ✔
│  ├─ BubbleTests ✔
│  │  └─ helloReturnsAsciiHello() ✔
│  └─ GreeterTests ✔
│     ├─ greetWithArgumentSteveReturnsHelloSteve() ✔
│     └─ greetWithNoArgsReturnsHelloWorld() ✔
└─ JUnit Vintage ✔

我们的JUnit版本可以在命令行上运行。 我们正在传递--scan-class-path标志以使JUnit自动在我们的类路径上查找所有测试,因此这需要添加箱子到类路径的文件夹(因为我们位于项目文件夹的顶部)以及JFiglet,这仍然是气泡。

而且,是的,测试通过了。

4. Running our main app:
$ java -cp bin:lib/jfiglet-0.0.8.jar space.gaston.helloworld.HelloWorld
  _   _          _   _             ____    _
 | | | |   ___  | | | |   ___     / ___|  | |_    ___  __   __   ___
 | |_| |  / _ \ | | | |  / _ \    \___ \  | __|  / _ \ \ \ / /  / _ \
 |  _  | |  __/ | | | | | (_) |    ___) | | |_  |  __/  \ V /  |  __/
 |_| |_|  \___| |_| |_|  \___/    |____/   \__|  \___|   \_/    \___|

不,我也不知道为什么我们要它输出“ Hello Steve”。

很好。 我们已经做到了。 但是,天哪,对于一个简单的,完全人为的应用程序,这还不是很多吗? 您能想象一下,每次您对应用程序进行更改并需要重新编译时,会产生字面的印象吗? 我不了解你,但是如果我必须像那样工作一周以上,我会像我在扮演爱德华·蒙克的《呐喊》一样永久性地被困住。

在下一篇文章中,骑兵将进军以拯救我们一生永无休止的建造恐怖。


这个帖子对您有用吗? 对于是否有任何可以说得更清楚或更能说明问题的评论和反馈,我深表感谢。 我也非常感谢任何更正!

from: https://dev.to//martingaston/understanding-the-java-classpath-building-a-project-manually-3c3l

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值