Java 接口中静态方法和默认方法的区别是什么?

当我通过接口学习时,我注意到现在可以在接口中定义静态方法和默认方法。

public interface interfacesample2 {
public static void method() {
System.out.println("hello world");
}


public default void menthod3() {
System.out.println("default print");
}
}

请解释一下这两者的区别,如果有一个例子说明我们什么时候会使用它,那就太好了。接口有点混乱。

77415 次浏览

可以说,静态方法是应用于类“名称空间”的方法。因此,Interface.foo()访问接口 Interfacestatic方法 foo。注意,函数调用不适用于接口的任何特定 例子

另一方面,默认实现 bar

Interface x = new ConcreteClass();
x.bar();

static接口方法不能知道 this变量,但默认实现可以。

1. 解释两者的区别

静态接口方法类似于静态类方法(这里它们只属于 Interface)。作为默认接口方法提供接口方法的 default implementation(哪些实现类可能是 override)
但是请记住,如果一个类是 implementing more than one interface with same default方法签名,那么实现类 needs to override the default method

你可以在下面找到一个简单的例子(可以 DIY 为不同的情况)

public class Test {
public static void main(String[] args) {
// Accessing the static member
I1.hello();


// Anonymous class Not overriding the default method
I1 t = new I1() {
@Override
public void test() {
System.out.println("Anonymous test");
}
};
t.test();
t.hello("uvw");


// Referring to class instance with overridden default method
I1 t1 = new Test2();
t1.test();
t1.hello("xyz");


}
}


interface I1 {


void test();
//static method
static void hello() {
System.out.println("hello from Interface I1");
}


// default need not to be implemented by implementing class
default void hello(String name) {
System.out.println("Hello " + name);
}
}


class Test2 implements I1 {
@Override
public void test() {
System.out.println("testing 1234...");
}


@Override
public void hello(String name) {
System.out.println("bonjour" + name);
}
}

我们什么时候用这个会比较好。

这取决于你的问题陈述。如果您的规范中的某个方法需要在该契约中的所有类中使用相同的实现,那么我会说 Default 方法是有用的,或者它可以像 Adapter类一样使用。

这里有一个很好的阅读: https://softwareengineering.stackexchange.com/questions/233053/why-were-default-and-static-methods-added-to-interfaces-in-java-8-when-we-alread

下面 Oracle doc 解释了演化现有接口的默认和静态方法:

具有实现用新的 默认或静态方法不必将它们修改或重新编译为 适应额外的方法。

Http://docs.oracle.com/javase/tutorial/java/iandi/nogrow.html

根据 Oracle 的 Javadocs: http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html

默认方法使您能够向库的接口添加新功能,并确保与为这些接口的旧版本编写的代码的二进制兼容性。

静态方法是与定义它的类关联的方法,而不是与任何对象关联的方法。该类的每个实例都共享其静态方法。

通常,接口中的静态方法用作 Helper 方法,而默认方法用作实现该接口的类的默认实现。

例如:

interface IDemo {


//this method can be called directly from anywhere this interface is visible
static int convertStrToInt(String numStr) {
return Integer.parseInt(numStr);
}




//getNum will be implemented in a class
int getNum();


default String numAsStr() {
//this.getNum will call the class's implementation
return Integer.toString(this.getNum());
}


}

这个链接 有一些有用的见解,这里列出了其中的一些。

Default & 静电干扰方法缩小了 接口摘要类之间的差异。

接口 违约方法:

  • 它有助于避免使用实用程序类,例如所有 Collectionsclass 方法都可以在接口本身中提供。
  • 它有助于扩展接口,而不必担心破坏实现类。

接口 静电干扰方法:

  • 它们是接口的一部分,我们不能将其用于实现类对象。
  • 它不允许实现类重写它们,从而有助于提供安全性。

喜欢引用另一个有用的 参考文献

我们不能执行 Interfacesample2.menthod3();,因为它不是静态方法。为了执行 method3(),我们需要一个 Interfacesample2接口的实例。

请参考以下实例:

public class Java8Tester {
public static void main(String args[]){
// Interfacesample2.menthod3(); Cannot make a static reference to the non-static method menthod3 from the type Interfacesample2


new Interfacesample2(){ }.menthod3();// so in order to call default method we need an instance of interface


Interfacesample2.method(); // it
}
}


interface Interfacesample2 {
public static void method() {
System.out.println("hello world");
}


public default void menthod3() {
System.out.println("default print");
}
}

Java8中静态方法和默认方法的区别:

1)在实现类中重写默认方法 可以是,而静态 不能

2)静态方法属于接口类 只有,所以你只能调用接口类的静态方法,而不能调用实现这个接口的类,参见:

public interface MyInterface {
default void defaultMethod(){
System.out.println("Default");
}


static void staticMethod(){
System.out.println("Static");
}
}


public class MyClass implements MyInterface {


public static void main(String[] args) {


MyClass.staticMethod(); //not valid - static method may be invoked on containing interface class only
MyInterface.staticMethod(); //valid
}
}

3)类和接口 可以静态方法名称相同,并且都不覆盖其他方法!

public class MyClass implements MyInterface {


public static void main(String[] args) {


//both are valid and have different behaviour
MyClass.staticMethod();
MyInterface.staticMethod();
}


static void staticMethod(){
System.out.println("another static..");
}
}

以下是我的观点:

接口中的静态方法 :

  • 您可以直接调用它(InterfacetA.staticMethod ())

  • 子类将无法重写。

  • 子类可以具有与 staticMethod 同名的方法

接口中的默认方法 :

  • 你不能直接调用它。

  • 子类将能够重写它

优点:

  • Static Method: 您不需要为实用程序方法创建单独的类。

  • Default Method: 提供默认方法中的通用功能。

接口默认方法:

它有助于避免使用实用程序类,例如所有 Collectionsclass 方法都可以在接口本身中提供。

它有助于扩展接口,而不必担心破坏实现类。

接口静态方法:

它们是接口的一部分,我们不能将其用于实现类对象。

它不允许实现类重写它们,从而有助于提供安全性。

现在来看静态方法如何提供安全性。

interface MyInterface {
/*
* This is a default method so we need not to implement this method in the implementation classes
*/
default void newMethod() {
System.out.println("Newly added default method in Interface");
}


/*
* This is a static method. Static method in interface is similar to default method except that we cannot override them in the implementation classes. Similar to default methods, we need to implement these methods in implementation classes so we can safely add them to the existing interfaces.
*/
static void anotherNewMethod() {
System.out.println("Newly added static method in Interface");
}


/*
* Already existing public and abstract method We must need to implement this method in implementation classes.
*/
void existingMethod(String str);
}


public class Example implements MyInterface {
// implementing abstract method
public void existingMethod(String str) {
System.out.println("String is: " + str);
}


public void newMethod() {
System.out.println("Newly added default method in Class");
}


static void anotherNewMethod() {
System.out.println("Newly added static method in Class");
}


public static void main(String[] args) {
Example obj = new Example();


// calling the default method of class
obj.newMethod();
// calling the static method of class


obj.anotherNewMethod();


// calling the static method of interface
MyInterface.anotherNewMethod();


// calling the abstract method of interface
obj.existingMethod("Java 8 is easy to learn");


}
}

这里 obj.newMethod();打印类的实现逻辑,意味着我们可以在实现类中更改该方法的逻辑。

但是 obj.anotherNewMethod();打印类的实现逻辑,却没有改变接口的实现。因此,如果任何加密-解密逻辑写在该方法中,你不能改变。

启动 Java8接口也可以使用静态方法。与类的静态方法一样,接口的静态方法也可以使用接口名称调用。

例子

public interface Calculator {
int add(int a, int b);
int subtract(int a, int b);


default int multiply(int a, int b) {
throw new RuntimeException("Operation not supported. Upgrade to UltimateCalculator");
}


static void display(String value) {
System.out.println(value);
}
}

接口的静态方法和默认方法的区别在于默认方法支持继承,而静态方法不支持继承。可以在继承接口中重写默认方法。

这里可以很好地了解接口默认方法和静态方法

都是好答案。我想在接口中添加静态函数的另一种实际用法。技巧来自 Joshua Bloch 在《第2章: 创建和摧毁对象》一书中的第3版《有效的 Java 》。

Static functions can be used for static factory methods.

静态工厂方法是返回对象的方法。它们像构造函数一样工作。在特定情况下,静态工厂方法比使用构造函数提供更多可读代码。

引自约书亚 · 布洛赫的著作《有效的 Java 》第三版

在 Java8之前,接口不能有静态方法 约定,名为 Type 的接口的静态工厂方法是 放入一个名为 Type 的非实例化伙伴类(第4项)。

作者给出了一个集合的例子,其中实现了这种静态工厂方法。检查代码,Josh Bloch 可以被看作是 Collectionsclass 的第一作者。虽然集合是一个类而不是接口。但这个概念仍然适用。

例如,Java集合框架有四十五个功能 实现它的接口,提供不可修改的集合, 同步收集等等,几乎所有这些 实现是通过一个静态工厂方法导出的 非实例化类(java.util.Collections) 返回的对象都是非公共的。

他进一步解释说,API 不仅更小,而且有助于提高代码的可读性和 API 的易用性。

减少的不仅仅是 API 的大部分,还有概念上的 权重: 数量和难度的概念,程序员 为了使用 API,必须掌握。程序员知道 返回的对象具有由其接口指定的 API,因此 类的其他类文档 实现类。

下面是 java.util. Collectionsclass 中的一个静态方法:

public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c) {
return new UnmodifiableCollection<>(c);
}

根据 Java14 JLS 文档:

默认方法:

  • 它是在缺省接口中声明的实例方法 修饰语

  • 它只能由实现类的实例访问 只有

  • 它的主体始终由一个块表示,该块提供了一个默认值 任何实现类的实现或行为 重写方法

  • 它永远不能是静态的或私有的

静态法:

  • 它可以通过接口调用,而不需要引用特定的 对象,就像类静态方法一样

  • 静态方法可以是私有的

  • 实现类不能访问静态方法

让我们借助下面的示例代码来理解它:

            public interface MyInterface {
        

private void privateMethod() {
System.out.println("Hi, this is privateMethod");
}
        

private static void staticPrivateMethod() {
System.out.println("Hi, this is staticPrivateMethod");
}
        

static void staticMethod() {
//privateMethod();    // Non-static method cannot be referenced from a static contex
System.out.println("Hi, this is staticMethod");
staticPrivateMethod();
}
        

default void defaultMethod() {
System.out.println("Hi, this is defaultMethod");
}
        

}
    

public class MyInterfaceImpl implements MyInterface{
public static void main(String[] args) {
    

MyInterface.staticMethod();
// myInterface.staticMethod(); // Not allowed
    

MyInterface myInterface = new MyInterfaceImpl();
myInterface.defaultMethod();
// MyInterface.defaultMethod(); // Not allowed
    

}
}