为啥接口变量默认是静态的和最终的?
Posted
技术标签:
【中文标题】为啥接口变量默认是静态的和最终的?【英文标题】:Why are interface variables static and final by default?为什么接口变量默认是静态的和最终的? 【发布时间】:2011-01-26 17:01:03 【问题描述】:为什么Java中的接口变量默认是static和final的?
【问题讨论】:
你不应该在接口里面放任何变量。 因为接口定义了可以以各种方式实现的合约。变量的值是实现。 当我们知道所有实现接口的类都有一些常量变量(例如字段名称)时,我们当然可以。 将类中的变量作为该类实现的接口的实例是个好主意吗?我以前听说过。 Arun Raaj 的回答(2018 年 4 月 24 日 12:30 回答)和 denis 的评论(2017 年 8 月 17 日 21:02)正确地将多重继承确定为主要问题...跨度> 【参考方案1】:来自 Philip Shaw 的 Java 界面设计常见问题解答:
接口变量是静态的,因为 Java 接口不能单独实例化;变量的值必须在不存在实例的静态上下文中分配。 final 修饰符确保分配给接口变量的值是一个真正的常量,程序代码不能重新分配。
source
【讨论】:
请注意,抽象类也不能“以它们自己的权利”实例化,它们可以有实例变量。 这种对static
修饰符的解释完全是虚假的。一个类的公共实例变量是它的接口的一部分,没有理由不应该在 Java interface
中抽象它们,就像实例方法一样。不能直接实例化 Java interface
并不重要 - 您仍然可以拥有实现 interface
的类的实例,并且要求它们具有某个公共实例变量是明智的。至于final
的部分,根本没有提供任何解释——它只是描述了final
的含义。
上面的引用在上下文中更好。它给出的原因是“接口变量旨在成为 Java 常量”。引用只是详细说明了为什么这样的常量是静态的和最终的。确实如此,但真正的问题是:为什么不允许将变量作为实际接口 的一部分(即指定必须在实现类中出现的非私有成员的名称和类型)。如果他们想要特殊的“接口常量”,他们可以使用新语法,或者只是决定在接口中实际定义的任何变量都是接口常量。
接口不能有实例变量以避免多重继承的状态问题。见docs.oracle.com/javase/tutorial/java/IandI/…。由于同样的原因,一个类不能扩展多个类。
默认方法是如何引入的,它们确实有实例,但不支持实例变量...【参考方案2】:
public:用于所有类的可访问性,就像接口中的方法一样
静态:由于接口不能有对象,可以使用 interfaceName.variableName 来引用它,也可以直接在实现它的类中使用 variableName。
final:使它们成为常量。如果 2 个类实现了相同的接口,并且你赋予它们两个改变值的权利,那么 var 的当前值就会发生冲突,这就是为什么只允许一次初始化的原因。
此外,所有这些修饰符对于接口都是隐含的,您实际上不需要指定其中任何一个。
【讨论】:
【参考方案3】:由于接口没有直接对象,访问它们的唯一方法是使用类/接口,因此如果接口变量存在,它应该是静态的,否则外界根本无法访问它.现在因为它是静态的,它只能保存一个值,任何实现它的类都可以改变它,因此它会一团糟。
因此,如果有一个接口变量,它将是隐式静态的、最终的并且显然是公共的!!!
【讨论】:
当然,如果在 Javainterface
中允许,实例变量将是可访问的。一个类将实现接口,声明实例变量(根据接口的要求)。它的构造函数(或其他方法)设置实例变量。当类的实例被实例化时,您将能够访问其实例变量。
Java 允许带有主体的静态方法存在于接口中。那些可以访问静态变量。他们只是不能改变它们,这意味着静态函数不能存储任何数据【参考方案4】:
(这不是一个哲学答案,而是一个实际的答案)。 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
。
【讨论】:
【参考方案5】:因为其他任何东西都是实现的一部分,接口不能包含任何实现。
【讨论】:
那么final的原因是什么。 表示它是一个常数。 Java 没有 const 关键字。 static final 是您声明常量的方式。 从 Java 8 开始,它们可以包含一个实现,但如果您不需要向后兼容性,强烈建议不要使用它。 :)【参考方案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
我认为这是接口变量是静态的原因之一。
不要在接口内声明变量。
【讨论】:
事实上,如果没有规范“A.x”,它甚至不会编译”,因此在接口中使用变量(隐含地是公共静态最终变量)实际上是安全的。 我不同意这个答案,因为@Marco 说它甚至不会编译。到目前为止我没有发现任何其他缺点,也许只是你没有看到在实际上是静态和最终的变量之前写了static final
。【参考方案7】:
静态 - 因为接口不能有任何实例。和 final - 因为我们不需要更改它。
【讨论】:
"我们不需要" == "我们不允许",不要混淆意思。【参考方案8】:因为:
Static
: 因为我们不能拥有接口对象,所以我们应该避免使用对象级别的成员变量,而应该使用类级别的变量,即静态的。
Final
:这样我们就不应该有变量的模棱两可的值(钻石问题 - 多重继承)。
并且根据文档接口是合同而不是实现。
参考:Abhishek Jain 在 quora 上的 answer
【讨论】:
【参考方案9】: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”关键字意味着只有扩展类可以访问这些方法和变量。)
斯派罗
【讨论】:
【参考方案10】:接口:系统需求服务。
在接口中,变量默认由public,static,final访问修饰符赋值。 因为:
public : 有时接口可能会放在其他包中。所以它需要从项目中的任何地方访问变量。
静态:这样不完整的类不能创建对象。所以在项目中我们需要访问没有对象的变量,这样我们就可以在interface_filename.variable_name
的帮助下访问
final : 假设一个接口由多个类实现,所有类都尝试访问和更新接口变量。因此它会导致数据变化不一致并影响其他所有类。所以需要用final声明访问修饰符。
【讨论】:
【参考方案11】:接口是两方之间不变的契约,刻在石头上,因此是最终的。见Design by Contract。
【讨论】:
【参考方案12】:在Java
中,接口不允许您声明任何实例变量。将接口中声明的变量用作实例变量将返回编译时错误。
您可以使用不同于实例变量的static final
声明一个常量变量。
【讨论】:
这是完全错误的。除非您将其设为私有或受保护,否则编译器不会抱怨。正如其他人已经提到的那样,在幕后,它们被转换为公共静态决赛。我想这很明显为什么。因为接口是为了指示行为,而不是状态。【参考方案13】:接口可以由任何类实现,如果该值被其中一个实现类更改,那么将会误导其他实现类。接口基本上是组合两个相关但不同的实体的引用。因此,接口内的声明变量将隐含地是最终的并且也是静态的,因为接口不能被实例化。
【讨论】:
【参考方案14】:想象一个 Web 应用程序,其中您定义了接口并由其他类实现它。由于您无法创建接口实例来访问您需要具有静态关键字的变量。由于它是静态的,因此值的任何更改都将反映到已实现它的其他实例。因此,为了防止它发生,我们将它们定义为 final。
【讨论】:
【参考方案15】:刚刚在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));
【讨论】:
以上是关于为啥接口变量默认是静态的和最终的?的主要内容,如果未能解决你的问题,请参考以下文章