2

我是一位经验丰富的程序员,但多年来没有使用过 Java - 主要是 C# - 并且过去使用过 IDE。我正在尝试从我的 Mac 上的命令行编译一些代码,但无法让我的测试文件找到我的源代码。我假设问题出在包、文件结构、类路径和导入语句空间的某个地方——但我已经投入了几个小时(包括在 Stack Overflow 上寻找)并且仍然卡住了。

这是我所拥有的:

Directory structure:
ProjectName
|
 --src
    |
     --SourceClass
 --test
    |
     --SourceClassTest
 --external
    |
     --testng-6.8.7.jar

我的 SourceClass 看起来像这样:

package ProjectName;

public class SourceClass<T>{

}

很简单。显然,还会有更多——但我想首先确保在我实际进行编码之前所有这些设置都是正确的。

我的测试类如下所示:

package ProjectName;

import java.util.*;
import org.testng.Assert;
import org.testng.annotations.*;


    public class SourceClassTest{

            @Test
            private void createEmptySourceClass(){
                    SourceClass<Object> sourceClass = new SourceClass<Object>();
                    Assert.assertTrue(sourceClass.isEmtpy());
            }

    }

sourceClass 编译时使用“javac src/*.java”没有问题,从“ProjectName”目录运行。我想看到这个失败并出现“SourceClass 没有 isEmpty() 方法”的错误,但是我从“ProjectName”目录运行 javac 是这样的:

javac test/*.java -classpath external/testng-6.8.7.jar

并得到这个例外:

test/SourceClassTest.java:12: error: cannot find symbol
        SourceClass<Object> tree = new SourceClass<Object>();
        ^
  symbol:   class SourceClass
  location: class SourceClassTest
test/SourceClassTest.java:12: error: cannot find symbol
        SourceClass<Object> sourceClass = new SourceClass<Object>();
                                       ^
  symbol:   class SourceClass
  location: class SourceClassTest
2 errors

我已经尝试了很多东西 - 添加导入语句,向 javac 命令添加源路径,将 sourceClass 编译为 jar 并将其放入 bin 目录中,然后将其添加到类路径中,但我无法得到测试找到 SourceClass 符号。

知道我在这里缺少什么吗?

4

3 回答 3

3

如果您编译到单独的目标目录中,它会起作用。例如,

mkdir target
javac -d target/ src/*.java
javac -classpath target/ test/*.java

当您这样做时javac src/*.java,它将在目录本身中创建.class文件。src默认情况下,您引用的任何类都假定在同一个包中。因此,即使您添加src/到类路径中,它也会查找src/ProjectName/SourceClass.class,但它没有找到。当您传递该-d target/选项时,它会创建正确的包层次结构,从而找到类。

javac官方文档中的相关文档:

您应该将源文件排列在反映其包树的目录树中。例如,如果您将所有源文件保存在 C:\workspace 中,则 com.mysoft.mypack.MyClass 的源代码应该在 C:\workspace\com\mysoft\mypack\MyClass.java 中。

默认情况下,编译器将每个类文件与其源文件放在同一目录中。您可以使用 -d 指定单独的目标目录(请参阅下面的选项)。

...

...

-d 目录设置类文件的目标目录。该目录必须已经存在;javac 不会创建它。如果类是包的一部分,javac 会将类文件放在反映包名称的子目录中,并根据需要创建目录。例如,如果您指定 -d C:\myclasses 并且类称为 com.mypackage.MyClass,则类文件称为 C:\myclasses\com\mypackage\MyClass.class。如果未指定 -d,javac 会将每个类文件放在与生成它的源文件相同的目录中。

注意:-d 指定的目录不会自动添加到您的用户类路径中。

于 2013-09-28T16:54:56.960 回答
1

我的猜测是找不到 SourceClass 因为定义该类的文件位于下src,并且您没有在 javac 命令行中提到该目录。

如果我是你,我会将文件层次结构更改为:

ProjectName/src/ProjectName/SourceClass.java
ProjectName/src/ProjectName/SourceClassTest.java
ProjectName/external/testng-6.8.7.jar

然后运行javac src/ProjectName/*.java -classpath external/testng-6.8.7.jar

或者保持文件层次结构不变,然后运行javac src/*.java test/*.java -classpath external/testng-6.8.7.jar

于 2013-09-28T16:45:24.217 回答
0

公认的答案是正确的,但它忽略了一个关键点:当要求 javac 编译*.java(而不是foo.java, 然后foo2.java...)时,它将它们视为一个包并接受它们之间的引用。

这就是魔法。其他语言使用头文件不那么隐式地做到这一点。

即使在阅读了这篇文章之后,我还是花了一些时间才弄清楚这一点,这与我固有的假设相反,即一个接一个地在文件上单独运行的程序会(应该)产生与在一组文件上运行该程序相同的结果。我的错; 这*不仅仅是一种便利,而是至关重要的。

于 2020-04-15T02:03:21.433 回答