javac 编译,如何引用定义在其他文件夹的包

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javac 编译,如何引用定义在其他文件夹的包相关的知识,希望对你有一定的参考价值。

问题是由于你没有编译包路径,导致在使用类的时候找不到,请按如下方法进行编译并运行。第一步,编译DataForm.java
javac -d .\ DataForm.java
-d 这个参数会在 DataForm.java 文件所在路径下生成 data 文件夹,里面有一个文件 DataForm.clsaa 第二步,编译Service.java
javac -d .\ Service.java第三步,执行Service
java -cp .\ Service注意:
由于不知道你的 Service.java 是否有 package 目录,如果有将 package目录加到类鸣的前面。
如:
Service.java 中 package 路径如下:
package service;
执行脚本将变为:
java -cp .\ service.Service有问题请给我留言
参考技术A -classpath,
设定要搜索类的路径,
可以是目录,
jar文件,zip文件(里面都是class文件),
会覆盖掉所有在CLASSPATH里面的设定。
参考技术B javac
-classpath,设定要搜索类的路径,可以是目录,jar文件,zip文件(里面都是class文件),会覆盖掉所有在CLASSPATH里面的设定。
-sourcepath, 设定要搜索编译所需java 文件的路径,可以是目录,jar文件,zip文件(里面都是java文件)。
所以一个完整的javac命令行应该是这样的,
假设abc.java在路径c:\src里面,在任何的目录的都可以执行以下命令来编译。
javac -classpath c:\classes;c:\jar\abc.jar;c:\zip\abc.zip -sourcepath c:\source\project1\src;c:\source\project2 \lib\src.jar;c:\source\project3\lib\src.zip c:\src\abc.java

表示编译需要c:\classed下面的class文件,c:\jar\abc.jar里面的class文件,c:\zip\abc.zip里面的class文件
还需要c:\source\project1\src下面的源文件,c:\source\project2 \lib\src.jar里面的源文件,c:\source\project3\lib\src.zip里面的源文件,
注意:jar,zip里面的源文件不会有什么改动,目录下的源文件,有可能会被重新编译。
参考技术C package com.example.model;import java.util.ArrayList;import java.util.List;public class BeerExpert public List getBrands(String color)
List brands = new ArrayList(); return (brands);

重载的包私有方法导致编译失败 - 这是 JLS 怪异还是 javac 错误?

【中文标题】重载的包私有方法导致编译失败 - 这是 JLS 怪异还是 javac 错误?【英文标题】:Overloaded package-private method causes compilation failure - Is this a JLS oddity or javac bug? 【发布时间】:2010-12-23 14:26:37 【问题描述】:

我遇到了 JLS 的一个奇怪之处,或者一个 JavaC 错误(不确定是哪一个)。请阅读以下内容并提供解释,并酌情引用 JLS 段落或 Sun Bug ID。

假设我有一个人为的项目,其中包含三个“模块”中的代码 -

    API - 定义框架 API - 考虑 Servlet API Impl - 定义 API 实现 - 想想 Tomcat Servlet 容器 App - 我写的应用程序

这是每个模块中的类:

API - MessagePrinter.java

package api;

public class MessagePrinter 

    public void print(String message) 
        System.out.println("MESSAGE: " + message);
    

API - MessageHolder.java(是的,它引用了一个“impl”类 - 稍后会详细介绍)

​​>
package api;

import impl.MessagePrinterInternal;

public class MessageHolder 

    private final String message;

    public MessageHolder(String message) 
         this.message = message;
    

    public void print(MessagePrinter printer) 
        printer.print(message);
    

    /**
     * NOTE: Package-Private visibility.
     */ 
    void print(MessagePrinterInternal printer) 
        printer.print(message);    
    


Impl - MessagePrinterInternal.java - 这个类依赖于一个 API 类。顾名思义,它是为我的小框架中其他地方的“内部”使用而设计的。

package impl;

import api.MessagePrinter;

/**
 * An "internal" class, not meant to be added to your
 * application classpath. Think the Tomcat Servlet API implementation classes.
 */
public class MessagePrinterInternal extends MessagePrinter 

    public void print(String message) 
        System.out.println("INTERNAL: " + message);
    

最后,App 模块中唯一的类...MyApp.java

import api.MessageHolder;
import api.MessagePrinter;

public class MyApp 

    public static void main(String[] args) 
        MessageHolder holder = new MessageHolder("Hope this compiles");
        holder.print(new MessagePrinter());
    


所以,现在我尝试编译我的小应用程序 MyApp.java。假设我的 API jar 是通过一个 jar 导出的,比如 api.jar,并且作为一个好公民,我只在我的类路径中引用了那个 jar,而不是 impl.jar 中的 Impl 类。

现在,显然我的框架设计存在缺陷,即 API 类不应依赖于“内部”实现类。然而,令人惊讶的是 MyApp.java 根本没有编译。

javac -cp api.jar src\MyApp.java
src\MyApp.java:11: cannot access impl.MessagePrinterInternal class file for impl.MessagePrinterInternal not found

    holder.print(new MessagePrinter());
                 ^
      1 error

问题在于,由于方法重载,编译器正在尝试解析要使用的 print() 版本。但是,编译错误有点出乎意料,因为其中一种方法是包私有的,因此对 MyApp 不可见。

那么,这是 javac 的错误,还是 JLS 的一些奇怪之处?

编译器:Sun javac 1.6.0_14

【问题讨论】:

“由于运算符重载”应该是“由于方法重载” 【参考方案1】:

首先,我希望 api 包中的东西是接口而不是类(基于名称)。一旦你这样做了,问题就会消失,因为你不能在接口中访问包。

接下来的事情是,AFAIK,这是一个 Java 奇怪的东西(因为它没有做你想做的事)。如果您摆脱公共方法并将包设为私有,您将得到同样的结果。

将 api 包中的所有内容更改为接口将解决您的问题并在代码中提供更清晰的分离。

【讨论】:

即使您更改此代码以使用接口,您也可以通过声明接口包私有来重现相同的行为。例如,MessagePrinterInternal 可以是 API 包中的接口。事实上,我基于这个问题的生产代码正是这样做的。 如果接口是包,只有包外的任何东西都看不到。如果您只对接口进行编码(将所有变量和参数声明为接口),那么应该没有问题。不管有没有一个名为 API 的包包含接口、枚举、工厂和异常以外的东西,对我来说都是没有意义的。 很抱歉,您所说的另一件事是基于您所说的 - API 不应包含私有 thi fs 包,因为它应该是公开消费的东西。【参考方案2】:

我想你总是会争辩说 javac 可以更聪明一点,但它必须在某个地方停下来。它不是人类,人类总是比编译器更聪明,你总能找到对人类非常有意义但编译器傻眼的例子。

我不知道这件事的确切规范,我怀疑 javac 作者在这里犯了任何错误。但谁在乎?为什么不将所有依赖项都放在类路径中,即使其中一些是肤浅的?始终如一地这样做让我们的生活更轻松。

【讨论】:

有些类不应该在编译类路径中,因为它们只打算在运行时使用。例如,Sun Java 附带的 Sun 类。 例如?大多数 sun 类都在 rt.jar 中,编译时在类路径中。 直接使用 com.sun 类被普遍认为是最坏的做法:java.sun.com/products/jdk/faq/faq-sun-packages.html【参考方案3】:

JLS 或 javac 没有任何问题。当然这不会编译,因为你的类 MessageHolder 引用 MessagePrinterInternal 如果我理解你的解释正确的话,它不在编译类路径中。您必须将此引用分解到实现中,例如使用 API 中的接口。

编辑 1:澄清:这与您似乎认为的 package-visible 方法无关。问题是编译需要MessagePrinterInternal 类型,但类路径中没有它。当 javac 无法访问引用的类时,你不能期望它编译源代码。

编辑 2:我再次重新阅读代码,这似乎正在发生:编译 MyApp 时,它尝试加载类 MessageHolder。 MessageHolder 类引用 MessagePrinterInternal,因此它也尝试加载它并失败。我不确定 JLS 中是否指定了它,它也可能取决于 JVM。根据我使用 Sun JVM 的经验,加载类时至少需要所有静态引用的类可用;这包括字段的类型、方法签名中的任何内容、扩展类和实现的接口。您可能会争辩说这是违反直觉的,但我会回应说,一般来说,您对缺少此类信息的类几乎没有做任何事情:您不能实例化对象,不能使用元数据(Class 对象)等。那些背景知识,我会说你看到的行为是预期的。

【讨论】:

是的,但是使用 MessagePrinterInternal 的方法是包私有的。 MyApp.java 类将永远无法访问它。所以这是违反直觉的。 这对你来说可能违反直觉,但我认为他是正确的。试试看吧。 他的回答只是重申了我的问题。当然,源代码需要更改才能编译。我的问题:它在 JLS 中的哪个位置将此编译失败定义为预期行为?

以上是关于javac 编译,如何引用定义在其他文件夹的包的主要内容,如果未能解决你的问题,请参考以下文章

javac如何编译.java,.jar

重载的包私有方法导致编译失败 - 这是 JLS 怪异还是 javac 错误?

列出javac编译的Java源文件

当其他包中有Java文件时,如何编译多个Java文件?

java基础小测试

python中多重目录中的包引用怎么样?