在设计流体API时,有时我想使用接口返回类型,以便调用者可以轻松地遵循可用的方法,或者如果他没有,则会出现编译器错误(Step Builder pattern就是一个例子)。
但是当我想使用接口来指向下一个可用的方法时,例如:
package packageone;
public class SomeClass implements CanPrint {
private SomeClass() {
}
public static CanPrint get() {
return new SomeClass();
}
@Override
public void print() {
System.out.println("Runs fine!");
}
}
public interface CanPrint {//Compile error: must be defined in own file
public void print();
}
然而,启动快速测试工作正常(以下代码打印“运行正常!”):
package packagetwo;
import packageone.CanPrint;
import packageone.SomeClass;
public class Main {
public static void main(String[] args) {
CanPrint returnType = SomeClass.get();
returnType.print();
}
}
编译器可以通过包装整个类来“欺骗”:
package packageone;
public class Wrapper {
public static CanPrint get() {
return SomeClass.get();
}
public static class SomeClass implements CanPrint {
public static CanPrint get() {
return new SomeClass();
}
private SomeClass() {
}
@Override
public void print() {
System.out.println("Runs fine!");
}
}
public interface CanPrint {
public void print();
}
}
所以当前我希望将接口保持在与打算使用它的唯一代码相同的位置(因为调用者只需要方法),我将它包装在一个仅指向同一方法的包装器类中在内心阶层。
为什么会出现这种限制?另一个类可以导入接口,使用它,甚至可以实现自己的版本。所有这一切似乎没有问题。但它没有编译。
注意:我尽可能地简化了我的示例,但由于这个原因,人们为什么会选择这种设计可能不太清楚。
答案 0 :(得分:0)
为什么会出现这种限制?
它使编译器和人类更容易找到包含顶级类的源文件。
您可以通过以下方式公开界面:
ISomeClassCanPrint
。这是嵌套界面的另一个例子:
public static class SomeClassFactory {
public interface CanPrint {
public void print();
}
public static CanPrint get() {
return new SomeClass();
}
public static class SomeClass implements CanPrint {
@Override
public void print() {
System.out.println("Runs fine!");
}
}
}
该限制由Java Language Specification, section 7.6: Top level type declarations:
涵盖当且仅当包存储在文件系统(第7.2节)中时,如果在由组成的名称下的文件中找不到类型,则主机系统可以选择强制执行编译时错误的限制。如果满足以下任一条件,则类型名称加上扩展名(例如.java或.jav):
该类型由声明类型的包的其他编译单元中的代码引用。
该类型声明为public(因此可以从其他包中的代码访问)。
这个限制意味着每个编译单元最多只能有一个这样的类型。这种限制使Java编译器可以轻松地在包中找到命名类。在实践中,许多程序员选择将每个类或接口类型放在它自己的编译单元中,无论它是公共的还是由其他编译单元中的代码引用。
因此,虽然您可以在单个文件中声明多个顶级类,但最多只能暴露一个文件以外的文件。
但是,您可以根据需要公开任意数量的嵌套类。