102

我只是想了解为什么接口中定义的所有字段都是隐式staticfinal. 保留字段的想法static对我来说很有意义,因为您不能拥有接口的对象,但为什么它们是final(隐式)?

任何人都知道为什么 Java 设计人员会在界面中制作字段staticfinal

4

7 回答 7

131

接口旨在指定交互契约,而不是实现细节。开发人员应该能够通过查看接口来使用实现,而不必查看实现它的类内部。

接口不允许您创建它的实例,因为您不能指定构造函数。所以它不能有实例状态,尽管接口字段可以定义常量,这些常量是隐式静态和最终的。

您不能在接口中指定方法主体或初始化程序块,尽管从 Java 8 开始您可以使用主体指定默认方法。此功能旨在允许将新方法添加到现有接口,而无需更新所有实现。但是如果不首先创建一个实现接口的实例,您仍然无法执行这样的方法。

旁白:请注意,您可以使用匿名内部类实现接口:

interface Foo {
    String bar();
}

class FooBar {
    Foo anonymous = new Foo() {
         public String bar() {
             return "The Laundromat Café";
    };
}

您必须提供接口的完整实现才能编译匿名内部类。

new Foo()正在使用其默认构造函数初始化匿名内部类。

于 2009-10-03T14:32:23.327 回答
30

存在的理由final

如果未将字段定义为 final,则任何实现都可以更改字段的值。然后它们将成为实施的一部分。接口是没有任何实现的纯规范。

存在的理由static

如果它们是静态的,那么它们属于接口,而不是对象,也不属于对象的运行时类型。

于 2012-03-11T17:55:46.830 回答
18

这里有几个要点:

仅仅因为接口中的字段是隐式静态 final 并不意味着它们必须是编译时常量,甚至是不可变的。您可以定义例如

interface I {
  String TOKEN = SomeOtherClass.heavyComputation();
  JButton BAD_IDEA = new JButton("hello");
}

(请注意,在注释定义中执行此操作可能会使javac 混淆,这与上述实际编译为静态初始化程序的事实有关。)

而且,这个限制的原因更多的是风格而不是技术,很多人希望看到它放宽

于 2009-10-29T00:57:29.897 回答
9

字段必须是静态的,因为它们不能是抽象的(就像方法一样)。因为它们不能是抽象的,所以实现者将无法在逻辑上提供字段的不同实现。

我认为,这些字段必须是最终的,因为这些字段可能被许多不同的实现者访问,允许它们是可变的可能是有问题的(作为同步)。还要避免它被重新实现(隐藏)。

只是我的想法。

于 2009-10-03T11:36:11.603 回答
2

我认为要求字段为 final 的要求过于严格,并且是 Java 语言设计者的错误。有时,例如树处理,当您需要在实现中设置对接口类型的对象执行操作所需的常量时。在实现类上选择代码路径是一个难题。我使用的解决方法是定义一个接口函数并通过返回一个文字来实现它:

public interface iMine {
    String __ImplementationConstant();
    ...
}

public class AClass implements iMine {
    public String __ImplementationConstant(){
        return "AClass value for the Implementation Constant";
    }
    ...
}

public class BClass implements iMine {
    public String __ImplementationConstant(){
        return "BClass value for the Implementation Constant";
    }
    ...
}

但是,使用以下语法会更简单、更清晰且不易出现异常实现:

public interface iMine {
    String __ImplementationConstant;
    ...
}

public class AClass implements iMine {
    public static String __ImplementationConstant =
        "AClass value for the Implementation Constant";
    ...
}

public class BClass implements iMine {
    public static String __ImplementationConstant =
        "BClass value for the Implementation Constant";
    ...
}
于 2014-04-03T19:13:11.310 回答
0

规范、合同……字段访问的机器指令使用对象地址加上字段偏移量。由于类可以实现许多接口,因此无法使非最终接口字段在扩展此接口的所有类中具有相同的偏移量。因此必须实现不同的字段访问机制:两次内存访问(获取字段偏移量,获取字段值),而不是一次加维护一种虚拟字段表(虚拟方法表的模拟)。猜猜他们只是不想让 jvm 复杂化,因为这些功能可以通过现有的东西(方法)轻松模拟。

在 Scala 中,我们可以在接口中有字段,尽管在内部它们是按照我上面解释的(作为方法)实现的。

于 2016-10-04T07:37:45.593 回答
-1

static

staticJava 中的任何东西(变量或方法)都可以直接调用Classname.variablename或调用Classname.methodname。仅通过使用对象名称来调用它不是强制性的。

在接口中,不能声明对象,并且static可以只通过类名调用变量,而无需对象名。

final

它有助于保持变量的常量值,因为它不能在其子类中被覆盖。

于 2016-11-02T13:15:31.013 回答