为什么默认情况下接口变量是静态变量和最终变量?


274

为什么在Java中默认情况下接口变量是静态变量和最终变量?


41
您不应该在Interfaces中放置任何变量。
cherouvim 2010年

34
因为接口定义了可以以各种方式实现的合同。变量的值是实现。
cherouvim 2011年

10
当我们知道实现接口的所有类都具有一些常量变量(例如字段名称)时,我们当然可以。
Aniket Thakur 2013年

将一个类中的变量作为该类实现的接口的实例是一个好主意吗?我以前听过
Doug Hauf 2014年

java中的接口遵循ACID原则,最终是由于C中的规范化。@cherouvim变量的类型是实现,必须声明一个变量,带有或不带有值,变量的定义是值。如果更改了变量的值,则不会重新实现,请重新定义它。
Grim 2015年

Answers:


264

从Philip Shaw的Java接口设计常见问题解答中:

接口变量是静态的,因为不能单独实例化Java接口。必须在不存在任何实例的静态上下文中分配变量的值。final修饰符确保分配给接口变量的值是一个真正的常量,不能由程序代码重新分配。

资源


39
请注意,抽象类也不能“以其自身的权利”实例化,它们也可以具有实例变量。
macias

18
static修饰符的解释完全是虚假的。类的公共实例变量是其接口的一部分,没有理由不应该interface像实例方法那样在Java中抽象它们。interface不能直接实例化Java 没关系-您仍然可以拥有实现的类的实例,interface明智的是要求它们具有某个公共实例变量。关于的部分final完全没有提供解释-只是描述了什么final意思。
火爆的风格'16

3
上面的引用在上下文中更好。它给出的原因是“接口变量旨在成为Java常量”。引用只是在说明为什么这样的常数是静态的和最终的。是的,但是真正的问题是:为什么不允许变量作为实际接口的一部分(即,指定必须在实现类中出现的非私有成员的名称和类型)。如果他们想要特殊的“接口常量”,则可以使用新的语法,或者只是确定接口中实际定义的任何变量都是接口常量。
pyrocrasty

6
接口不能具有实例变量,以避免状态问题的多重继承。请参阅docs.oracle.com/javase/tutorial/java/IandI/…。由于相同的原因,一个类不能扩展一个以上的类。
denis

1
如何引入默认方法,它们有实例,但不支持实例变量...
M.kazem Akhgary

41

由于interface没有直接的对象,因此访问它们的唯一方法是使用类/接口,因此这就是为什么如果interface变量存在,则它应该是静态的,否则它将根本无法被外界访问。现在,由于它是静态的,因此它只能保存一个值,实现它的任何类都可以更改它,因此将一团糟。

因此,如果根本没有接口变量,它将是隐式静态的,最终的并且显然是公共的!


当然,如果Java中允许使用实例变量,则可以访问该实例变量interface。一个类将实现该接口,并声明实例变量(根据接口的要求)。它的构造函数(或其他方法)设置实例变量。当实例化该类的实例时,您将能够访问其实例变量。
pyrocrasty

Java允许带有主体的静态方法存在于接口中。那些可以访问静态变量。它们只是无法更改它们,这意味着静态函数无法存储任何数据
simpleuser

36

public:用于所有类的可访问性,就像接口中提供的方法一样

静态的:由于接口不能具有对象,所以可以使用interfaceName.variableName来引用它,也可以直接在实现它的类中使用variableName。

最终:使它们成为常数。如果2个类实现相同的接口,而您又赋予它们两个更改值的权限,则var的当前值将发生冲突,这就是为什么只允许一次初始化的原因。

同样,所有这些修饰符对于接口都是隐式的,您实际上不需要指定任何修饰符。


15

这不是哲学上的答案,而是更多实际的答案)。static修饰符的要求是显而易见的,已被其他人回答。基本上,由于无法实例化接口,因此访问其字段的唯一方法是使它们成为类字段- static

的背后的原因interface字段自动成为final(常数)是为了防止不同的实现意外更改接口变量的值可无意中影响其它实施方式的行为。想象一下下面的场景,其中一个interface属性没有final被Java 明确地变成:

public interface Actionable {
    public static boolean isActionable = false;

    public void performAction();
}

public NuclearAction implements Actionable {

    public void performAction() {
        // Code that depends on isActionable variable
        if (isActionable) {
            // Launch nuclear weapon!!!
        }
    }
}

现在,考虑一下如果另一个实现的类Actionable改变了接口变量的状态会发生什么:

public CleanAction implements Actionable  {

    public void performAction() {
        // Code that can alter isActionable state since it is not constant
        isActionable = true;
    }
}

如果这些类是由类加载器在单个JVM中加载的,则当NuclearAction另一个类在执行后(在同一线程中或其他线程中)被调用CleanAction时,其行为可能会受到另一个类的影响,这在情况下可能是灾难性的(显然是)。performAction()CleanAction

由于我们不知道an的每个实现interface将如何使用这些变量,因此它们必须隐式为final


9

因为其他任何东西都是实现的一部分,所以接口不能包含任何实现。


1
那最后的原因是什么。
Jothi

7
表示其常数。Java没有const关键字。static final是声明常量的方式。
阿米尔·阿富汗尼

5
从Java 8开始,它们可以包含一个实现,但是如果您不需要反向支持兼容性,则强烈建议不要使用它。:)
codepleb

6
public interface A{
    int x=65;
}
public interface B{
    int x=66;
}
public class D implements A,B {
    public static void main(String[] a){
        System.out.println(x); // which x?
    }
}

这是解决方案。

System.out.println(A.x); // done

我认为这是接口变量是静态的原因之一。

不要在Interface内部声明变量。


3
事实上,不规范“斧”,它甚至不会编译”,所以它实际上是安全的接口使用变量(隐含的公共静态最终)
马可

我不同意答案,因为@Marco表示甚至不会编译。到目前为止,我还没有发现任何其他缺点,也许只是您没有static final在实际为static和final的变量之前看到未编写的代码。
米瑟


3

因为:

Static :因为我们没有接口的对象,所以我们应该避免使用对象级别的成员变量,而应该使用类级别的变量,即静态的。

Final :,这样我们就不会为变量设置不明确的值(钻石问题-多重继承)。

而且根据文档界面,这是合同而非实施。

参考:Abhishek Jain 对quora 的回答


2

Java不允许在接口中使用抽象变量和/或构造函数定义。解决方案:只需在您的接口和您的实现之间挂一个抽象类,就可以像这样扩展抽象类:

 public interface IMyClass {

     void methodA();
     String methodB();
     Integer methodC();

 }

 public abstract class myAbstractClass implements IMyClass {
     protected String varA, varB;

     //Constructor
     myAbstractClass(String varA, String varB) {
         this.varA = varA;
         this.varB = VarB;
     }

     //Implement (some) interface methods here or leave them for the concrete class
     protected void methodA() {
         //Do something
     }

     //Add additional methods here which must be implemented in the concrete class
     protected abstract Long methodD();

     //Write some completely new methods which can be used by all subclasses
     protected Float methodE() {
         return 42.0;
     }

 }

 public class myConcreteClass extends myAbstractClass {

     //Constructor must now be implemented!
     myClass(String varA, String varB) {
         super(varA, varB);
     }

     //All non-private variables from the abstract class are available here
     //All methods not implemented in the abstract class must be implemented here

 }

如果您确定以后不希望将其与其他接口一起实现,则也可以使用不带任何接口的抽象类。请注意,您不能创建抽象类的实例,而必须首先对其进行扩展。

(“ protected”关键字意味着只有扩展类才能访问这些方法和变量。)

间谍



1

接口:系统需求服务。

在界面中,默认情况下,变量是由public,static,final访问修饰符分配的。因为:

public:有时接口可能会放在其他包中。因此,它需要从项目中的任何位置访问变量。

静态:这样的不完整类无法创建对象。因此,在项目中,我们需要访问没有对象的变量,以便我们可以在interface_filename.variable_name

final:假设一个接口由许多类实现,并且所有类都尝试访问和更新接口变量。因此,这导致数据更改不一致并影响其他所有类。因此,需要使用final声明访问修饰符。


0

在中Java,interface不允许您声明任何实例变量。将在接口中声明的变量用作实例变量将返回编译时错误。

您可以声明一个常量变量,static final该变量不同于实例变量。


这是完全错误的。除非您将其设为私有或受保护,否则编译器不会抱怨。正如其他人已经提到的,在幕后,它们已转换为公共静态最终版本。我想这很明显是为什么。因为接口是用来决定行为的,而不是陈述状态的。
Mikayil Abdullayev,

0

接口可以由任何类实现,如果该值被其中一个实现类更改,那将对其他实现类产生误导。接口基本上是将两个相互关联但互不相同的实体组合在一起的引用,因此,由于接口无法实例化,因此接口内部的声明变量将隐式为final且为静态。


0

想想一个Web应用程序,您在其中定义了接口,而其他类则实现了它。由于无法创建接口实例来访问变量,因此需要使用static关键字。由于它是静态的,因此该值的任何更改都将反映给其他已实现该值的实例。因此,为了防止这种情况,我们将它们定义为final。


0

刚刚在Eclipse中尝试过,interface中的变量默认为final,所以您不能更改它。与父类相比,变量肯定是可变的。为什么?在我看来,class中的变量是一个将由孩子继承的属性,孩子可以根据他们的实际需要对其进行更改。相反,接口仅定义行为,而不定义属性。在接口中放入变量的唯一原因是将它们用作与该接口相关的const。不过,根据以下摘录,这不是一个好习惯:

“在Java的早期,在接口中放置常量是一种流行的技术,但是现在很多人认为它是对接口的一种令人讨厌的用法,因为接口应该处理对象提供的服务,而不是对象的数据。此外,使用的常量通常,类的实现细节,但将它们放在接口中会将它们提升为该类的公共API。”

我也尝试过将静态放置或不放置完全没有区别。代码如下:

public interface Addable {
    static int count = 6;

    public int add(int i);

}

public class Impl implements Addable {

    @Override
    public int add(int i) {
        return i+count;
    }
}

public class Test {

    public static void main(String... args) {
        Impl impl = new Impl();

        System.out.println(impl.add(4));
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.