为什么Java不允许接口中的私有成员?有什么特别的原因吗?
13 回答
从 Java 8 开始,接口可以有默认方法,从 Java 9 开始,一个接口允许有一个私有方法,这些私有方法只能通过同一接口中的默认方法访问。
接口用于描述由任何实现该接口的类提供的 API。由于定义中的接口没有状态,因此无需在其中声明字段成员。
没有办法实现这样的接口。 对我提出的一个问题的回答强烈表明,用私有方法实现接口是不可能的(如果不彻底改变规则)——这就留下了为什么不允许受保护和封装私有方法的问题。
class OuterClass
{
void run ( MyInterface x )
{
x . publicMethod ( ) ; // why not?
x . protectedMethod ( ) ; // why not?
x . packagePrivateMethod ( ) ; // why not?
x . privateMethod ( ) ; // why not?
}
interface MyInterface
{
public abstract void publicMethod ( ) ; // OK
protected abstract void protectedMethod ( ) ; // why not?
abstract void packagePrivateMethod ( ) ; // in interface default is public, but why not package private
private void privateMethod ( ) ; // impossible to implement
}
class MyImpl implements MyInterface
{
public void publicMethod ( ) { } // ok
protected void protectedMethod ( ) { } // no sweat
void packagePrivateMethod ( ) { } // no sweat
private void privateMethod ( ) { } // not happening
}
}
下面的代码应该达到预期的结果。尽管所有方法都是公共的,但只有公共方法才是有效的公共方法。protected 方法得到有效保护。packagePrivateMethod 实际上是 packagePrivate。privateMethod 实际上是私有的。
class WorkAround
{
void run ( MyPrivateInterface x )
{
x . publicMethod ( ) ;
x . protectedMethod ( ) ;
x . packagePrivateMethod ( ) ;
x . privateMethod ( ) ;
}
public interface MyPublicInterface { void publicMethod ( ) ; }
protected interface MyProtectedInterface extends MyPublicInterface { void protectedMethod ( ) ; }
interface MyPackagePrivateInterface extends MyProtectedInterface { void packagePrivateMethod ( ) ; }
private interface MyPrivateInterface extends MyPackagePrivateInterface { void privateMethod ( ) ; }
}
根据Java
编程语言的范围private members
仅限于class
声明它的地方,并且只能通过 that 的方法访问class
。但是inteface
没有方法体,因此没有使用在interface
.
Java 允许在 Java 9 的接口中使用私有方法。默认方法是在 Java 8 中引入的。可能多个默认方法想要共享一些代码,然后可以将此代码移动到私有方法而不将其暴露给外部世界。此错误已得到修复,并从JDK 9 build 54 开始,对私有接口方法的编译器支持已恢复。
public interface IData{
default void processData(int data) {
validate(data);
// do some work with it
}
default void consumeData(int data) {
validate(data);
// do some work with it
}
private void validate(int data) {
// validate data
}
}
这是因为它们将毫无用处。
没有办法调用私有方法。
私有成员是一个实现细节。接口是关于一个类可以承担的公共角色。
私有字段不会完全没用,因为其他字段和内部类可以访问它们。
然而,即使在嵌套类中,私有方法也无法实现,这使得它们几乎毫无用处。您可以使用反射来阅读它们,但这是一个极端情况。
私有成员在界面中没有意义。接口是一种使用已定义方法访问类的方法,您不需要查看该类的内部。
私人成员不同意这一点。
声明为私有的类的成员不会被该类的子类继承。只有声明为protected 或public 的类的成员才能被声明在一个包中的子类继承,而不是声明该类的那个。
源
所以你在一个接口中没有任何工作方法可以与那个私有的不可继承字段一起工作,那它为什么要存在呢?
是的,不能那样做。对于所有评论为什么不应该这样做的人:
想象一下,我有 A 类,它使用接口 I。B 类扩展了 A 类,因此也继承了 A 中的所有接口方法。
现在,假设我想要 A 类中的私有方法,但也希望它以合同方式为其他类定义(可能是 C 类,它不一定扩展 B 类或 A 类)。
也许对于“初始化”方法,我想要所有使用 I 接口的类。但显然我不希望一个初始化方法是公开的......因为它应该只使用一次,或者类认为有必要,而不仅仅是因为你想随意使用它。
唯一的解决方案是一种解决方法,或者通过简单地将 init 方法强制到类本身而没有接口。
我当然不太了解原因,但有时它仍然可以派上用场。显然,Oracle 同意他们在 JDK 9 中允许私有接口方法。
无论如何,我所做的是放置一个简单的布尔变量,这样接口方法(应该是私有的)可以在设置一次后标记为真(初始化=真)。然后当再次调用该方法时,它什么也不做。这样接口方法可以实现为public,但是由于(我的类的)构造函数首先调用该方法,这将变量设置为true,因此不能再次调用它。
否则,如果您只希望类的内部工作来使用它,您将不得不尝试不同的解决方法......也许方法本身在使用它时会设置一个标志打开和关闭。当标志为假时,该方法什么也不做(这将是当有人从类外部调用它时)。但是,当类自己的方法调用它时,他们很快将标志设置为true,然后调用方法,然后将标志设置为false??
到底是种哑巴。现在可能只是将私有类简单地放入类本身并完全删除接口更好。