接口中静态方法和默认方法之间的区别


107

当我发现您现在可以在接口中定义静态和默认方法时,我正在通过接口进行学习。

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

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

请解释两者的区别,并且如果有一个示例说明何时使用它会很好。在接口上有些困惑。


4
您是否尝试过在Java教程中阅读静态方法?
达伍德·伊本·卡里姆

1
因此,您错过了有关永远无法覆盖静态方法的部分?
Dawood Ibn Kareem

1
界面上的理解不一样
Vipin Menon 2015年

9
静态方法是接口的静态成员,不能被覆盖(与类一样),默认方法是default implementation可能被覆盖的方法的。
2015年

2
只是想知道:您为什么从未在这里接受答案?
GhostCat

Answers:


116

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

1)在实现类时可以覆盖默认方法,而static 不能

2)静态方法属于Interface类,因此您只能在Interface类上调用静态方法,而不能在实现此Interface的类上调用静态方法,请参见:

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

2
但是为什么要“静态”呢?它在Java 8中有什么作用?
Shashank Vivek

4
静态关键字的用途没有改变-定义类级别成员:字段,方法等。在Java 8中,此行为扩展为接口,因此它们与类更加相似,并且现在可以在大多数情况下替换类。
毒刺

是的,但是我们仍然可以隐藏接口静态方法而不是覆盖它,.....我只是认为两者都 实现相同purpose使用通用实现),并通过implementing the logic again in subclass 覆盖,隐藏)解决歧义 。唯一明智的原因是由于[静态接口方法未继承](stackoverflow.com/questions/25169175/…),因此我们不能使用子类实例来调用它们。
amarnath harish

29

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

bar另一方面,默认实现由调用

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

一个static接口方法不能知道的this变量,而是一个默认的实现可以。


19

1.解释两者的区别

静态接口方法类似于静态类方法(此处仅属于接口)。默认接口方法提供default implementation接口方法的地方(实现类可以override),
但是请记住,如果类是implementing more than one interface with same default方法签名,则实现类needs to override the default method

您可以在下面找到一个简单的示例(不同情况下可以自己制作)

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.何时使用它会很好。

这取决于您的问题陈述。我想说默认方法很有用,如果您需要在合同中所有类的规范中对方法进行相同的实现,或者可以像Adapter类一样使用它。

这是一本好书:https : //softwareengineering.stackexchange.com/questions/233053/why-were-default-and-static-methods-add-to-interfaces-in-java-8-when-we-read

同样在下面,oracle doc解释了用于改进现有接口的默认和静态方法:

具有实现用新的默认方法或静态方法增强的接口的类的用户不必修改或重新编译它们即可容纳其他方法。

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


我有个疑问。是否可以创建接口的对象?您的代码包含以下行:I1 t = new I1()
Hackinet

@Hackinet请仔细阅读该语句的Java注释。还请阅读有关匿名类的信息。希望对您有帮助。
Shail016 '18 -10-29

12

这是我的看法:

接口中的静态方法

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

  • 子类将无法覆盖。

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

接口中的默认方法

  • 您不能直接调用它。

  • 子类将能够覆盖它

优点:

  • 静态方法:您无需为实用程序方法创建单独的类。

  • 默认方法:提供默认方法的常用功能。


8

该链接具有一些有用的见解,此处仅列出了一些见解。

默认静态方法缩小了接口抽象类之间的差异。

接口默认方法:

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

接口静态方法:

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

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


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

2

根据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());
    }   

}

1

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

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

启动Java 8接口也可以具有静态方法。像类的静态方法一样,可以使用接口名称来调用接口的静态方法。

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

接口的静态方法和默认方法之间的区别是默认方法支持继承,但静态方法不支持继承。继承接口中可以覆盖默认方法。

这里是有关接口默认方法和静态方法的很好的阅读。Java 8中的接口默认方法


0

所有好的答案都在这里。我想在界面中添加静态函数的另一种实际用法。提示来自Joshua Bloch在《第二章:创建和销毁对象》中所著的有效Java,第三版。

Static functions can be used for static factory methods. 

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

书中引述-有效的Java,第3版,约书亚·布洛赫(Joshua Bloch)

在Java 8之前,接口不能具有静态方法。按照约定,将名为Type的接口的静态工厂方法放在名为Types的不可实例的伴随类(项目4)中。

作者提供了一个Collections的示例,其中实现了这种静态工厂方法。检查代码,Josh Bloch可以被视为Collections类的第一作者。尽管Collections是类而不是接口。但是这个概念仍然适用。

例如,Java Collections Framework具有其接口的四十五个实用程序实现,提供了不可修改的集合,同步的集合等。几乎所有这些实现都是通过静态工厂方法在一个不可实例化的类(java.util.Collections)中导出的。返回对象的类都是非公共的。

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

不仅减少了API的体积,而且减少了概念的权重:程序员使用该API必须掌握的概念的数量和难度。程序员知道返回的对象恰好具有其接口指定的API,因此无需阅读实现类的其他类文档。

这是java.util.Collections类的静态方法之一:

public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c) {
    return new UnmodifiableCollection<>(c);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.