JavaRush /จาวาบล็อก /Random-TH /วิธีการเริ่มต้นใน Java 8: สิ่งที่พวกเขาทำได้และไม่สามารถท...
Spitfire
ระดับ

วิธีการเริ่มต้นใน Java 8: สิ่งที่พวกเขาทำได้และไม่สามารถทำได้?

เผยแพร่ในกลุ่ม
การแปลบทความที่เขียนโดยPeter Verhasลงวันที่เดือนเมษายน 2014 วิธีการเริ่มต้นใน Java 8: สิ่งที่พวกเขาทำได้และไม่สามารถทำได้?  - 1จากผู้แปล: คำว่า " default method " เพิ่งปรากฏใน Java และฉันไม่แน่ใจว่ามีการแปลเป็นภาษารัสเซียหรือไม่ ฉันจะใช้คำว่า "วิธีการเริ่มต้น" แม้ว่าฉันจะไม่คิดว่ามันเหมาะก็ตาม ฉันขอเชิญชวนให้คุณหารือเกี่ยวกับการแปลที่ประสบความสำเร็จมากขึ้น

วิธีการเริ่มต้นคืออะไร

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

มรดกหลายรายการ?

สิ่งต่างๆ จะซับซ้อนมากขึ้นหากคลาสใช้อินเทอร์เฟซมากกว่าหนึ่ง (เช่น สอง) และใช้วิธีการเริ่มต้นเดียวกัน คลาสจะสืบทอดวิธีใด คำตอบคือไม่มี ในกรณีนี้ คลาสจะต้องใช้วิธีการนั้นเอง (ไม่ว่าจะโดยตรงหรือโดยการสืบทอดจากคลาสอื่น) สถานการณ์จะคล้ายกันหากมีเพียงอินเทอร์เฟซเดียวที่มีวิธีการเริ่มต้น และอีกวิธีหนึ่งนั้นเป็นนามธรรม Java 8 พยายามรักษาวินัยและหลีกเลี่ยงสถานการณ์ที่ไม่ชัดเจน หากมีการประกาศวิธีการในอินเทอร์เฟซมากกว่าหนึ่งรายการ คลาสจะไม่มีการนำไปใช้งานเริ่มต้น คุณจะได้รับข้อผิดพลาดในการคอมไพล์ แม้ว่าคุณอาจไม่ได้รับข้อผิดพลาดในการคอมไพล์หากคลาสของคุณถูกคอมไพล์แล้ว Java 8 ไม่แข็งแกร่งเพียงพอในเรื่องนี้ มีเหตุผลหลายประการที่ฉันไม่ต้องการพูดคุย (เช่น: Java release ได้รับการเผยแพร่แล้วและเวลาสำหรับการสนทนาผ่านไปนานแล้วและโดยทั่วไปนี่ไม่ใช่ที่สำหรับพวกเขา)
  • สมมติว่าคุณมีสองอินเทอร์เฟซและคลาสใช้งานทั้งสองอินเทอร์เฟซ
  • หนึ่งในอินเทอร์เฟซใช้วิธีการเริ่มต้น m()
  • คุณรวบรวมอินเทอร์เฟซและคลาสทั้งหมด
  • คุณเปลี่ยนอินเทอร์เฟซที่ไม่มีเมธอด m() โดยประกาศว่าเป็นวิธีนามธรรม
  • คุณคอมไพล์เฉพาะอินเทอร์เฟซที่แก้ไขแล้ว
  • เริ่มชั้นเรียน
วิธีการเริ่มต้นใน Java 8: สิ่งที่พวกเขาทำได้และไม่สามารถทำได้?  - 2ในกรณีนี้ชั้นเรียนใช้งานได้ คุณไม่สามารถคอมไพล์ด้วยอินเทอร์เฟซที่อัปเดต แต่คอมไพล์ด้วยเวอร์ชันเก่ากว่าจึงใช้งานได้ ตอนนี้
  • เปลี่ยนอินเทอร์เฟซด้วยวิธี abstract m() และเพิ่มการใช้งานเริ่มต้น
  • รวบรวมอินเทอร์เฟซที่แก้ไข
  • เรียกใช้คลาส: ข้อผิดพลาด
เมื่อมีสองอินเทอร์เฟซที่ให้การใช้งานเริ่มต้นของวิธีการ วิธีการนั้นจะไม่สามารถเรียกในคลาสได้ เว้นแต่จะถูกนำไปใช้โดยคลาสนั้นเอง (อีกครั้ง ไม่ว่าจะด้วยตัวมันเองหรือสืบทอดจากคลาสอื่น) วิธีการเริ่มต้นใน Java 8: สิ่งที่พวกเขาทำได้และไม่สามารถทำได้?  - 3เข้ากันได้กับชั้นเรียน สามารถโหลดได้ด้วยอินเทอร์เฟซที่แก้ไขแล้ว มันอาจจะทำงานจนกว่าจะมีการเรียกเมธอดที่มีการใช้งานเริ่มต้นในอินเทอร์เฟซทั้งสอง

รหัสตัวอย่าง

วิธีการเริ่มต้นใน Java 8: สิ่งที่พวกเขาทำได้และไม่สามารถทำได้?  - 4เพื่อสาธิตข้างต้น ฉันได้สร้างไดเร็กทอรีทดสอบสำหรับคลาส C.java และไดเร็กทอรีย่อย 3 ไดเร็กทอรีสำหรับอินเทอร์เฟซในไฟล์ I1.java และ I2.java ไดเร็กทอรีรากสำหรับการทดสอบประกอบด้วยซอร์สโค้ดสำหรับคลาส C.java ไดเร็กทอรีฐานประกอบด้วยเวอร์ชันของอินเทอร์เฟซที่เหมาะสมสำหรับการดำเนินการและการคอมไพล์: อินเทอร์เฟซ I1 มีเมธอดดีฟอลต์ m(); อินเทอร์เฟซ I2 ยังไม่มีวิธีการใดๆ คลาสมีเมธอดmainเพื่อให้เราสามารถดำเนินการทดสอบได้ จะตรวจสอบว่ามีข้อโต้แย้งบรรทัดคำสั่งหรือไม่ เพื่อให้เราสามารถดำเนินการได้อย่างง่ายดายไม่ว่าจะมีหรือไม่มีการเรียกไฟล์m().
~/github/test$ cat C.java
public class C implements I1, I2 {
  public static void main(String[] args) {
    C c = new C();
    if( args.length == 0 ){
      c.m();
    }
  }
}
~/github/test$ cat base/I1.java
public interface I1 {
  default void m(){
    System.out.println("hello interface 1");
  }
}
~/github/test$ cat base/I2.java
public interface I2 {
}
คุณสามารถคอมไพล์และรันคลาสได้จากบรรทัดคำสั่ง
~/github/test$ javac -cp .:base C.java
~/github/test$ java -cp .:base C
hello interface 1
ไดเร็กทอรีที่เข้ากันได้มีเวอร์ชันของอินเทอร์เฟซ I2 ที่ประกาศว่าเมธอด m() เป็นแบบนามธรรม และด้วยเหตุผลทางเทคนิค จึงมีสำเนา I1.java ที่ยังไม่ได้แก้ไข
~/github/test$ cat compatible/I2.java

public interface I2 {
  void m();
}
ชุดดังกล่าวไม่สามารถใช้ในการรวบรวมคลาส C:
~/github/test$ javac -cp .:compatible C.java
C.java:1: error: C is not abstract and does not override abstract method m() in I2
public class C implements I1, I2 {
       ^
1 error
ข้อความแสดงข้อผิดพลาดมีความถูกต้องมาก อย่างไรก็ตาม เรามี C.class จากการคอมไพล์ครั้งก่อน และหากเราคอมไพล์อินเทอร์เฟซลงในไดเร็กทอรีที่เข้ากันได้ เราจะมีสองอินเทอร์เฟซที่ยังคงสามารถใช้เพื่อรันคลาสได้:
~/github/test$ javac compatible/I*.java
~/github/test$ java -cp .:compatible C
hello interface 1
ไดเรกทอรีที่สาม - wrong- มีเวอร์ชัน I2 ซึ่งประกาศวิธีการด้วยm():
~/github/test$ cat wrong/I2.java
public interface I2 {
  default void m(){
    System.out.println("hello interface 2");
  }
}
คุณไม่ต้องกังวลกับการรวบรวม แม้ว่าเมธอดนี้จะถูกประกาศสองครั้ง แต่คลาสยังคงสามารถใช้งานและรันได้จนกว่าจะมีการเรียกใช้เมธอด m() นี่คือสิ่งที่เราต้องการอาร์กิวเมนต์บรรทัดคำสั่งสำหรับ:
~/github/test$ javac wrong/*.java
~/github/test$ java -cp .:wrong C
Exception in thread "main" java.lang.IncompatibleClassChangeError: Conflicting default methods: I1.m I2.m
    at C.m(C.java)
    at C.main(C.java:5)
~/github/test$ java -cp .:wrong C x
~/github/test$

บทสรุป

เมื่อคุณย้ายไลบรารีของคุณไปที่ Java 8 และเปลี่ยนอินเทอร์เฟซของคุณให้มีวิธีการเริ่มต้น คุณอาจไม่มีปัญหาใดๆ อย่างน้อยนั่นคือสิ่งที่นักพัฒนาไลบรารี Java 8 คาดหวังเมื่อพวกเขาเพิ่มฟังก์ชันการทำงาน แอปพลิเคชันที่ใช้ไลบรารีของคุณยังคงใช้งานสำหรับ Java 7 ซึ่งไม่มีวิธีการเริ่มต้น หากใช้หลายไลบรารีร่วมกัน อาจเกิดข้อขัดแย้งได้ จะหลีกเลี่ยงได้อย่างไร? ออกแบบ API ของห้องสมุดของคุณในลักษณะเดียวกับเมื่อก่อน อย่าชะล่าใจโดยอาศัยความสามารถของวิธีการเริ่มต้น พวกเขาเป็นทางเลือกสุดท้าย เลือกชื่ออย่างระมัดระวังเพื่อหลีกเลี่ยงการชนกับอินเทอร์เฟซอื่นๆ มาดูกันว่าการพัฒนา Java โดยใช้ฟีเจอร์นี้จะพัฒนาไปอย่างไร
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION