ทำไมฉันไม่สามารถกำหนดวิธีการคงที่ในส่วนต่อประสาน Java?


498

แก้ไข: ในฐานะของ Java 8 ตอนนี้วิธีการคงที่ได้รับอนุญาตในส่วนต่อประสาน

นี่คือตัวอย่าง:

public interface IXMLizable<T>
{
  static T newInstanceFromXML(Element e);
  Element toXMLElement();
}

แน่นอนว่ามันจะไม่ทำงาน แต่ทำไมล่ะ

หนึ่งในปัญหาที่เป็นไปได้คือสิ่งที่เกิดขึ้นเมื่อคุณโทร:

IXMLizable.newInstanceFromXML(e);

ในกรณีนี้ฉันคิดว่ามันควรจะเรียกวิธีการที่ว่างเปล่า (เช่น {}) คลาสย่อยทั้งหมดจะถูกบังคับให้ใช้เมธอดสแตติกดังนั้นพวกมันทั้งหมดจึงใช้ได้เมื่อเรียกเมธอดสแตติก เหตุใดจึงเป็นไปไม่ได้

แก้ไข:ฉันเดาว่าฉันกำลังมองหาคำตอบที่ลึกกว่า "เพราะนั่นคือวิธีที่ Java เป็น"

มีเหตุผลทางเทคโนโลยีเฉพาะหรือไม่ทำไมวิธีการแบบคงที่ไม่สามารถเขียนทับได้? นั่นคือเหตุผลที่นักออกแบบของ Java ตัดสินใจที่จะทำให้วิธีการเช่นการแทนที่ แต่ไม่ใช่วิธีการคงที่?

แก้ไข:ปัญหาเกี่ยวกับการออกแบบของฉันคือฉันกำลังพยายามใช้อินเทอร์เฟซเพื่อบังคับใช้แบบแผนการเข้ารหัส

นั่นคือเป้าหมายของอินเทอร์เฟซคือสองเท่า:

  1. ฉันต้องการอินเทอร์เฟซ IXMLizable เพื่อให้ฉันสามารถแปลงคลาสที่นำไปใช้กับองค์ประกอบ XML (โดยใช้ polymorphism ทำงานได้ดี)

  2. ถ้ามีคนต้องการสร้างอินสแตนซ์ใหม่ของคลาสที่ใช้อินเทอร์เฟซ IXMLizable พวกเขาจะรู้อยู่เสมอว่าจะมีตัวสร้างแบบคงที่ newInstanceFromXML (องค์ประกอบ e)

มีวิธีอื่นอีกไหมในการรับรองสิ่งนี้นอกเหนือจากการใส่ความคิดเห็นในอินเทอร์เฟซ


4
คุณไม่จำเป็นต้องถ่วงวิธี (และเขตข้อมูล) คำจำกัดความด้วย public ในส่วนต่อประสาน btw
Tom Hawtin - tackline

อืมน่าจะเป็นซ้ำstackoverflow.com/questions/21817/... ไม่เคยเห็นแบบนั้นมาก่อน
Michael Myers

1
คุณสามารถให้รหัสบางส่วนว่าคุณต้องการใช้วิธีการส่วนต่อประสานแบบคงที่ได้อย่างไร
Pavel Feldman

43
สิ่งนี้จะเป็นไปได้ใน Java 8: docs.oracle.com/javase/tutorial/java/IandI/ …
dakshang

1
@dakshang ใช่ แต่มันไม่ได้ทำตามที่ OP ต้องการ
user253751

คำตอบ:


518

Java 8 อนุญาตวิธีเมธอดอินเตอร์เฟสแบบคงที่

ด้วย Java 8 อินเตอร์เฟสสามารถมีเมธอดแบบสแตติก พวกเขายังสามารถมีวิธีการอินสแตนซ์ที่เป็นรูปธรรม แต่ไม่สามารถเขตข้อมูลอินสแตนซ์

มีคำถามสองข้อจริงๆที่นี่:

  1. ทำไมในสมัยก่อนไม่สามารถอินเทอร์เฟซไม่ประกอบด้วยวิธีแบบคงที่ได้อย่างไร
  2. ทำไมวิธีการแบบคงที่ไม่สามารถเขียนทับได้

วิธีการคงที่ในส่วนต่อประสาน

ไม่มีเหตุผลทางเทคนิคที่ชัดเจนว่าเหตุใดอินเทอร์เฟซจึงไม่มีวิธีคงที่ในเวอร์ชันก่อนหน้า สิ่งนี้จะถูกสรุปโดยผู้โพสต์ของคำถามที่ซ้ำกัน วิธีการอินเตอร์เฟซแบบคงที่ได้รับการพิจารณาครั้งแรกเป็นการเปลี่ยนแปลงภาษาขนาดเล็กและจากนั้นมีข้อเสนออย่างเป็นทางการที่จะเพิ่มพวกเขาใน Java 7 แต่มันก็เป็นภายหลังลดลงในเนื่องจากภาวะแทรกซ้อนที่ไม่คาดฝัน

ในที่สุด Java 8 แนะนำวิธีการคงที่ของอินเทอร์เฟซเช่นเดียวกับวิธีการแทนที่ได้ด้วยการใช้งานเริ่มต้น พวกเขายังคงไม่สามารถมีฟิลด์อินสแตนซ์ได้ คุณสมบัติเหล่านี้เป็นส่วนหนึ่งของการรองรับการแสดงออกแลมบ์ดาและคุณสามารถอ่านเพิ่มเติมเกี่ยวกับพวกเขาได้ในส่วน H ของ JSR 335

การเอาชนะวิธีแบบคงที่

คำตอบของคำถามที่สองนั้นซับซ้อนกว่าเล็กน้อย

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

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

แกล้งทำเป็นว่าแต่ละคลาสมีตารางแฮชที่แม็พเมธอดลายเซ็นต์ (ชื่อและชนิดพารามิเตอร์) กับ chunk ของรหัสที่แท้จริงเพื่อใช้เมธอด เมื่อเครื่องเสมือนพยายามเรียกใช้เมธอดบนอินสแตนซ์มันจะสอบถามวัตถุสำหรับคลาสและค้นหาลายเซ็นที่ร้องขอในตารางของคลาส หากพบเมธอดเนื้อหามันจะถูกเรียกใช้ มิฉะนั้นจะได้รับชั้นผู้ปกครองของชั้นเรียนและการค้นหาจะถูกทำซ้ำที่นั่น NoSuchMethodErrorเงินนี้จนวิธีการที่จะพบหรือไม่มีผู้ปกครองชั้นเรียนซึ่งจะส่งผลให้

หากทั้งคลาสย่อยและคลาสย่อยมีรายการในตารางสำหรับลายเซ็นเมธอดเดียวกันเวอร์ชันของคลาสย่อยจะถูกพบก่อนและเวอร์ชันของคลาสซูเปอร์จะไม่ถูกใช้นี่คือ "แทนที่"

ทีนี้สมมติว่าเราข้ามตัวอย่างของวัตถุและเริ่มต้นด้วยคลาสย่อย ความละเอียดสามารถดำเนินการตามข้างต้นทำให้คุณมีวิธีคงที่ "overridable" การแก้ปัญหาทั้งหมดสามารถเกิดขึ้นได้ในเวลาคอมไพล์อย่างไรก็ตามเนื่องจากคอมไพเลอร์เริ่มจากคลาสที่รู้จักแทนที่จะรอจนกระทั่งรันไทม์เพื่อสอบถามวัตถุประเภทที่ไม่ระบุสำหรับคลาสนั้น ไม่มีจุดใน "การแทนที่" วิธีการคงที่เนื่องจากสามารถระบุคลาสที่มีรุ่นที่ต้องการได้เสมอ


ตัวสร้าง "อินเทอร์เฟซ"

ต่อไปนี้เป็นข้อมูลเพิ่มเติมเล็กน้อยสำหรับการแก้ไขคำถามล่าสุด

IXMLizableดูเหมือนคุณต้องการได้อย่างมีประสิทธิภาพอาณัติวิธีการคอนสตรัคเหมือนสำหรับการดำเนินงานของแต่ละคน ลืมเกี่ยวกับการพยายามบังคับใช้สิ่งนี้ด้วยอินเทอร์เฟซเป็นเวลาหนึ่งนาทีและแกล้งทำเป็นว่าคุณมีคลาสที่ตรงตามข้อกำหนดนี้ คุณจะใช้มันอย่างไร?

class Foo implements IXMLizable<Foo> {
  public static Foo newInstanceFromXML(Element e) { ... }
}

Foo obj = Foo.newInstanceFromXML(e);

เนื่องจากคุณต้องระบุชื่อประเภทคอนกรีตFooเมื่อ "สร้าง" วัตถุใหม่คอมไพเลอร์สามารถตรวจสอบว่ามันมีวิธีการโรงงานที่จำเป็นแน่นอน และถ้าไม่เช่นนั้นจะเป็นอย่างไร ถ้าฉันสามารถดำเนินการIXMLizableที่ขาด "คอนสตรัค" และฉันจะสร้างอินสแตนซ์และผ่านมันไปรหัสของคุณก็คือIXMLizableกับอินเตอร์เฟซที่จำเป็น

การก่อสร้างเป็นส่วนหนึ่งของการดำเนินการไม่ใช่ส่วนต่อประสาน รหัสใด ๆ ที่ทำงานได้ดีกับอินเทอร์เฟซไม่สนใจตัวสร้าง โค้ดใด ๆ ที่เกี่ยวกับคอนสตรัคเตอร์จำเป็นต้องทราบชนิดที่เป็นรูปธรรมอยู่แล้วและสามารถละเว้นอินเตอร์เฟสได้



12
เหตุผลที่ # 1 เป็นมรดกหลายอย่างหรือไม่ เนื่องจากเราสามารถสืบทอดจากหลายอินเตอร์เฟสได้หากสองอินเตอร์เฟสมีลายเซ็นของวิธีการสแตติกเดียวกันและจากนั้นคลาสก็ใช้ทั้งคู่และเรียกใช้เมธอดนั้นสิ่งนั้นอาจซับซ้อนในวิธีที่ผู้สร้างภาษา Java ต้องการหลีกเลี่ยงโดยไม่อนุญาตให้สืบทอดหลายคลาสใน สถานที่แรก เห็นได้ชัดว่าสามารถสร้างอาร์กิวเมนต์เดียวกันสำหรับอินเทอร์เฟซที่ไม่อนุญาตให้ใช้วิธีการใด ๆ
shrini1000

1
@ shrini1000 - ไม่วิธีการคงที่ได้รับการแก้ไขในเวลารวบรวม ความคลุมเครือสามารถจัดการได้ในลักษณะเดียวกับที่จัดการกับค่าคงที่: ด้วยข้อผิดพลาดของคอมไพเลอร์ อย่างไรก็ตามข้อเสนอภายใต้ Project Coin ถูกปฏิเสธโดยอ้างถึงปัญหาที่ไม่คาดฝัน ไม่แน่ใจว่าพวกเขาเป็นอะไร แต่ฉันไม่คิดว่ามันเป็นไปตามบรรทัดเหล่านี้
erickson

1
@ tgm1024 ใช่ส่วน "ตัวสร้างอินเทอร์เฟซ" "อธิบายว่าทำไมจึงไม่สมเหตุสมผลที่จะเรียกใช้พฤติกรรม polymorphic ผ่านประเภทที่รู้จักกันในเวลารวบรวม คุณจะเรียกRESET()ชั้นเรียนอย่างไร SomeClass.RESET()คุณต้องการเขียน ดังนั้นคุณไม่จำเป็นต้องมีอินเทอร์เฟซเพื่ออธิบาย API นั้น มันคงที่ อินเทอร์เฟซจะใช้เมื่อคุณไม่ทราบประเภทคอนกรีตในเวลารวบรวม นั่นไม่ใช่กรณีที่มีวิธีการคงที่
erickson

2
"การก่อสร้างเป็นส่วนหนึ่งของการนำไปปฏิบัติไม่ใช่ส่วนต่อประสานโค้ดใด ๆ ที่ทำงานได้ดีกับอินเทอร์เฟซไม่สนใจตัวสร้าง" - เห็นได้ชัดว่าไม่เป็นความจริง ในภาษาอื่น (เช่น Swift) ฉันสามารถสร้างอินสแตนซ์ใหม่Tโดยไม่ทราบว่าเป็นTแบบสแตติกได้เนื่องจากฉันสัญญาในอินเทอร์เฟซว่ามีตัวสร้าง (หรือวิธีการแบบคงที่) ที่รันไทม์ ความจริงที่ว่าการสร้างเป็นไปไม่ได้ที่จะระบุใน Java ไม่ได้หมายความว่าไม่ใช่สิ่งที่มีความหมายที่ต้องทำ
Raphael

48

สิ่งนี้ถูกถามและตอบแล้วที่นี่

ในการทำซ้ำคำตอบของฉัน:

ไม่เคยมีจุดที่จะประกาศวิธีคงที่ในอินเตอร์เฟซ ไม่สามารถดำเนินการได้โดยการเรียก MyInterface.staticMethod () ปกติ หากคุณเรียกพวกเขาโดยระบุคลาสการนำไปใช้งาน MyImplementor.staticMethod () คุณต้องรู้คลาสจริงดังนั้นจึงไม่เกี่ยวข้องว่าอินเทอร์เฟซนั้นมีหรือไม่

ที่สำคัญกว่านั้นคือวิธีการคงที่จะไม่ถูกแทนที่และถ้าคุณพยายามทำ:

MyInterface var = new MyImplementingClass();
var.staticMethod();

กฎสำหรับสแตติกบอกว่าวิธีการที่กำหนดไว้ในประเภทประกาศของ var จะต้องดำเนินการ เนื่องจากนี่เป็นอินเทอร์เฟซจึงเป็นไปไม่ได้

เหตุผลที่คุณไม่สามารถดำเนินการ "result = MyInterface.staticMethod ()" ก็คือมันจะต้องดำเนินการรุ่นของวิธีการที่กำหนดไว้ใน MyInterface แต่ไม่สามารถกำหนดรุ่นใน MyInterface ได้เนื่องจากเป็นส่วนต่อประสาน มันไม่มีรหัสตามคำนิยาม

ในขณะที่คุณสามารถพูดได้ว่าจำนวนนี้เป็น "เพราะ Java ทำอย่างนั้น" แต่ในความเป็นจริงการตัดสินใจเป็นผลมาจากเหตุผลของการตัดสินใจออกแบบอื่น ๆ เช่นกันด้วยเหตุผลที่ดีมาก


14
หากคุณใช้ <T ขยาย MyInterface> เป็นพารามิเตอร์ประเภททั่วไปจะเป็นการดีที่จะรับประกันผ่านอินเทอร์เฟซที่ T สามารถ. doSomething ()
Chris Betti

4
ในขณะที่ฉันเข้าใจข้อโต้แย้งฉันเห็นด้วยกับ @Chris_Betti (ถึงแม้จะไม่ใช่ประเภททั่วไป): มันเป็นเรื่องดีที่โครงสร้างโค้ดรับรองว่าบางคลาสใช้สแตติก API ที่เฉพาะเจาะจง บางทีมันอาจเป็นไปได้ที่จะใช้แนวคิดที่แตกต่าง ...
Juh_

@Juh_, ..... หรือคำหลักใหม่หากจำเป็นจริงๆ ฉันเชื่อว่าstaticเป็นคำที่หยาบคายในภาษาต่อไปและได้รับการยืดออกไปไกลเกินกว่าที่เป็นอยู่ ดังนั้นการมีด้วยตัวเองจึงเป็นภาพร่างที่สมบูรณ์ ดูตัวอย่างของฉันด้านบนstackoverflow.com/questions/512877/… {shrug}

3
สิ่งนี้ดูเหมือนว่าไม่จริง: "ไม่มีทางที่จะประกาศวิธีคงที่ในส่วนต่อประสาน" ถ้าฉันมีชุดของคลาสที่โดยไม่ต้องมีอินสแตนซ์สามารถเสนอข้อมูลบางอย่างให้ฉัน แต่ฉันต้องการอินเทอร์เฟซทั่วไปเพื่อใส่ข้อมูลระดับคลาสแบบคงที่นี้ (เช่นอินเทอร์เฟซที่มีวิธีคงที่ overridable) . Think reflection ++ ซึ่งคุณสามารถรวบรวมข้อมูล meta เกี่ยวกับคุณสมบัติของคลาสได้โดยไม่ต้องเจาะข้อมูลด้วยคุณลักษณะการไตร่ตรองและอื่น ๆ อีกต่อไป
Jason

1
"ไม่มีทางที่จะประกาศวิธีคงที่ในส่วนต่อประสาน" สิ่งนี้ไม่เป็นความจริง: จินตนาการว่าระบบของคุณมีตัวจำแนกคลาสเริ่มต้น หากตรวจพบว่าคุณใช้เมธอด ContainerInjectionInterce :: create (คอนเทนเนอร์ $ คอนเทนเนอร์) จะสร้างวัตถุด้วยฟังก์ชันนี้เป็นตัวอย่าง
3790897

37

โดยปกติจะทำโดยใช้รูปแบบโรงงาน

public interface IXMLizableFactory<T extends IXMLizable> {
  public T newInstanceFromXML(Element e);
}

public interface IXMLizable {
  public Element toXMLElement();
}

7
+1 รูปแบบจากโรงงานดูเหมือนวิธีแก้ไขปัญหา (แม้ว่าจะไม่ใช่คำถาม)
pvgoddijn

ใครสามารถบอกฉันได้ว่าอะไรคือความหมายของการใส่ <T ขยาย IXMLizable> ที่นี่ฉันใหม่กับ java แล้วมันจะทำยังไง?
Nuwan Harshakumara Piyarathna

1
@NuwanHarshakumaraPiyarathna T ต้องเป็นคลาสที่ขยาย IXMLizable มองเข้าไปใน generics Java เพื่อความเข้าใจที่ดีขึ้นของสิ่งนี้หมายถึง
เอเดรีย

37

ด้วยการถือกำเนิดของJava 8ตอนนี้เป็นไปได้ที่จะเขียนวิธีการเริ่มต้นและคงที่ในอินเตอร์เฟซ docs.oracle/staticMethod

ตัวอย่างเช่น:

public interface Arithmetic {

    public int add(int a, int b);

    public static int multiply(int a, int b) {
        return a * b;
    }
}
public class ArithmaticImplementation implements Arithmetic {

    @Override
    public int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        int result = Arithmetic.multiply(2, 3);
        System.out.println(result);
    }
}

ผลลัพธ์ : 6

เคล็ดลับ: การเรียกใช้วิธีการอินเทอร์เฟซแบบคงที่ไม่จำเป็นต้องใช้ในคลาสใด ๆ แน่นอนว่าสิ่งนี้เกิดขึ้นเพราะกฎเดียวกันสำหรับวิธีการคงที่ในซูเปอร์คลาสใช้สำหรับวิธีการแบบคงที่ในส่วนต่อประสาน


นี่เป็นตัวอย่างที่สมบูรณ์แบบของคำถามนี้

21

เนื่องจากวิธีการแบบสแตติกไม่สามารถเขียนทับในคลาสย่อยและดังนั้นจึงไม่สามารถเป็นนามธรรมได้ และวิธีการทั้งหมดในอินเทอร์เฟซคือพฤตินัยนามธรรม


2
คุณสามารถบังคับให้แต่ละประเภทใช้วิธีการคงที่ใดก็ได้ ประเภททั่วไปใคร ๆ
MichaelGG

16
ออกไปข้างนอกด้วยตัวคุณเองและตอบคำถาม: ทำไมวิธีการแบบคงที่ไม่สามารถเขียนทับได้ หากวิธีการแบบคงที่อาจถูกแทนที่สิ่งที่มันจะมีลักษณะอย่างไร คุณสามารถทำอะไรกับพวกเขา คำตอบนี้เป็นพื้น "คุณทำไม่ได้เพราะคุณทำไม่ได้"
erickson

10

ทำไมฉันไม่สามารถกำหนดวิธีการคงที่ในส่วนต่อประสาน Java?

จริงๆแล้วคุณสามารถทำได้ใน Java 8

ตามเอกสาร Java :

วิธีการคงที่เป็นวิธีการที่เกี่ยวข้องกับชั้นเรียนที่มีการกำหนดมากกว่าที่จะมีวัตถุใด ๆ ทุกอินสแตนซ์ของคลาสแบ่งปันวิธีการแบบคงที่

ใน Java 8 อินเตอร์เฟซที่สามารถมีวิธีการเริ่มต้นและวิธีการคง สิ่งนี้ทำให้ง่ายขึ้นสำหรับเราในการจัดระเบียบวิธีการช่วยเหลือในห้องสมุดของเรา เราสามารถเก็บวิธีการแบบคงที่เฉพาะกับอินเทอร์เฟซในอินเทอร์เฟซเดียวกันมากกว่าในคลาสแยกต่างหาก

ตัวอย่างของวิธีการเริ่มต้น:

list.sort(ordering);

แทน

Collections.sort(list, ordering);

ตัวอย่างของวิธีการคงที่ (จากdocเอง):

public interface TimeClient {
    // ...
    static public ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}

6

อินเทอร์เฟซเกี่ยวข้องกับ polymorphism ซึ่งผูกติดอยู่กับอินสแตนซ์ของวัตถุไม่ใช่คลาส ดังนั้นคงไม่เหมาะสมในบริบทของอินเทอร์เฟซ


ตรรกะที่ชัดเจนและกระชับ ใส่กัน
Oke Uwechue

6

ประการแรกการตัดสินใจทางภาษาทั้งหมดเป็นการตัดสินใจของผู้สร้างภาษา ไม่มีอะไรในโลกของวิศวกรรมซอฟต์แวร์หรือภาษาที่กำหนดหรือการเขียนคอมไพเลอร์ / ล่ามซึ่งบอกว่าวิธีคงที่ไม่สามารถเป็นส่วนหนึ่งของอินเตอร์เฟซ ฉันได้สร้างสองภาษาและคอมไพเลอร์ที่เขียนขึ้นสำหรับพวกเขา - มันเป็นเพียงแค่การนั่งและกำหนดความหมายที่มีความหมาย ฉันยืนยันว่าความหมายของวิธีการคงที่ในส่วนต่อประสานนั้นชัดเจนมาก - แม้ว่าคอมไพเลอร์จะต้องเลื่อนความละเอียดของวิธีการทำงาน

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

คำตอบที่ถูกต้องที่สุดคือไม่มีความต้องการการรับรู้ ณ เวลาที่ภาษาถูกกำหนดไว้สำหรับวิธีการคงที่ในส่วนต่อประสาน Java เติบโตขึ้นอย่างมากในช่วงหลายปีที่ผ่านมาและนี่คือรายการที่ได้รับความสนใจอย่างเห็นได้ชัด ว่ามันถูกมองสำหรับ Java 7 บ่งชี้ว่ามันเพิ่มขึ้นถึงระดับของความสนใจที่อาจส่งผลให้เกิดการเปลี่ยนแปลงภาษา ฉันหนึ่งจะมีความสุขเมื่อฉันไม่ต้องยกตัวอย่างวัตถุอีกต่อไปดังนั้นฉันสามารถเรียกวิธีการทะเยอทะยานที่ไม่คงที่ของฉันในการเข้าถึงตัวแปรคงที่ในอินสแตนซ์คลาสย่อย ...


5

วิธีการแบบคงที่ไม่ได้เสมือนวิธีการแบบอินสแตนซ์ดังนั้นฉันจึงคิดว่านักออกแบบ Java ตัดสินใจว่าพวกเขาไม่ต้องการให้อยู่ในอินเตอร์เฟส

แต่คุณสามารถใส่คลาสที่มีวิธีการคงที่ภายในส่วนต่อประสาน คุณลองได้!

public interface Test {
    static class Inner {
        public static Object get() {
            return 0;
        }
    }
}

5
  • "มีเหตุผลบางอย่างที่วิธีการคงที่ไม่สามารถแทนที่"

ให้ฉันตอบคำถามนั้นให้คุณโดยเติมคำจำกัดความ

  • "มีเหตุผลบางอย่างที่วิธีการแก้ไขที่รวบรวมเวลาไม่สามารถแก้ไขได้ในขณะทำงาน"

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


3

มีคำตอบมากมายที่กล่าวถึงปัญหาเกี่ยวกับแนวคิดของวิธีการสถิตแบบ overridable อย่างไรก็ตามบางครั้งคุณพบรูปแบบที่ดูเหมือนว่าเป็นเพียงสิ่งที่คุณต้องการใช้

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

cmd = createCmd(Person.getCreateCmdId());
Person p = cmd.execute();

และโหลด Person ด้วย ID ที่คุณต้องการ

cmd = createCmd(Person.getGetCmdId());
cmd.set(ID, id);
Person p = cmd.execute();

สิ่งนี้ค่อนข้างสะดวก แต่ก็มีปัญหา การคงอยู่ของวิธีคงที่นั้นไม่สามารถบังคับใช้ได้ในส่วนต่อประสาน วิธีคงที่ overridable ในอินเทอร์เฟซจะเป็นสิ่งที่เราต้องการถ้าเพียงมันสามารถทำงานได้อย่างใด

EJBs แก้ปัญหานี้ด้วยการมีส่วนต่อประสานภายในบ้าน แต่ละวัตถุรู้วิธีการค้นหาหน้าแรกและหน้าแรกประกอบด้วยวิธี "คงที่" วิธีนี้สามารถแทนที่เมธอด "สแตติก" ได้ตามต้องการและคุณไม่ได้ยุ่งกับอินเทอร์เฟซปกติ (เรียกว่า "รีโมท") ด้วยวิธีการที่ไม่ได้ใช้กับอินสแตนซ์ของ bean ของคุณ เพียงทำให้อินเตอร์เฟสปกติระบุเมธอด "getHome ()" ส่งคืนอินสแตนซ์ของวัตถุหน้าแรก (ซึ่งอาจเป็นแบบซิงเกิลฉันคิดว่า) และผู้เรียกสามารถดำเนินการที่ส่งผลต่อวัตถุบุคคลทั้งหมดได้


3

แสดงความคิดเห็น EDIT: As of Java 8, static methods are now allowed in interfaces.

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


2

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

ด้วยยาชื่อสามัญพวกเขามีการใช้ - มีหรือไม่มีการใช้งานเริ่มต้น เห็นได้ชัดว่าจะต้องมีการเอาชนะและอื่น ๆ อย่างไรก็ตามฉันเดาว่าการใช้งานดังกล่าวไม่ได้เป็น OO มาก (อย่างที่คำตอบอื่น ๆ ชี้ให้เห็นอย่างชัดเจน) และด้วยเหตุนี้จึงไม่ถือว่าคุ้มค่ากับความพยายามที่พวกเขาต้องการในการนำไปใช้อย่างเป็นประโยชน์


1
ยาชื่อสามัญต้องทำอะไรกับสิ่งนี้ วิธีการคงที่ในส่วนต่อประสานจะยังไม่สามารถใช้งานได้
DJClayworth

อันดับแรกนั่นคือการตัดสินใจดำเนินการ แต่ฉันเดาว่าเขาไม่ต้องการเรียกวิธีการคงที่บนอินเทอร์เฟซ (เขาสามารถใช้คลาส) แต่ต้องการที่จะมีบางอย่าง sorta เช่น typeclass หรือ whatnot ผ่านพารามิเตอร์ประเภท ในความเป็นจริงการแก้ไขล่าสุดของเขาแสดงให้เห็นอย่างชัดเจนยิ่งขึ้น
MichaelGG

2
Why can't I define a static method in a Java interface?

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


1

อินเตอร์เฟซที่ไม่สามารถ dereferenced ISomething.memberแบบคงที่เช่น อินเทอร์เฟซถูกอ้างอิงเสมอผ่านตัวแปรที่อ้างอิงถึงอินสแตนซ์ของคลาสย่อยของอินเทอร์เฟซ ดังนั้นการอ้างอิงอินเตอร์เฟสไม่สามารถรู้ได้ว่าคลาสย่อยใดที่อ้างอิงถึงโดยไม่มีอินสแตนซ์ของคลาสย่อย

ดังนั้นการประมาณค่าที่ใกล้เคียงที่สุดกับวิธีสแตติกในอินเทอร์เฟซจะเป็นวิธีที่ไม่คงที่ซึ่งจะละเว้น "สิ่งนี้" คือไม่เข้าถึงสมาชิกที่ไม่คงที่ของอินสแตนซ์ ที่ระดับต่ำนามธรรมทุกวิธีที่ไม่คงที่ (หลังจากการค้นหาใน vtable ใด ๆ ) เป็นจริงเพียงฟังก์ชั่นที่มีขอบเขตชั้นเรียนที่ใช้ "นี้" เป็นพารามิเตอร์ทางการนัย ดูวัตถุเดี่ยวของ Scala และการทำงานร่วมกันกับ Javaเป็นหลักฐานของแนวคิดนั้น ดังนั้นทุกวิธีคงที่เป็นฟังก์ชั่นที่มีขอบเขตชั้นเรียนที่ไม่ใช้พารามิเตอร์ "นี้" ดังนั้นโดยปกติวิธีการคงที่สามารถเรียกว่าแบบคงที่ แต่ตามที่ระบุไว้ก่อนหน้านี้อินเทอร์เฟซที่ไม่มีการใช้งาน (เป็นนามธรรม)

ดังนั้นเพื่อให้การประมาณใกล้เคียงกับวิธีการแบบคงที่ในอินเทอร์เฟซคือการใช้วิธีการแบบไม่คงที่แล้วไม่เข้าถึงสมาชิกอินสแตนซ์ที่ไม่คงที่ใด ๆ จะไม่มีผลประโยชน์ที่เป็นไปได้ทางอื่นใด ๆ เพราะมีวิธีการเชื่อมโยงแบบคงไม่มี ISomething.member()(ที่รวบรวมเวลาบริการ) ประโยชน์เพียงอย่างเดียวที่ฉันเห็นของวิธีการคงที่ในอินเทอร์เฟซคือมันจะไม่ป้อนข้อมูล (เช่นเพิกเฉย) นัย "นี่" และทำให้ไม่อนุญาตให้เข้าถึงสมาชิกอินสแตนซ์ที่ไม่คงที่ นี่จะประกาศโดยปริยายว่าฟังก์ชั่นที่ไม่เข้าถึง "นี่" นั้นไม่ได้ผลและไม่แม้แต่จะอ่านด้วยความเคารพในคลาสที่มีอยู่ แต่การประกาศของ "คงที่" ในอินเทอร์เฟซISomethingจะทำให้ผู้ที่พยายามเข้าใช้งานสับสนISomething.member()ซึ่งจะทำให้เกิดข้อผิดพลาดของคอมไพเลอร์ ฉันคิดว่าข้อผิดพลาดของคอมไพเลอร์มีการอธิบายอย่างเพียงพอมันจะดีกว่าการพยายามให้ความรู้กับผู้คนเกี่ยวกับการใช้วิธีการที่ไม่คงที่เพื่อบรรลุสิ่งที่พวกเขาต้องการ (เห็นได้ชัดว่าส่วนใหญ่เป็นวิธีการจากโรงงาน) คำถาม & เวลาบนไซต์นี้) ดังนั้นจึงเป็นเรื่องที่ไม่ง่ายสำหรับคนจำนวนมาก ฉันต้องคิดถึงมันซักพักนึงเพื่อให้ได้ความเข้าใจที่ถูกต้อง

วิธีรับฟิลด์คงที่ไม่แน่นอนในอินเทอร์เฟซคือใช้เมธอด getter และ setter ที่ไม่คงที่ในอินเตอร์เฟสเพื่อเข้าถึงฟิลด์สแตติกที่อยู่ในคลาสย่อย Sidenote static finalเห็นได้ชัดว่าไม่เปลี่ยนรูปสถิตสามารถประกาศในอินเตอร์เฟซกับ


0

อินเทอร์เฟซเพียงแค่ให้รายการสิ่งที่คลาสจะให้ไม่ใช่การใช้งานจริงของสิ่งเหล่านั้นซึ่งเป็นสิ่งที่รายการแบบคงที่ของคุณ

หากคุณต้องการสถิตศาสตร์ใช้คลาสนามธรรมและสืบทอดมิฉะนั้นให้ลบสแตติกออก

หวังว่าจะช่วย!


2
ในทางทฤษฎีคุณสามารถกำหนดอินเทอร์เฟซเพื่อรวมพฤติกรรมแบบสแตติกนั่นคือ "การใช้งานอินเทอร์เฟซนี้จะมีวิธีการแบบคงที่ foo () ด้วยลายเซ็นนี้" และออกจากการใช้งานจนถึงระดับที่เฉพาะเจาะจง ฉันพบสถานการณ์ที่พฤติกรรมนี้จะมีประโยชน์
Rob

0

คุณไม่สามารถกำหนดเมธอดสแตติกในอินเทอร์เฟซได้เนื่องจากเมธอดสแตติกเป็นของคลาสไม่ใช่อินสแตนซ์ของคลาสและอินเทอร์เฟซไม่ใช่คลาส อ่านเพิ่มเติมได้ที่นี่

อย่างไรก็ตามหากคุณต้องการคุณสามารถทำได้:

public class A {
  public static void methodX() {
  }
}

public class B extends A {
  public static void methodX() {
  }
}

ในกรณีนี้สิ่งที่คุณมีคือสองคลาสที่มี 2 วิธีคงที่ที่แตกต่างกันที่เรียกว่า methodX ()


0

สมมติว่าคุณทำได้ ลองพิจารณาตัวอย่างนี้:

interface Iface {
  public static void thisIsTheMethod();
}

class A implements Iface {

  public static void thisIsTheMethod(){
    system.out.print("I'm class A");
  }

}

class B extends Class A {

  public static void thisIsTheMethod(){
    System.out.print("I'm class B");
  } 
}

SomeClass {

  void doStuff(Iface face) {
    IFace.thisIsTheMethod();
    // now what would/could/should happen here.
  }

}

1
มันจะพิมพ์ "ฉันคลาส A" อย่างไรก็ตามถ้าคุณพิมพ์A.thisIsTheMethod()มันจะพิมพ์ว่า "ฉันเป็นคลาส B"
cdmckay

แต่ oyr เรียกวิธีการบนอินเตอร์เฟสว่าคุณ (หรือคอมไพเลอร์) รู้ได้อย่างไรว่าควรใช้วิธีใด (Rember สามารถมีชั้นเรียนมากขึ้น dricetly ดำเนิน iface
pvgoddijn

ขออภัยฉันตั้งใจจะพูดว่า: อย่างไรก็ตามถ้าคุณพิมพ์B.thisIsTheMethod()มันจะพิมพ์ว่า "ฉันเป็นคลาส B"
cdmckay

ฉันกล่าวว่า IFace.thisIs วิธีนี้เกี่ยวกับวัตถุประสงค์เพราะในนั้นมีปัญหาอยู่ มันจะเป็นไปไม่ได้ที่จะเรียกมันบนอินเทอร์เฟซโดยไม่มีพฤติกรรมที่ไม่ได้กำหนด (แม้ว่ามันจะประกาศอยู่ก็ตาม)
pvgoddijn

0

สิ่งที่สามารถใช้งานได้คือส่วนต่อประสานแบบคงที่ (แทนวิธีคงที่ในส่วนต่อประสาน) คลาสทั้งหมดที่ใช้อินเตอร์เฟสแบบสแตติกที่กำหนดควรใช้วิธีสแตติกที่สอดคล้องกัน คุณสามารถรับ SI ส่วนต่อประสานคงที่จากคลาส clazz ใด ๆ ที่ใช้

SI si = clazz.getStatic(SI.class); // null if clazz doesn't implement SI
// alternatively if the class is known at compile time
SI si = Someclass.static.SI; // either compiler errror or not null

si.method(params)จากนั้นคุณสามารถโทรหา สิ่งนี้จะมีประโยชน์ (ตัวอย่างเช่นรูปแบบการออกแบบจากโรงงาน) เนื่องจากคุณสามารถรับ (หรือตรวจสอบการใช้งาน) การใช้วิธี SI คงที่จากคลาสที่ไม่ทราบเวลารวบรวม! การกระจายแบบไดนามิกเป็นสิ่งที่จำเป็นและคุณสามารถแทนที่วิธีการแบบคงที่ (ถ้าไม่ได้สุดท้าย) ของชั้นเรียนโดยการขยายมัน (เมื่อเรียกผ่านอินเตอร์เฟซแบบคงที่) เห็นได้ชัดว่าวิธีการเหล่านี้สามารถเข้าถึงตัวแปรคงที่ของชั้นเรียนของพวกเขา


0

ในขณะที่ฉันรู้ว่า Java 8 แก้ไขปัญหานี้ได้ฉันคิดว่าฉันจะพูดสอดแทรกกับสถานการณ์ที่ฉันกำลังทำงานอยู่ (ถูกล็อคด้วยการใช้ Java 7) ซึ่งสามารถระบุวิธีการคงที่ในส่วนต่อประสานได้

ฉันมีคำจำกัดความ enum หลายอย่างที่ฉันได้กำหนดเขตข้อมูล "id" และ "displayName" พร้อมกับวิธีการของผู้ช่วยประเมินค่าด้วยเหตุผลต่างๆ การใช้อินเทอร์เฟซช่วยให้ฉันมั่นใจได้ว่ามีการใช้เมธอด getter อยู่ แต่ไม่ใช่วิธีการแบบตัวช่วยคงที่ การเป็น Enum นั้นไม่มีวิธีที่สะอาดจริง ๆ ในการถ่ายโอนเมธอดตัวช่วยไปยังคลาสนามธรรมที่สืบทอดมาหรือสิ่งที่คล้ายกัน นอกจากนี้เนื่องจากเป็น enum คุณจะไม่สามารถผ่านมันเป็นวัตถุแบบอินสแตนซ์และถือว่าเป็นประเภทอินเตอร์เฟสได้ แต่การที่ต้องอาศัยวิธีการช่วยเหลือแบบคงที่ผ่านทางอินเทอร์เฟซนั้นเป็นสิ่งที่ฉันชอบ กำลังได้รับการสนับสนุนใน Java 8

นี่คือรหัสที่แสดงจุดของฉัน

นิยามอินเตอร์เฟส:

public interface IGenericEnum <T extends Enum<T>> {
    String getId();
    String getDisplayName();
    //If I was using Java 8 static helper methods would go here
}

ตัวอย่างหนึ่งนิยาม enum:

public enum ExecutionModeType implements IGenericEnum<ExecutionModeType> {
    STANDARD ("Standard", "Standard Mode"),
    DEBUG ("Debug", "Debug Mode");

    String id;
    String displayName;

    //Getter methods
    public String getId() {
        return id;
    }

    public String getDisplayName() {
        return displayName;
    }

    //Constructor
    private ExecutionModeType(String id, String displayName) {
        this.id = id;
        this.displayName = displayName;
    }

    //Helper methods - not enforced by Interface
    public static boolean isValidId(String id) {
        return GenericEnumUtility.isValidId(ExecutionModeType.class, id);
    }

    public static String printIdOptions(String delimiter){
        return GenericEnumUtility.printIdOptions(ExecutionModeType.class, delimiter);
    }

    public static String[] getIdArray(){
        return GenericEnumUtility.getIdArray(ExecutionModeType.class);
    }

    public static ExecutionModeType getById(String id) throws NoSuchObjectException {
        return GenericEnumUtility.getById(ExecutionModeType.class, id);
    }
}

นิยามยูทิลิตี้ทั่วไป enum:

public class GenericEnumUtility {
    public static <T extends Enum<T> & IGenericEnum<T>> boolean isValidId(Class<T> enumType, String id) {       
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(enumOption.getId().equals(id)) {
                return true;
            }
        }

        return false;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String printIdOptions(Class<T> enumType, String delimiter){
        String ret = "";
        delimiter = delimiter == null ? " " : delimiter;

        int i = 0;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(i == 0) {
                ret = enumOption.getId();
            } else {
                ret += delimiter + enumOption.getId();
            }           
            i++;
        }

        return ret;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String[] getIdArray(Class<T> enumType){
        List<String> idValues = new ArrayList<String>();

        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            idValues.add(enumOption.getId());
        }

        return idValues.toArray(new String[idValues.size()]);
    }

    @SuppressWarnings("unchecked")
    public static <T extends Enum<T> & IGenericEnum<T>> T getById(Class<T> enumType, String id) throws NoSuchObjectException {
        id = id == null ? "" : id;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(id.equals(enumOption.getId())) {
                return (T)enumOption;
            }
        }

        throw new NoSuchObjectException(String.format("ERROR: \"%s\" is not a valid ID. Valid IDs are: %s.", id, printIdOptions(enumType, " , ")));
    }
}

0

สมมติว่าวิธีสแตติกได้รับอนุญาตในอินเตอร์เฟส: * พวกเขาจะบังคับให้คลาสที่ใช้งานทั้งหมดประกาศวิธีนั้น * การเชื่อมต่อมักจะใช้ผ่านวัตถุดังนั้นวิธีการที่มีประสิทธิภาพเพียงอย่างเดียวสำหรับสิ่งเหล่านั้นก็คือวิธีที่ไม่คงที่ * คลาสใด ๆ ที่รู้ว่าอินเตอร์เฟสใดสามารถเรียกใช้เมธอดสแตติกได้ ดังนั้นวิธีการคงที่ของคลาสที่ใช้งานจะถูกเรียกภายใต้ แต่คลาสของผู้เรียกใช้ไม่ทราบว่าวิธีไหน จะรู้ได้อย่างไร? มันไม่มีการคาดเดาในสิ่งนั้น!

อินเทอร์เฟซถูกคิดว่าจะใช้เมื่อทำงานกับวัตถุ ด้วยวิธีนี้วัตถุจะถูกยกตัวอย่างจากคลาสเฉพาะดังนั้นเรื่องนี้จะได้รับการแก้ไข คลาสที่กล่าวอ้างไม่จำเป็นต้องทราบว่าคลาสใดเป็นพิเศษเนื่องจากอินสแตนซ์นั้นสามารถทำได้โดยคลาสที่สาม ดังนั้นคลาสที่เรียกใช้จะรู้เพียงอินเตอร์เฟส

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

Metaclasses ทำหน้าที่เพื่อจุดประสงค์นี้ คุณอาจลองคลาสของ Java แต่ปัญหาคือ Java ไม่ยืดหยุ่นเพียงพอสำหรับเรื่องนี้ คุณไม่สามารถประกาศเมธอดในคลาสอ็อบเจ็กต์ของอินเตอร์เฟส

นี่เป็นปัญหาเมตา - เมื่อคุณต้องการลางาน

.. blah blah

อย่างไรก็ตามคุณมีวิธีแก้ปัญหาง่าย ๆ - ทำให้วิธีการไม่คงที่ด้วยตรรกะเดียวกัน แต่ก่อนอื่นคุณต้องสร้างวัตถุเพื่อเรียกใช้เมธอด


0

ในการแก้ปัญหานี้: ข้อผิดพลาด: เนื้อหาวิธีที่หายไปหรือประกาศโมฆะหลักคงที่นามธรรม (String [] args);

interface I
{
    int x=20;
    void getValue();
    static void main(String[] args){};//Put curly braces 
}
class InterDemo implements I
{
    public void getValue()
    {
    System.out.println(x);
    }
    public static void main(String[] args)
    {
    InterDemo i=new InterDemo();
    i.getValue();   
    }

}

ผลลัพธ์: 20

ตอนนี้เราสามารถใช้วิธีการคงที่ในส่วนต่อประสาน


1
แม้ว่าจะไร้ประโยชน์ก็ตาม การนิยามเมธอดสแตติกบนอินเตอร์เฟสไม่บังคับใช้ข้อกำหนดเพิ่มเติมในคลาสที่ใช้อินเตอร์เฟสดังกล่าว หากคุณเพิ่งลบเมธอดสแตติกทั้งหมดออกจากส่วนต่อประสานฉันโค้ดของคุณจะรวบรวมและรันต่อไปโดยไม่มีปัญหา กล่าวอีกนัยหนึ่งคุณไม่ได้เอาชนะวิธีการหลักของส่วนต่อประสานฉันในคลาส InterDemo เพียงแค่สร้างวิธีการใหม่ที่มีลายเซ็นเดียวกัน
Fran Marzoa

-2

ฉันคิดว่า java ไม่มีวิธีอินเตอร์เฟสแบบคงที่เนื่องจากคุณไม่ต้องการใช้ คุณอาจคิดว่าคุณทำ แต่ ... คุณจะใช้มันอย่างไร ถ้าคุณต้องการที่จะเรียกพวกเขาเช่น

MyImplClass.myMethod()

จากนั้นคุณไม่จำเป็นต้องประกาศในอินเทอร์เฟซ ถ้าคุณต้องการที่จะเรียกพวกเขาเช่น

myInstance.myMethod()

จากนั้นไม่ควรคงที่ หากคุณกำลังจะใช้วิธีแรก แต่เพียงแค่ต้องการบังคับให้แต่ละการใช้งานมีวิธีการแบบคงที่นั้นจริงๆแล้วมันเป็นแบบแผนการเข้ารหัสไม่ใช่สัญญาระหว่างอินสแตนซ์ที่ใช้อินเทอร์เฟซและรหัสการโทร

อินเทอร์เฟซช่วยให้คุณกำหนดสัญญาระหว่างอินสแตนซ์ของคลาสที่ใช้อินเทอร์เฟซและรหัสการโทร และจาวาช่วยให้คุณมั่นใจได้ว่าสัญญานี้ไม่ได้ละเมิดดังนั้นคุณสามารถพึ่งพาได้และไม่ต้องกังวลว่าชนชั้นจะใช้สัญญานี้เพียงแค่ "คนที่เซ็นสัญญา" ก็เพียงพอแล้ว ในกรณีที่อินเตอร์เฟซแบบคงที่รหัสของคุณ

MyImplClass.myMethod()

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


-5

อะไรคือความต้องการของวิธีสแตติกในอินเตอร์เฟสวิธีสแตติกจะถูกใช้โดยทั่วไปเมื่อคุณไม่ต้องสร้างอินสแตนซ์ของแนวคิดทั้งหมดของอินเทอร์เฟซคือการนำแนวคิด OOP มาใช้ด้วยการแนะนำวิธีสแตติก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.