ChatGPT解决这个技术问题 Extra ChatGPT

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

为什么Java中的接口变量默认是静态的和最终的?

您不应该在接口中放置任何变量。
因为接口定义了可以以各种方式实现的合约。变量的值是实现。
当我们知道所有实现接口的类都有一些常量变量(例如字段名称)时,我们当然可以。
将类中的变量作为该类实现的接口的实例是个好主意吗?我以前听说过这个。
Arun Raaj 的回答(2018 年 4 月 24 日 12:30 回答)和 denis 的评论(17 年 8 月 17 日 21:02)正确地将多重继承确定为主要问题......

D
Dave Jarvis

来自 Philip Shaw 的 Java 接口设计常见问题解答:

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

source


请注意,抽象类也不能“以它们自己的权利”实例化,并且它们可以具有实例变量。
这种对 static 修饰符的解释是完全错误的。类的公共实例变量是其接口的一部分,没有理由不应该在 Java interface 中抽象它们,就像实例方法一样。 Java interface 不能直接实例化并不重要——您仍然可以拥有实现 interface 的类的实例,并且要求它们具有某个公共实例变量是明智的。至于关于 final 的部分,根本没有提供任何解释——它只是描述了 final 的含义。
上面的引用在上下文中更好。它给出的原因是“接口变量旨在成为 Java 常量”。引用只是详细说明了为什么这样的常量是静态的和最终的。这是真的,但真正的问题是:为什么不允许变量作为实际接口的一部分(即指定必须在实现类中出现的非私有成员的名称和类型)。如果他们想要特殊的“接口常量”,他们可以使用新语法,或者只是决定在接口中实际定义的任何变量都是接口常量。
接口不能有实例变量以避免状态问题的多重继承。请参阅docs.oracle.com/javase/tutorial/java/IandI/…。由于同样的原因,一个类不能扩展多个类。
默认方法是如何引入的,它们确实有实例,但不支持实例变量......
N
Nutan

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

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

final:使它们成为常量。如果 2 个类实现了相同的接口,并且你赋予它们两个改变值的权利,那么 var 的当前值就会发生冲突,这就是为什么只允许一次初始化的原因。

此外,所有这些修饰符对于接口都是隐式的,您实际上不需要指定其中任何一个。


K
Kasun Siyambalapitiya

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

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


当然,如果在 Java interface 中允许,实例变量将是可访问的。一个类将实现接口,声明实例变量(根据接口的要求)。它的构造函数(或其他方法)设置实例变量。当类的实例被实例化时,您将能够访问其实例变量。
Java 允许带有主体的静态方法存在于接口中。那些可以访问静态变量。他们只是不能改变它们,这意味着静态函数不能存储任何数据
M
Malvon

这不是一个哲学答案,而是一个实用的答案)。 static 修饰符的要求很明显,其他人已经回答了。基本上,由于接口不能被实例化,访问其字段的唯一方法是使它们成为类字段——static

interface 字段自动变为 final(常量)背后的原因是为了防止不同的实现意外更改接口变量的值,这可能会无意中影响其他实现的行为。想象一下下面的场景,其中 interface 属性没有被 Java 显式变为 final

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 中加载的,那么在执行 CleanAction 之后调用其 performAction() 时,NuclearAction 的行为可能会受到另一个类 CleanAction 的影响(在同一线程或其他),在这种情况下可能是灾难性的(语义上就是这样)。

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


A
Amir Afghani

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


那么最终的原因是什么。
表示它是一个常数。 Java 没有 const 关键字。 static final 是您声明常量的方式。
从 Java 8 开始,它们可以包含一个实现,但如果您不需要向后兼容性,强烈建议不要使用它。 :)
A
Asif Mushtaq
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

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

不要在接口内声明变量。


事实上,如果没有规范“Ax”,它甚至不会编译”,因此在接口中使用变量(隐含地是 public static final)实际上是安全的。
我不同意这个答案,因为@Marco 说它甚至不会编译。到目前为止,我没有发现任何其他缺点,也许只是您没有看到在实际上是静态和最终的变量之前写有 static final
A
Arun Raaj

因为:

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

Final:这样我们就不应该有变量的模棱两可的值(钻石问题 - 多重继承)。

并且根据文档接口是合同而不是实现。

参考:Abhishek Jain 在 quora 上的 answer


R
RubyDubee

静态 - 因为接口不能有任何实例。最后——因为我们不需要改变它。


“我们不需要” == “我们不允许”,不要混淆含义。
s
spyro

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”关键字意味着只有扩展类可以访问这些方法和变量。)

斯派罗


V
Vishal Sheth

接口:系统需求服务。

在接口中,变量默认由 public、static、final 访问修饰符分配。因为 :

public :有时接口可能会放在其他包中。所以它需要从项目中的任何地方访问变量。

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

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


A
Anssi

接口是两方之间的合约,它是不变的,刻在石头上,因此是最终的。请参阅Design by Contract


G
Giri

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

您可以使用不同于实例变量的 static final 声明一个常量变量。


这是完全错误的。除非您将其设为私有或受保护,否则编译器不会抱怨。正如其他人已经提到的那样,在幕后,它们被转换为公共静态决赛。我想这是很明显的原因。因为接口旨在指示行为,而不是状态。
u
user3889476

接口可以由任何类实现,如果该值被其中一个实现类更改,那么将会误导其他实现类。接口基本上是组合两个相关但不同的实体的引用。因此,接口内的声明变量将隐含地是最终的并且也是静态的,因为接口不能被实例化。


s
srikant

想象一个 Web 应用程序,其中您定义了接口并且其他类实现了它。由于您无法创建接口实例来访问您需要具有静态关键字的变量。由于它是静态的,因此值的任何更改都将反映到已实现它的其他实例。所以为了防止它,我们将它们定义为最终的。


S
Saidolim

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

“在接口中放置常量在 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));
    }
}

W
Watachiaieto

我觉得所有这些答案都错过了 OP 问题的重点。 OP 没有要求确认他们的陈述,他们想知道为什么他们的陈述是标准。

回答这个问题需要一点信息。首先,让我们谈谈继承。让我们假设有一个名为 A 的类和一个名为 x 的实例变量。

当你创建一个类 A 时,它继承了 Object 类的所有属性。当您实例化 A 时,如果您不知道,您也在实例化一个 Object 对象,并且 A 指向它作为它的父对象。

现在假设您创建了一个继承自 A 的类 B。

当你创建一个类 B 时,你也在创建一个类 A 和一个对象。 B 可以访问变量 x。这意味着 Bx 实际上与 BAx 完全相同,而 Java 只是为您隐藏了抓取 A 的魔力。

不要让我们谈论接口......接口不是inheretence。如果 B 要实现接口 Comparable,则 B 不会创建 Comparable 实例并将其称为父级。相反,B 承诺拥有 Comparable 拥有的东西。

不让我们在这里谈一点理论......接口是一组可以用来与某物交互的函数。它不是事物本身。例如,您通过与朋友交谈、与他们分享食物、与他们跳舞、靠近他们来与他们互动。但是,您不会从它们那里继承-您没有它们的副本。

接口类似。只有一个接口,所有对象都与它相关联。由于接口仅作为类存在一次(与其自身的实例相反),因此实现该接口的每个对象都不可能拥有自己的接口副本。这意味着每个变量只有一个实例。这意味着变量由使用接口的所有类(又名静态)共享。

至于为什么我们将它们公开...私有将毫无用处。这些函数是抽象的,其中不能有任何代码来使用私有变量。它永远不会被使用。如果变量被标记为受保护,那么只有类的继承者才能使用这些变量。我不认为你可以从接口继承。公开是唯一可行的选择。

剩下的唯一设计决定是“最终”。您可能打算更改类的多个实例之间的共享变量。 (例如,也许您有 5 名玩家在玩 Monopoly,并且您希望存在一个棋盘,这样您就可以让所有玩家满足界面和一个共享棋盘 - 您可能希望根据玩家功能实际更改棋盘。. .) [我不推荐这种设计]

但是,对于多线程应用程序,如果您不将变量设为静态,您以后会遇到困难,但我不会阻止您。这样做并了解为什么会疼<3

所以你去。最终公共静态变量