Java接口中静态方法和默认方法有何区别?

136

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

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

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

请简要说明这两者之间的区别,如果有使用示例更好。接口让我有点困惑。


4
你尝试过在Java教程中阅读关于静态方法的内容吗? - Dawood ibn Kareem
1
所以你错过了一个关于无法覆盖静态方法的部分? - Dawood ibn Kareem
1
不理解接口上的相同之处。 - Vipin Menon
16
静态方法是接口的静态成员,不能像类一样被覆盖。默认方法是方法的“默认实现”,可以被覆盖。 - Shailesh Aswal
3
只是好奇:为什么你从来没有在这里接受过答案? - GhostCat
12个回答

147

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

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..");
    }
}

4
为什么要使用“static”?在Java 8中,它有什么作用? - Shashank Vivek
6
static关键字的目的没有改变——定义类级别成员:字段,方法等。在Java 8中,这种行为被扩展到接口上,使它们更类似于类,并且现在可以在大多数场景中替代类。 - stinger
是的,但我们仍然可以隐藏接口静态方法而不是覆盖它们...我只是认为两者都实现了相同的目的(使用公共实现)并通过在子类中再次实现逻辑 (覆盖,隐藏) 来解决歧义。唯一合理的原因可能是由于接口静态方法不被继承,因此我们无法使用子类实例调用它们。 - amarnath harish

31

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

另一方面,默认实现bar则是通过调用:

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

静态接口方法无法访问 this 变量,但默认实现可以。


21
1. 解释两者的区别:
静态接口方法类似于静态类方法(它们仅属于接口)。默认接口方法提供了接口方法的默认实现(实现类可以覆盖)。但是请注意,如果一个类实现了具有相同默认方法签名的多个接口,则实现类需要覆盖默认方法。 您可以在下面找到一个简单的示例(可以为不同情况 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);
    }
}

2. 我们什么时候会使用这个功能呢?

这取决于您的问题陈述。我认为,如果您需要在该契约中的所有类中将某个方法的实现相同,则默认方法非常有用,或者它可以像适配器类一样使用。

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

此外,下面的 Oracle 文档解释了默认和静态方法如何用于演化现有接口:

实现增强了新默认或静态方法的接口的类的用户不必修改或重新编译它们以适应其他方法。

http://docs.oracle.com/javase/tutorial/java/IandI/nogrow.html


我有一个疑问。是否可以创建一个接口的对象?你的代码有这一行:I1 t = new I1() - Hackinet
@Hackinet 请阅读该语句上的 Java 评论。还请了解匿名类。希望对您有所帮助。 - Shailesh Aswal

17

以下是我的看法:

接口中的静态方法:

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

  • 子类将无法重写。

  • 子类可能会有与staticMethod同名的方法。

接口中的默认方法:

  • 不能直接调用。

  • 子类将能够重写它。

优点:

  • 静态方法:您不需要创建单独的类来实现公用方法。

  • 默认方法:在默认方法中提供公共功能。


8

这个链接提供了一些有用的见解,以下是其中的部分内容。

defaultstatic方法已经弥合了接口和抽象类之间的差异。

接口default方法:

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

接口static方法:

  • 它们是接口的一部分,我们无法将其用于实现类对象。
  • 它有助于通过不允许实现类覆盖它们来提供安全性。

这里引用另一个有用的参考资料


6
根据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
    
        }
    }


4
根据Oracle的Javadocs:http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html 默认方法使您能够向库接口添加新功能,并确保与旧版本接口的代码具有二进制兼容性。
静态方法是一种与任何对象无关,而是与定义它的类相关联的方法。该类的每个实例都共享其静态方法。
通常,在接口中使用静态方法作为助手方法,而使用默认方法作为实现该接口的类的默认实现。
示例:
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());
    }   

}

3

接口默认方法:

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

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

接口静态方法:

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

它有助于通过不允许实现类覆盖它们来提供安全性。

现在介绍静态方法如何提供安全性。让我们看一个例子。

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(); 打印类的实现逻辑,但没有更改接口实现。因此,如果在该方法中编写了任何加密解密逻辑,则无法更改。


这个答案开始似乎有一定方向,然后突然就没有了有意义的结论。但是“但没改变接口实现”是什么意思呢? - amarnath harish

0

我们无法执行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");
    }
}

0

静态接口方法:

  1. 它是属于接口的静态方法。我们可以在接口本身中编写此方法的实现。
  2. 静态方法只能在接口类上调用,而不能在类上调用。
  3. 接口和实现类都可以具有相同名称的静态方法,而不会互相覆盖。
  4. 它可用作实用程序方法。

默认方法:

  1. 它是带有默认关键字的方法,类可以重写此方法。
  2. 它可以在接口以及类上调用。
  3. 我们可以在实现类中重写默认方法。
  4. 它可用于在所有实现类中提供公共功能。

这里有一个详细解释的链接。详细示例:Java 中接口中的默认方法与静态方法有什么区别?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接