【问题标题】:Confusion with Java packages与 Java 包混淆
【发布时间】:2014-10-31 21:22:29
【问题描述】:

所以我以为我了解包,但事实证明我不了解。

  • 包内的类:我有这个文件夹结构:mypackage/mysubpackage。在 mysubpackage 文件夹中,我有 2 个类:

    package mypackage.mysubpackage;
    
    public class Class1 {...}
    

    package mypackage.mysubpackage;

    public class Class2 {...}

但是,当我在目录 mypackage/mysubpackage 中使用 javac Class1.java 编译 Class1(使用 Class2 中的方法)时,它看不到 Class2:

Class1.java: error: cannot find symbol
    Class2 c = new Class2();
    ^
symbol:   class Class2
location: class Class1

如果我在包含mypackage/mysubpackage 的目录中运行javac Class1.java,它工作正常。编译不应该在 mysubpackage 文件夹中工作吗?

  • 另一个包中的类:现在,我有另一个类,其中包含我希望所有子包都可以访问的方法,所以我在 mypackage/commons 中创建了一个最终的 Commons.java

    package mypackage.commons;
    
    public final class Commons {
    
        public static double method() {...}
        ...
    }
    

然后我更新 Class2 导入该类,以便我可以在类中使用它的方法:

    package mypackage.mysubpackage;

    import mypackage.commons.*;

    public class Class2 {...}

现在它没有找到我在最终类中定义的方法:

./mypackage/mysubpackage/Class2.java: error: cannot find symbol
        double var = method();
                        ^
symbol:   method method()
location: class Class2

不应该找到吗?我想我正确地导入了它,方法是静态的,类是最终的。为什么不识别?

干杯!

【问题讨论】:

  • “使用 javac Class1.java”——这是你的错误。您应该编译为“javac package/subpackage/Class1.java”。或者在 javac 上指定适当的类路径。
  • 你能添加你的代码吗?
  • (类必须位于与其包对应的目录结构中的某个位置。)
  • @HotLicks 好的,这就是为什么当我在包含它们的文件夹中时它可以工作的原因。我认为它也可以在本地文件夹中工作。
  • 如果你想在不命名类的情况下调用静态方法,你必须导入类,而不仅仅是包。

标签: java class static packages final


【解决方案1】:

看起来您的问题在于从命令行启动 Java 编译器时设置工作目录的位置。

我建议您选择一个集成开发环境 -- Eclipse is a good one。使用 IDE,您不会遇到此类问题。这是我刚刚在 Eclipse 中创建的类,它们可以正确编译。

通用

package com.example.packagecommons;

public class Commons {

     public static double method() {
        return 0;}
}

Class1

package com.example.packages;

public class Class1 {
    private Class2 c2;
    public Class1() {
        c2 = new Class2();
    }
}

Class2

package com.example.packages;

import com.example.packagecommons.Commons;
public class Class2 {
    private double initialValue;
    public Class2() {
        initialValue = Commons.method();
    }
    public double getValue() {
        return initialValue;
    }
}

【讨论】:

  • 有趣,所以我应该在文件夹层次结构中使用三个级别?我会试试的。奇怪的是,您仍然应该将该方法称为Commons.method。关于 IDE,我的 Windows 笔记本电脑中有 NetBeans,但它正在修复中,所以我一个人使用不属于我的 Ubuntu,我不想在上面安装东西。这就是为什么我必须在 CLI 中完成这项工作。另一方面,它应该起作用。
  • 不..你不需要三层,这只是我自己的Java StackOverflow的包装结构。你可能会想要 com..xxx (如果你共享代码来识别你)。
  • 好的,三层结构也不起作用。还是不认识方法。不知道为什么,Commons.javapublic final,它的方法是public static,文件夹层次好像没问题。
  • 您确实将代码放在与您的包名称匹配的文件夹结构中,对吧?
  • 是的,我在我的问题中这么说 =) 类文件也匹配类名和所有内容。
【解决方案2】:

假设您的两个类 Demo01 和 Demo03 在包 pack1.subpack 中,而您的 Demo02 在 pack2

所以层次结构是这样的

  • someDrive/pack1/subpack/Demo01
  • someDrive/pack1/subpack/Demo03
  • someDrive/pack2/Demo02
  • someDrive/pack1/common/Demo04

Demo01 在哪里

package pack1.subpack;
import pack2.Demo02; // need to add this if calling class of different package
import pack1.common.Demo04; // if you are going to use Demo04 class in Demo01 class
public class Demo01 {

public void run() {
    System.out.println("--running Demo01-");
}
public static void main(String[] args){
    Demo01 demo01 = new Demo01();
    demo01.run();
    Demo02 demo02 = new Demo02();
    demo02.run();
    Demo03 demo03 = new Demo03();
    demo03.run();
    Demo04.run();
 }
}

Demo02 是

package pack2;
public class Demo02 {

public void run() {
    System.out.println("--running Demo02--");
}
}

Demo03 是

package pack1.subpack;   
public class Demo03 {

public void run() {
    System.out.println("--running Demo03--");
}
}

Demo04 是

package pack1.common;

public final class Demo04 {

public void run() {
    System.out.println("--running Demo04--");
}
}

然后使用javac pack1/subpack/Demo01.java编译它

并使用java pack1/subpack.Demo01执行它

【讨论】:

  • 非常全面的例子,谢谢。这解决了第一个问题,但我仍然无法使我的第二个示例工作,尽管我的文件夹层次结构是正确的,而且我认为调用也是正确的。
  • 检查 Demo01(import) 和 Demo04 的编辑,它必须澄清你的困惑
  • 感谢您的编辑。这正是我所拥有的,一个package pack1.subpack;,然后是一个import pack1.common.Demo04;,然后我在Demo01 中调用Demo04 方法,它会抛出一个错误。我的Demo04 类是final,它的方法run()static,所以我不知道出了什么问题。
  • 它工作正常检查Demo04和Demo01如何调用Demo04的run()
【解决方案3】:

我知道这个帖子很旧,但我想澄清一下,以帮助未来的观众。

您的第一个问题基本上是,Java 运行时系统如何知道在哪里查找您创建的包?记住这 3 条规则(其中一条必须适用):

  1. 您的主包必须位于要找到的当前工作目录的子目录中。
  2. 您可以通过设置CLASSPATH 环境变量来指定一个或多个目录路径。
  3. 当您通过终端/cmd 执行代码时,您可以将-classpath 选项与javajavac 一起使用来指定类的路径。

要回答您的第一个问题,您正在执行来自mypackage/mysubpackage 的代码。要让 Java 运行时识别 Class2,您必须从 mypackage 执行。

回到第二个问题,当你使用*导入一个包的所有内容时,你需要通过在静态类成员前面显式写类名来引用它们,因为Java不知道包中的哪个类你指的是。因此,在您的代码中,您必须编写 Commons.method() 而不仅仅是 method()。如果您不想一次又一次地为类的名称添加前缀,则可以显式导入所需的特定类。在您的情况下,这将是mypackage.commons.Commons。然后可以直接调用method()(前提是静态的)。

【讨论】:

    【解决方案4】:
    sh$ cd package/subpackage
    sh$ javac Class1.java
    

    将导致错误,因为编译器将尝试在当前目录的package/subpackage 子目录中定位Class2

    你必须这样编译:

    sh$ javac package/subpackage/Class1.java
    

    这是一个完整的工作示例:

    sh$ cat pkg/subpackage/Class1.java
    package pkg.subpackage;
    
    import pkg.commons.Class2;
    
    public class Class1 {
        public static void main(String args[]) {
            Class2.doSomething();
        }
    }
    
    sh$ cat pkg/commons/Class2.java 
    package pkg.commons;
    
    public class Class2 {
        public static void doSomething() {
            System.out.println("hello");
        }
    }
    
    sh$ javac pkg/subpackage/Class1.java
    sh$ java pkg.subpackage.Class1
    hello
    

    【讨论】:

    • "BTW 包是一个非常糟糕的包名。"好吧,我认为很明显这些是为了示例而使用的名称。我既没有将我的类命名为“Class1”和“Class2”,也没有将我的方法命名为“method()”。
    • @XiruxNefer 我明白这一点。但即使是一个示例,它也不适合,因为它会阻止正确编译,而 Class1method 等是有效的标识符。我从答案中删除了它。
    • 很公平。我很抱歉。
    猜你喜欢
    • 1970-01-01
    • 2017-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-09
    • 2016-07-18
    • 2014-04-15
    • 1970-01-01
    相关资源
    最近更新 更多