ความแตกต่างระหว่างคลาส Abstact และอินเตอร์เฟส
- คลาสนามธรรมกับอินเตอร์เฟสใน Java 8
- ความแตกต่างทางแนวคิด:
วิธีการเริ่มต้นของอินเตอร์เฟสใน Java 8
- วิธีการเริ่มต้นคืออะไร?
- ข้อผิดพลาดในการรวบรวมวิธี ForEach แก้ไขได้โดยใช้วิธีการเริ่มต้น
- วิธีการเริ่มต้นและปัญหาความกำกวมหลายประการ
- จุดสำคัญเกี่ยวกับวิธีการเริ่มต้นของอินเตอร์เฟส Java:
วิธีการคง Java Interface
- Java Interface Static Method ตัวอย่างโค้ดวิธี static เทียบกับวิธีการเริ่มต้น
- จุดสำคัญเกี่ยวกับวิธีการคงที่ของอินเตอร์เฟส Java:
Java ฟังก์ชั่นอินเทอร์เฟซ
คลาสนามธรรมกับอินเตอร์เฟสใน Java 8
การเปลี่ยนแปลงส่วนต่อประสานของ Java 8 รวมถึงวิธีการคงที่และวิธีการเริ่มต้นในส่วนต่อประสาน ก่อนหน้า Java 8 เราสามารถมีวิธีการประกาศในอินเตอร์เฟสเท่านั้น แต่จาก Java 8 เราสามารถมีวิธีการเริ่มต้นและวิธีการคงที่ในส่วนต่อประสาน
หลังจากแนะนำวิธีการเริ่มต้นดูเหมือนว่าอินเทอร์เฟซและคลาสนามธรรมเหมือนกัน อย่างไรก็ตามพวกเขายังคงแนวคิดที่แตกต่างใน Java 8
คลาสนามธรรมสามารถกำหนดตัวสร้าง พวกเขามีโครงสร้างมากขึ้นและสามารถมีสถานะที่เกี่ยวข้องกับพวกเขา ในขณะที่ตรงกันข้ามวิธีการเริ่มต้นสามารถใช้งานได้เฉพาะในแง่ของการเรียกใช้วิธีการอินเทอร์เฟซอื่น ๆ โดยไม่มีการอ้างอิงถึงสถานะของการใช้งานเฉพาะ ดังนั้นการใช้เพื่อวัตถุประสงค์ที่แตกต่างกันและการเลือกระหว่างสองอย่างขึ้นอยู่กับบริบทของสถานการณ์
ความแตกต่างทางแนวคิด:
คลาสนามธรรมใช้ได้สำหรับการใช้งานโครงร่าง (เช่นบางส่วน) ของอินเตอร์เฟส แต่ไม่ควรมีอยู่หากไม่มีอินเตอร์เฟสที่ตรงกัน
ดังนั้นเมื่อคลาสนามธรรมลดลงอย่างมีประสิทธิภาพเป็นทัศนวิสัยต่ำการใช้งานโครงร่างของอินเตอร์เฟสวิธีการเริ่มต้นสามารถเอาสิ่งนี้ออกไปได้ด้วยหรือไม่? ตัดสินใจแล้ว: ไม่! การใช้อินเทอร์เฟซมักต้องใช้เครื่องมือสร้างคลาสบางส่วนหรือทั้งหมดซึ่งวิธีการเริ่มต้นขาดหายไป และถ้าอินเทอร์เฟซบางตัวไม่เห็นได้ชัดว่าเป็นกรณีพิเศษซึ่งไม่ควรทำให้คุณหลงทาง
วิธีการเริ่มต้นของอินเตอร์เฟสใน Java 8
Java 8 เปิดตัวคุณสมบัติใหม่“ วิธีการเริ่มต้น ” หรือ (วิธีการป้องกัน) ซึ่งช่วยให้นักพัฒนาสามารถเพิ่มวิธีการใหม่ในอินเทอร์เฟซโดยไม่ทำให้การใช้งานอินเทอร์เฟซเหล่านี้แตกหัก มันให้ความยืดหยุ่นในการอนุญาตให้ Interface กำหนดการใช้งานซึ่งจะใช้เป็นค่าเริ่มต้นในสถานการณ์ที่คลาสคอนกรีตล้มเหลวในการเตรียมการใช้งานสำหรับวิธีการนั้น
ลองพิจารณาตัวอย่างเล็ก ๆ เพื่อทำความเข้าใจว่ามันทำงานอย่างไร:
public interface OldInterface {
public void existingMethod();
default public void newDefaultMethod() {
System.out.println("New default method"
+ " is added in interface");
}
}
คลาสต่อไปนี้จะคอมไพล์สำเร็จใน Java JDK 8
public class OldInterfaceImpl implements OldInterface {
public void existingMethod() {
// existing implementation is here…
}
}
หากคุณสร้างอินสแตนซ์ของ OldInterfaceImpl:
OldInterfaceImpl obj = new OldInterfaceImpl ();
// print “New default method add in interface”
obj.newDefaultMethod();
วิธีการเริ่มต้นจะไม่สิ้นสุดไม่สามารถทำข้อมูลให้ตรงกันและไม่สามารถแทนที่วิธีการของวัตถุ พวกเขาเป็นสาธารณะเสมอซึ่งจำกัดความสามารถในการเขียนวิธีการสั้นและนำกลับมาใช้อย่างรุนแรง
วิธีการเริ่มต้นสามารถให้กับอินเทอร์เฟซโดยไม่มีผลต่อการใช้งานคลาสเนื่องจากมีการใช้งาน หากแต่ละวิธีที่เพิ่มเข้ามาในส่วนต่อประสานที่กำหนดไว้พร้อมกับการนำไปใช้งานจะไม่มีผลกระทบต่อการนำคลาสไปใช้ คลาสที่ใช้งานสามารถแทนที่การใช้งานเริ่มต้นที่ได้รับจากอินเทอร์เฟซ
วิธีการเริ่มต้นเปิดใช้งานเพื่อเพิ่มฟังก์ชันการทำงานใหม่ให้กับอินเทอร์เฟซที่มีอยู่
เมื่อเราขยายส่วนต่อประสานที่มีวิธีการเริ่มต้นเราสามารถดำเนินการดังต่อไปนี้
- ไม่ได้แทนที่วิธีการเริ่มต้นและจะสืบทอดวิธีการเริ่มต้น
- แทนที่วิธีการเริ่มต้นคล้ายกับวิธีอื่น ๆ ที่เราแทนที่ในคลาสย่อย
- Redeclare วิธีการเริ่มต้นเป็นนามธรรมซึ่งบังคับให้คลาสย่อยแทนที่มัน
ข้อผิดพลาดในการรวบรวมวิธี ForEach แก้ไขได้โดยใช้วิธีการเริ่มต้น
สำหรับ Java 8, คอลเลกชัน JDK ได้รับการขยายและวิธีการ forEach ถูกเพิ่มเข้าไปในคอลเลกชันทั้งหมด (ซึ่งทำงานร่วมกับ lambdas) ด้วยวิธีการทั่วไปรหัสมีลักษณะดังนี้
public interface Iterable<T> {
public void forEach(Consumer<? super T> consumer);
}
เนื่องจากสิ่งนี้ส่งผลให้แต่ละคลาสที่ใช้งานมีข้อผิดพลาดในการคอมไพล์ดังนั้นจึงมีวิธีการเริ่มต้นที่เพิ่มเข้ามาพร้อมกับการใช้งานที่จำเป็นเพื่อไม่ให้มีการใช้งานที่มีอยู่
Iterable Interface ที่มีวิธีการเริ่มต้นอยู่ด้านล่าง
public interface Iterable<T> {
public default void forEach(Consumer
<? super T> consumer) {
for (T t : this) {
consumer.accept(t);
}
}
}
มีการใช้กลไกเดียวกันนี้เพื่อเพิ่มกระแสข้อมูลในอินเทอร์เฟซ JDK โดยไม่ทำลายการใช้คลาส
วิธีการเริ่มต้นและปัญหาความกำกวมหลายประการ
เนื่องจากจาวาคลาสสามารถใช้อินเตอร์เฟสหลายอินเทอร์เฟซและแต่ละอินเตอร์เฟสสามารถกำหนดวิธีการเริ่มต้นด้วยลายเซ็นวิธีเดียวกันดังนั้นวิธีที่สืบทอดมาจึงสามารถขัดแย้งกันได้
ลองพิจารณาตัวอย่างด้านล่าง
public interface InterfaceA {
default void defaultMethod(){
System.out.println("Interface A default method");
}
}
public interface InterfaceB {
default void defaultMethod(){
System.out.println("Interface B default method");
}
}
public class Impl implements InterfaceA, InterfaceB {
}
รหัสข้างต้นจะไม่สามารถรวบรวมกับข้อผิดพลาดดังต่อไปนี้
java: class Impl สืบทอดค่าเริ่มต้นที่ไม่เกี่ยวข้องสำหรับ defaultMethod () จากประเภท InterfaceA และ InterfaceB
ในการแก้ไขคลาสนี้เราจำเป็นต้องจัดเตรียมการใช้วิธีการเริ่มต้น:
public class Impl implements InterfaceA, InterfaceB {
public void defaultMethod(){
}
}
นอกจากนี้หากเราต้องการเรียกใช้การติดตั้งเริ่มต้นจากอินเทอร์เฟซสุดยอดใด ๆ แทนที่จะใช้งานของเราเองเราสามารถทำได้ดังนี้
public class Impl implements InterfaceA, InterfaceB {
public void defaultMethod(){
// existing code here..
InterfaceA.super.defaultMethod();
}
}
เราสามารถเลือกการใช้งานเริ่มต้นหรือทั้งสองอย่างเป็นส่วนหนึ่งของวิธีการใหม่ของเรา
จุดสำคัญเกี่ยวกับวิธีการเริ่มต้นของอินเตอร์เฟส Java:
- วิธีการตั้งค่าเริ่มต้นของส่วนต่อประสาน Java จะช่วยเราในการขยายส่วนต่อประสานโดยไม่ต้องกลัวการทำลายชั้นเรียนการใช้งาน
- วิธีการเริ่มต้นของส่วนต่อประสาน Java ได้ลดความแตกต่างระหว่างส่วนต่อประสานและคลาสนามธรรม
- วิธีการตั้งค่าเริ่มต้นของอินเตอร์เฟส Java 8 จะช่วยเราในการหลีกเลี่ยงคลาสยูทิลิตี้เช่นเมธอดคลาส Collections ทั้งหมดสามารถจัดเตรียมไว้ในอินเตอร์เฟสได้
- วิธีการเริ่มต้นของอินเตอร์เฟส Java จะช่วยเราในการลบคลาสการใช้งานพื้นฐานเราสามารถจัดให้มีการใช้งานเริ่มต้นและคลาสการใช้งานสามารถเลือกที่จะแทนที่
- หนึ่งในเหตุผลสำคัญสำหรับการแนะนำวิธีการเริ่มต้นในส่วนต่อประสานคือการปรับปรุง Collections API ใน Java 8 เพื่อรองรับการแสดงออกแลมบ์ดา
- ถ้าคลาสใด ๆ ในลำดับชั้นมีเมธอดที่มีลายเซ็นเหมือนกันดังนั้นเมธอดดีฟอลต์จะไม่เกี่ยวข้อง วิธีการเริ่มต้นไม่สามารถแทนที่วิธีการจาก java.lang.Object เหตุผลง่ายมากก็เพราะ Object เป็นคลาสพื้นฐานสำหรับคลาส java ทั้งหมด ดังนั้นแม้ว่าเราจะมีวิธีการคลาสวัตถุที่กำหนดเป็นวิธีการเริ่มต้นในการเชื่อมต่อก็จะไร้ประโยชน์เพราะวิธีการวัตถุคลาสจะถูกนำมาใช้เสมอ นั่นเป็นเหตุผลที่จะหลีกเลี่ยงความสับสนเราไม่สามารถมีวิธีการเริ่มต้นที่เอาชนะวิธีการคลาสวัตถุ
- วิธีการเริ่มต้นส่วนต่อประสาน Java ยังถูกอ้างถึงเป็นวิธีการ Defender หรือวิธีการขยายเสมือน
ลิงค์ทรัพยากร:
- ส่วนต่อประสานกับวิธีการเริ่มต้นกับคลาสนามธรรมใน Java 8
- คลาสนามธรรมกับอินเทอร์เฟซในยุค JDK 8
- วิวัฒนาการส่วนต่อประสานผ่านวิธีการขยายเสมือน
วิธีการคง Java Interface
Java Interface Static Method ตัวอย่างโค้ดวิธี static เทียบกับวิธีการเริ่มต้น
วิธีการแบบคงที่ส่วนต่อประสาน Java มีวิธีการคล้ายกับวิธีการเริ่มต้นยกเว้นว่าเราไม่สามารถแทนที่พวกเขาในชั้นเรียนการใช้งาน คุณลักษณะนี้ช่วยเราในการหลีกเลี่ยงผลลัพธ์ที่ไม่พึงประสงค์ในกรณีที่มีการนำไปปฏิบัติที่ไม่ดีในชั้นเรียนการใช้งาน ลองมาดูตัวอย่างนี้กัน
public interface MyData {
default void print(String str) {
if (!isNull(str))
System.out.println("MyData Print::" + str);
}
static boolean isNull(String str) {
System.out.println("Interface Null Check");
return str == null ? true : "".equals(str) ? true : false;
}
}
ตอนนี้เรามาดูคลาสการใช้งานที่มีเมธอด isNull () พร้อมกับการติดตั้งที่ไม่ดี
public class MyDataImpl implements MyData {
public boolean isNull(String str) {
System.out.println("Impl Null Check");
return str == null ? true : false;
}
public static void main(String args[]){
MyDataImpl obj = new MyDataImpl();
obj.print("");
obj.isNull("abc");
}
}
โปรดทราบว่า isNull (String str) เป็นวิธีการเรียนที่เรียบง่ายมันไม่ได้แทนที่วิธีการอินเตอร์เฟซ ตัวอย่างเช่นถ้าเราจะเพิ่มคำอธิบายประกอบ @Override ให้กับวิธี isNull () ก็จะส่งผลให้เกิดข้อผิดพลาดคอมไพเลอร์
ตอนนี้เมื่อเราจะเรียกใช้แอปพลิเคชันเราจะได้ผลลัพธ์ต่อไปนี้
อินเตอร์เฟส Null Check
Impl Null Check
หากเราสร้างวิธีการเชื่อมต่อจากคงที่ถึงค่าเริ่มต้นเราจะได้รับผลลัพธ์ต่อไปนี้
Impl Null Check
MyData พิมพ์ ::
Impl Null Check
วิธีการแบบคงที่ส่วนต่อประสาน Java จะปรากฏให้เห็นวิธีการติดต่อเท่านั้นถ้าเราลบวิธี isNull () จากชั้น MyDataImpl เราจะไม่สามารถใช้มันสำหรับวัตถุ MyDataImpl อย่างไรก็ตามเช่นเดียวกับวิธีการคงที่อื่น ๆ เราสามารถใช้วิธีคงที่ส่วนต่อประสานโดยใช้ชื่อชั้นเรียน ตัวอย่างเช่นคำสั่งที่ถูกต้องจะเป็น:
boolean result = MyData.isNull("abc");
จุดสำคัญเกี่ยวกับวิธีการคงที่ของอินเตอร์เฟส Java:
- วิธีการคงที่ของส่วนต่อประสาน Java เป็นส่วนหนึ่งของส่วนติดต่อเราไม่สามารถใช้มันสำหรับวัตถุคลาสการใช้งาน
- Java คงที่วิธีการอินเตอร์เฟซที่ดีสำหรับการให้วิธีการยูทิลิตี้เช่นการตรวจสอบโมฆะเรียงลำดับการเก็บรวบรวม ฯลฯ
- วิธีการคงที่ส่วนต่อประสาน Java ช่วยให้เราในการให้ความปลอดภัยโดยไม่อนุญาตให้ชั้นเรียนการใช้งานเพื่อแทนที่พวกเขา
- เราไม่สามารถกำหนดวิธีการคงที่ส่วนต่อประสานสำหรับวิธีการของคลาสวัตถุเราจะได้รับข้อผิดพลาดของคอมไพเลอร์เนื่องจาก“ วิธีการแบบคงที่นี้ไม่สามารถซ่อนวิธีอินสแตนซ์จากวัตถุ” นี่เป็นเพราะมันไม่ได้รับอนุญาตใน java เนื่องจาก Object เป็นคลาสพื้นฐานสำหรับทุกชั้นเรียนและเราไม่สามารถมีวิธีคงที่ระดับหนึ่งและวิธีการอินสแตนซ์อื่นที่มีลายเซ็นเดียวกัน
- เราสามารถใช้วิธีการคงที่ของอินเตอร์เฟส Java เพื่อลบคลาสยูทิลิตี้เช่นคอลเลกชันและย้ายวิธีการคงที่ทั้งหมดไปยังอินเทอร์เฟซที่เกี่ยวข้องซึ่งจะง่ายต่อการค้นหาและใช้งาน
Java ฟังก์ชั่นอินเทอร์เฟซ
ก่อนที่จะสรุปโพสต์ฉันต้องการที่จะให้คำแนะนำสั้น ๆ เกี่ยวกับฟังก์ชั่นการใช้งาน อินเทอร์เฟซที่มีวิธีการทางนามธรรมที่เรียกว่า Functional Interface
คำอธิบายประกอบใหม่@FunctionalInterface
ได้รับการแนะนำให้ทำเครื่องหมายส่วนต่อประสานเป็น Functional Interface @FunctionalInterface
คำอธิบายประกอบเป็นสิ่งอำนวยความสะดวกเพื่อหลีกเลี่ยงการเพิ่มโดยไม่ได้ตั้งใจของวิธีการที่เป็นนามธรรมในส่วนต่อประสานการทำงาน มันเป็นทางเลือก แต่เป็นแนวปฏิบัติที่ดีที่จะใช้
ส่วนต่อประสานการใช้งานนั้นเป็นคุณสมบัติที่รอคอยมานานและเป็นที่ต้องการอย่างมากของ Java 8 เพราะมันทำให้เราสามารถใช้แลมบ์ดานิพจน์เพื่อยกตัวอย่างพวกมัน แพ็กเกจใหม่ java.util.function ที่มีอินเตอร์เฟสการทำงานจำนวนมากถูกเพิ่มเพื่อจัดเตรียมชนิดเป้าหมายสำหรับนิพจน์แลมบ์ดาและการอ้างอิงเมธอด เราจะตรวจสอบอินเตอร์เฟสการใช้งานและการแสดงออกแลมบ์ดาในโพสต์ในอนาคต
ที่ตั้งทรัพยากร:
- การเปลี่ยนแปลงส่วนต่อประสานของ Java 8 - วิธีการคงที่, วิธีการเริ่มต้น