ความแตกต่างระหว่างวิธีการคงที่และวิธีเริ่มต้นในอินเทอร์เฟซ


108

ฉันเรียนรู้ผ่านอินเทอร์เฟซเมื่อสังเกตเห็นว่าตอนนี้คุณสามารถกำหนดวิธีการแบบคงที่และเริ่มต้นในอินเทอร์เฟซได้

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

9
วิธีการแบบคงที่เป็นสมาชิกแบบคงที่ของอินเทอร์เฟซไม่สามารถแทนที่ได้ (เช่นเดียวกับคลาส) เมธอดดีฟอลต์คือdefault implementationเมธอดที่อาจถูกแทนที่
Shail016

2
แค่สงสัยว่าทำไมคุณถึงไม่ยอมรับคำตอบที่นี่?
GhostCat

คำตอบ:


117

ความแตกต่างระหว่างวิธีการคงที่และวิธีเริ่มต้นใน Java 8:

1) วิธีการเริ่มต้นสามารถ overriden ในการดำเนินการระดับในขณะที่คงไม่สามารถ

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

2
แต่ทำไม 'คง'? มันทำหน้าที่อะไรใน Java 8?
Shashank Vivek

5
วัตถุประสงค์ของคีย์เวิร์ดแบบคงที่ไม่เปลี่ยนแปลง - เพื่อกำหนดสมาชิกระดับคลาส: ฟิลด์เมธอดและอื่น ๆ ใน Java 8 พฤติกรรมนี้ถูกขยายไปยังอินเทอร์เฟซดังนั้นจึงคล้ายกับคลาสมากขึ้นและตอนนี้สามารถแทนที่คลาสได้ในสถานการณ์ส่วนใหญ่
เหล็กใน

ใช่ แต่เรายังสามารถซ่อนวิธีการคงที่ของอินเทอร์เฟซได้แทนที่จะลบล้าง .... ฉันแค่คิดว่าทั้งคู่ ตอบสนองเหมือนกันpurpose( ใช้การใช้งานทั่วไป ) และแก้ไขความคลุมเครือโดย implementing the logic again in subclass (การลบล้างการซ่อน ) เหตุผลเดียวที่สมเหตุสมผลน่าจะเกิดจากสาเหตุที่ [วิธีการอินเตอร์เฟสแบบคงที่ไม่ได้รับการสืบทอด] ( stackoverflow.com/questions/25169175/… ) และด้วยเหตุนี้เราจึงไม่สามารถเรียกใช้โดยใช้อินสแตนซ์คลาสย่อยได้
amarnath ทำร้าย

29

วิธีการแบบคงที่เป็นวิธีการที่ใช้กับคลาส 'เนมสเปซ' เพื่อที่จะพูด ดังนั้นstaticวิธีการfooของอินเตอร์เฟซที่มีการเข้าถึงโดยInterface Interface.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

คุณสามารถดูตัวอย่างง่ายๆด้านล่าง (สามารถ 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. เมื่อเราจะใช้สิ่งนี้จะดี

ขึ้นอยู่กับคำชี้แจงปัญหาของคุณ ฉันจะบอกว่าวิธีการเริ่มต้นมีประโยชน์ถ้าคุณต้องการการใช้งานแบบเดียวกันสำหรับวิธีการในข้อกำหนดของคุณในทุกคลาสในสัญญานั้นหรืออาจใช้เหมือนAdapterคลาส

นี่คือการอ่านที่ดี: /software/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


ฉันมีข้อสงสัย สามารถสร้างวัตถุของอินเทอร์เฟซได้หรือไม่? รหัสของคุณมีบรรทัดนี้: I1 t = new I1 ()
Hackinet

@Hackinet กรุณาอ่านความคิดเห็นจาวาเกี่ยวกับข้อความนั้น โปรดอ่านเกี่ยวกับคลาส Anonymous หวังว่าจะช่วยคุณได้
Shail016

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 ทำร้าย

2

อ้างอิงจาก Javadocs ของ Oracle: 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());
    }   

}

1

ตามJava14 JLS doc:

วิธีเริ่มต้น:

  • เป็นวิธีการอินสแตนซ์ที่ประกาศในอินเทอร์เฟซที่มีตัวปรับค่าเริ่มต้น

  • สามารถเข้าถึงได้โดยอินสแตนซ์ของคลาสการนำไปใช้เท่านั้น

  • เนื้อหาจะแสดงด้วยบล็อกเสมอซึ่งจัดเตรียมการนำไปใช้หรือพฤติกรรมเริ่มต้นสำหรับคลาสการนำไปใช้งานใด ๆ โดยไม่ลบล้างเมธอด

  • ไม่สามารถเป็นแบบคงที่หรือเป็นส่วนตัวได้

วิธีคงที่:

  • สามารถเรียกใช้โดยอินเทอร์เฟซโดยไม่ต้องอ้างอิงกับออบเจ็กต์เฉพาะเช่นเดียวกับวิธีการคงที่คลาส

  • วิธีการคงที่สามารถเป็นส่วนตัวได้

  • คลาสการนำไปใช้ไม่สามารถเข้าถึงวิธีการแบบคงที่

มาทำความเข้าใจด้วยความช่วยเหลือของโค้ดตัวอย่างด้านล่าง:

            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

คำตอบที่ดีทั้งหมดที่นี่ ฉันต้องการเพิ่มการใช้งานฟังก์ชันคงที่ในอินเทอร์เฟซ เคล็ดลับมาจากหนังสือ - Effective Java, 3rd Edition โดย Joshua Bloch ใน Chapter2: การสร้างและทำลายวัตถุ

Static functions can be used for static factory methods. 

วิธีโรงงานแบบคงที่คือวิธีการที่ส่งคืนวัตถุ พวกเขาทำงานเหมือนตัวสร้าง ในบางกรณีวิธีการโรงงานแบบคงที่ให้รหัสที่อ่านได้มากกว่าการใช้ตัวสร้าง

อ้างจากหนังสือ - Effective Java, 3rd Edition โดย Joshua Bloch

ก่อนหน้า Java 8 อินเทอร์เฟซต้องไม่มีเมธอดแบบคงที่ ตามแบบแผนวิธีการโรงงานแบบคงที่สำหรับอินเทอร์เฟซที่ชื่อ Type ถูกใส่ไว้ในคลาสการแสดงร่วมที่ไม่หยุดนิ่ง (รายการ 4) ที่ชื่อประเภท

ผู้เขียนยกตัวอย่างคอลเลกชันที่ใช้วิธีการโรงงานแบบคงที่ดังกล่าว เมื่อตรวจสอบโค้ดแล้ว Josh Bloch จะถูกมองว่าเป็นผู้เขียนคนแรกของคลาส 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);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.