繁体   English   中英

为什么接口变量默认是static和final?

[英]Why are interface variables static and final by default?

为什么Java中接口变量默认是static和final?

来自 Philip Shaw 的 Java 界面设计常见问题解答:

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

来源

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

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

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

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

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

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

这不是一个哲学的答案,而是一个更实际的答案)。 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中加载,那么行为NuclearAction可以通过另一个类,受到影响CleanAction ,当其performAction()是后调用CleanAction执行的(在同一个线程或其他方式),其在这种情况下可能是灾难性的(语义上是这样)。

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

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

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

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

不要在接口内声明变量。

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

因为:

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

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

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

参考:Abhishek Jain 在 quora 上的回答

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

斯派罗

接口:系统需求服务。

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

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

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

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

接口是两方之间的契约,它是不变的,刻在石头上,因此是最终的。 请参阅合同设计

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

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

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

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

刚刚在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));
    }
}

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

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

当你创建一个 class A 时,它继承了 Object class 的所有属性。当你实例化 A 时你不知道,你也在实例化一个 Object object,并且 A 指向它作为它的父级。

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

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

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

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

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

至于为什么要公开。。。私有就没用了。 这些函数是抽象的,内部不能有任何代码来使用私有变量。 它永远不会被使用。 如果变量被标记为受保护,则只有 class 的继承人才能使用这些变量。 我不认为你可以从接口继承。 公共是唯一可行的选择。

剩下的唯一设计决定是“最终”。 您可能打算更改 class 的多个实例之间的共享变量。(例如,也许您有 5 个玩家在玩大富翁,并且您希望存在一个棋盘,以便所有玩家都满足该界面和一个共享棋盘 - 它可能是你想根据播放器功能实际改变面板......)[我反对这种设计]

但是对于多线程应用程序,如果你不创建变量 static 以后你会遇到困难,但我不会阻止你。 去做并了解为什么会受伤 <3

所以你有 go.final public static 变量

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM