来自 Philip Shaw 的 Java 接口设计常见问题解答:
接口变量是静态的,因为 Java 接口不能单独实例化;变量的值必须在不存在实例的静态上下文中分配。 final修饰符确保分配给接口变量的值是一个真正的常量,程序代码不能重新分配。
public:用于所有类的可访问性,就像接口中存在的方法一样
static:由于接口不能有对象,可以使用 interfaceName.variableName 来引用它,也可以直接使用实现它的类中的 variableName。
final:使它们成为常量。如果 2 个类实现了相同的接口,并且你赋予它们两个改变值的权利,那么 var 的当前值就会发生冲突,这就是为什么只允许一次初始化的原因。
此外,所有这些修饰符对于接口都是隐式的,您实际上不需要指定其中任何一个。
由于接口没有直接对象,访问它们的唯一方法是使用类/接口,因此这就是为什么如果接口变量存在,它应该是静态的,否则外部世界根本无法访问它。现在由于它是静态的,它只能保存一个值,任何实现它的类都可以更改它,因此它会一团糟。
因此,如果有一个接口变量,它将是隐式静态的、最终的并且显然是公共的!!!
interface
中允许,实例变量将是可访问的。一个类将实现接口,声明实例变量(根据接口的要求)。它的构造函数(或其他方法)设置实例变量。当类的实例被实例化时,您将能够访问其实例变量。
(这不是一个哲学答案,而是一个实用的答案)。 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
。
因为其他任何东西都是实现的一部分,接口不能包含任何实现。
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
。
因为:
Static
:因为我们不能拥有接口对象,所以我们应该避免使用对象级别的成员变量,而应该使用类级别的变量,即静态的。
Final
:这样我们就不应该有变量的模棱两可的值(钻石问题 - 多重继承)。
并且根据文档接口是合同而不是实现。
参考:Abhishek Jain 在 quora 上的 answer
静态 - 因为接口不能有任何实例。最后——因为我们不需要改变它。
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 :有时接口可能会放在其他包中。所以它需要从项目中的任何地方访问变量。
静态: 这样不完整的类不能创建对象。所以在项目中我们需要访问没有对象的变量,以便我们可以在 interface_filename.variable_name
的帮助下访问
final :假设一个接口由多个类实现,并且所有类都尝试访问和更新接口变量。因此它会导致数据变化不一致并影响其他所有类。所以需要用final声明访问修饰符。
在 Java
中,接口不允许您声明任何实例变量。将接口中声明的变量用作实例变量将返回编译时错误。
您可以使用不同于实例变量的 static final
声明一个常量变量。
接口可以由任何类实现,如果该值被其中一个实现类更改,那么将会误导其他实现类。接口基本上是组合两个相关但不同的实体的引用。因此,接口内的声明变量将隐含地是最终的并且也是静态的,因为接口不能被实例化。
想象一个 Web 应用程序,其中您定义了接口并且其他类实现了它。由于您无法创建接口实例来访问您需要具有静态关键字的变量。由于它是静态的,因此值的任何更改都将反映到已实现它的其他实例。所以为了防止它,我们将它们定义为最终的。
刚刚在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 的类和一个名为 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
所以你去。最终公共静态变量
static
修饰符的解释是完全错误的。类的公共实例变量是其接口的一部分,没有理由不应该在 Javainterface
中抽象它们,就像实例方法一样。 Javainterface
不能直接实例化并不重要——您仍然可以拥有实现interface
的类的实例,并且要求它们具有某个公共实例变量是明智的。至于关于final
的部分,根本没有提供任何解释——它只是描述了final
的含义。