我遇到了 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