Я столкнулся со странностью JLS или ошибкой JavaC (не уверен, какой именно). Пожалуйста, прочтите следующее и предоставьте объяснение со ссылкой на отрывок JLS или Sun Bug ID, в зависимости от ситуации.
Предположим, у меня есть надуманный проект с кодом в трех "модулях" -
- API - определяет API-интерфейс - думаю, Servlet API
- Impl - определяет реализацию API - думаю, контейнер Tomcat Servlet
- Приложение - приложение, которое я написал
Вот классы в каждом модуле:
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. Предположим, мои jar API экспортируются через jar, скажем, api.jar, и, будучи хорошим гражданином, я ссылаюсь только на этот jar в моем classpath, а не на класс Impl, поставляемый в impl.jar.
Теперь, очевидно, в моей структуре есть недостаток, заключающийся в том, что классы 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.
Итак, это ошибка Java или какая-то странность JLS?
Компилятор: Sun javac 1.6.0_14