为什么Java中默认接口变量是静态的和最终的?
答案 0 :(得分:242)
来自Philip Shaw的Java界面设计常见问题解答:
接口变量是静态的,因为Java接口本身无法实例化;必须在没有实例的静态上下文中分配变量的值。最终修饰符确保分配给接口变量的值是一个真正的常量,不能由程序代码重新赋值。
答案 1 :(得分:35)
由于接口没有直接对象,访问它们的唯一方法是使用类/接口,因此如果接口变量存在,它应该是静态的,否则它根本不可访问外部世界。既然它是静态的,它只能保存一个值,任何实现它的类都可以改变它,因此它会变得一团糟。
因此,如果有一个接口变量,它将是隐式静态的,最终的,显然是公开的!!!
答案 2 :(得分:31)
public :对于所有类的可访问性,就像界面中的方法一样
静态:由于接口不能有对象,可以使用interfaceName.variableName来引用它,也可以直接引用实现它的类中的variableName。
最终:使它们成为常量。如果2个类实现相同的接口,并且你给它们两个都有权更改值,那么var的当前值就会发生冲突,这就是为什么只允许一次初始化。
所有这些修饰符都是隐含的接口,你真的不需要指定它们中的任何一个。
答案 3 :(得分:11)
(这不是一个哲学答案,而是一个实际的答案)。 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
之后调用时1}}被执行(在相同的线程中或其他方式),在这种情况下可能是灾难性的(在语义上)。
由于我们不知道interface
的每个实现将如何使用这些变量,因此它们必须隐式为final
。
答案 4 :(得分:9)
因为其他任何东西都是实现的一部分,并且接口不能包含任何实现。
答案 5 :(得分:5)
static - 因为Interface不能有任何实例。最后 - 因为我们不需要改变它。
答案 6 :(得分:5)
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
我认为这是界面变量为静态的一个原因。
不要在接口内声明变量。
答案 7 :(得分: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”关键字表示只有扩展类才能访问这些方法和变量。)
SPYRO
答案 8 :(得分:2)
,因为:
Static
:因为我们不能拥有接口对象所以我们应该避免使用对象级别的成员变量,并且应该使用类级变量,即静态。
Final
:这样我们就不应该有变量的模糊值(钻石问题 - 多重继承)。
并且根据文档界面是合同而不是实现。
参考:Abhishek Jain对quora http://qr.ae/TU1dTm
的回答答案 9 :(得分:1)
界面是两方之间的契约,是不变的,刻在石头上,因此是最终的。请参阅Design by Contract。
答案 10 :(得分:1)
接口:系统需求服务。
在界面中,默认情况下,变量是由 public,static,final 访问修饰符分配的。 因为:
public:有时接口可能会放在其他软件包中。因此,它需要从项目中的任何位置访问变量。
静态:这样的不完整类无法创建对象。因此,在项目中,我们需要访问没有对象的变量,以便我们可以借助interface_filename.variable_name
最终:假设一个接口由许多类实现,并且所有类都尝试访问和更新接口变量。因此,这会导致数据更改不一致并影响其他所有类。因此,需要使用final声明访问修饰符。
答案 11 :(得分:0)
在Java
中,接口不允许您声明任何实例变量。使用在接口中声明的变量作为实例变量将返回编译时错误。
您可以使用与实例变量不同的static final
来声明常量变量。
答案 12 :(得分:0)
接口可以由任何类实现,如果该值被实现类之一更改,那么其他实现类会有误导。接口基本上是组合两个核心但不同的实体的引用。因此,接口内的声明变量将隐式地是最终的并且也是静态的,因为接口不能实例化。
答案 13 :(得分:0)
考虑一个Web应用程序,您可以在其中定义接口,其他类可以实现它。由于无法创建接口实例来访问变量,因此需要使用静态关键字。由于它的静态值,任何值的变化都会反映到实现它的其他实例。因此,为了防止它,我们将它们定义为最终。
答案 14 :(得分:0)
刚刚在Eclipse中尝试过,接口中的变量默认为final,因此您无法更改它。与父类相比,变量肯定是可变的。为什么?从我的观点来看,类中的变量是一个将由子项继承的属性,子项可以根据实际需要进行更改。相反,接口只定义行为,而不是属性。在接口中放入变量的唯一原因是将它们用作与该接口相关的consts。但是,根据以下摘录,这不是一个好习惯:
“在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));
}
}