Javase8 ที่วางจำหน่ายในปี 2013 จะมีแผนเรียกว่าโครงการแลมบ์ดาซึ่งอธิบายไว้ในร่าง JSR-335 ในเดือนมิถุนายนปีนี้
JSR-335 แนะนำการปิดสู่ Java การปิดมีอยู่ในภาษายอดนิยมมากมายเช่น C ++, C# การปิดช่วยให้เราสามารถสร้างตัวชี้ฟังก์ชั่นและส่งผ่านเป็นพารามิเตอร์ ในบทความนี้เราจะดูลักษณะของ Java8 และแนะนำการแสดงออกของแลมบ์ดา และฉันจะพยายามใส่โปรแกรมตัวอย่างเพื่ออธิบายแนวคิดและไวยากรณ์บางอย่าง
ภาษาการเขียนโปรแกรม Java ช่วยให้เรามีแนวคิดของอินเทอร์เฟซและวิธีนามธรรมสามารถกำหนดได้ในอินเทอร์เฟซ อินเทอร์เฟซกำหนด API และหวังว่าผู้ใช้หรือซัพพลายเออร์จะใช้วิธีการเหล่านี้ หลายครั้งที่เราไม่ได้สร้างคลาสการใช้งานอิสระสำหรับอินเทอร์เฟซบางอย่าง
การใช้งานที่ไม่ระบุชื่อถูกนำมาใช้กันอย่างแพร่หลาย ฉากที่พบบ่อยที่สุดที่ใช้ในชั้นเรียนภายในที่ไม่ระบุชื่อคือตัวประมวลผลเหตุการณ์ ประการที่สองคลาสภายในที่ไม่ระบุชื่อมักใช้ในโปรแกรมหลายเธรด
เช่นเดียวกับที่เรากำลังพูดถึงคลาสที่ไม่ระบุชื่อคือการดำเนินการของอินเทอร์เฟซที่กำหนดของนินจา โดยปกติแล้วเราจะส่งผ่านวัตถุของคลาสการใช้งานนี้เป็นพารามิเตอร์ไปยังวิธีการจากนั้นวิธีนี้จะเรียกวิธีการคลาสการใช้งานไปยังคลาสการใช้งานภายใน ดังนั้นอินเทอร์เฟซนี้เรียกว่าอินเทอร์เฟซการโทรกลับ
แม้ว่าหมวดหมู่ที่ไม่ระบุชื่อจะถูกใช้ทุกที่ แต่ก็ยังมีปัญหามากมาย ปัญหาหลักแรกคือความซับซ้อน ชั้นเรียนเหล่านี้ทำให้ระดับของรหัสดูยุ่งเหยิงและซับซ้อนหรือที่เรียกว่าแนวดิ่ง ประการที่สองพวกเขาไม่สามารถเข้าถึงสมาชิกที่ไม่ใช่ผู้ชนะของคลาสบรรจุภัณฑ์ คำหลักของเรื่องนี้จะทำให้สับสนมาก หากคลาสที่ไม่ระบุชื่อมีชื่อสมาชิกเดียวกันกับคลาสบรรจุภัณฑ์ตัวแปรภายในจะครอบคลุมตัวแปรสมาชิกภายนอกในกรณีนี้สมาชิกภายนอกจะมองไม่เห็นภายในหมวดหมู่ที่ไม่ระบุชื่อ เพราะคำหลักนี้คุ้มค่ากับวัตถุที่ไม่ระบุชื่อมากกว่าวัตถุห่อหุ้มของเขา
โมฆะสาธารณะ anonymousexample () {String nonfinalVariable = "nonformal exmple"; Run Method Variable "; // ด้านล่างให้ข้อผิดพลาดในการรวบรวม //system.out.println ("-> "" " + nonfinalvariable); System.out.println ("-> "" ตัวแปร); println ("->" + this.variable);}}) ผลลัพธ์คือ:
-> เรียกใช้เมธอด Varial-> สมาชิกคลาสที่รันได้
ตัวอย่างนี้อธิบายถึงปัญหาที่ฉันกล่าวถึงข้างต้นและการแสดงออกของแลมบ์ดาเกือบจะแก้ปัญหาทั้งหมดที่เกิดจากชั้นเรียนภายในที่ไม่ระบุชื่อ ก่อนที่เราจะสำรวจนิพจน์แลมบ์ดาเพิ่มเติมลองมาดูอินเตอร์เฟสที่ใช้งานได้
อินเทอร์เฟซการทำงาน
อินเทอร์เฟซการทำงานเป็นอินเทอร์เฟซที่มีเพียงวิธีเดียวเท่านั้นซึ่งแสดงถึงวิธีการนี้
เพียงหนึ่งเดียวในคำจำกัดความข้างต้นไม่ใช่เรื่องง่าย ฉันไม่เข้าใจย่อหน้านี้
ตัวอย่างต่อไปนี้แสดงให้เห็นถึงวิธีการทำความเข้าใจแนวคิดของอินเทอร์เฟซที่ใช้งานได้อย่างชัดเจน
อินเตอร์เฟส runnable {void run ();} // functionalinterface foo {boolean เท่ากับ (Object obj);} // ไม่ทำงาน; ฟังก์ชั่น; BAR มีการหาวิธีการที่ไม่ใช่วัตถุประสงค์ ไม่ใช้งานได้; ลายเซ็นเดียวกันอินเทอร์เฟซการโทรกลับส่วนใหญ่เป็นอินเตอร์เฟสที่ใช้งานได้ ตัวอย่างเช่น runnable, callable, comparator ฯลฯ ก่อนหน้านี้เรียกว่า SAM (วิธีนามธรรมเดียว)
การแสดงออกของแลมบ์ดา
ดังที่เราได้กล่าวไปแล้วปัญหาหลักของหมวดหมู่ที่ไม่ระบุชื่อคือระดับของรหัสดูยุ่งเหยิงนั่นคือการแสดงออกในแนวดิ่ง การแสดงออกของแลมบ์ดาดูเหมือนวิธีการ พวกเขามีรายการพารามิเตอร์อย่างเป็นทางการและการปิดกั้นพารามิเตอร์เหล่านี้
(สตริง s) -> s.lengh; () -> 43;
ตัวอย่างข้างต้นหมายความว่านิพจน์แรกได้รับตัวแปรสตริงเป็นพารามิเตอร์จากนั้นส่งคืนความยาวของสตริง อันที่สองไม่มีพารามิเตอร์ใด ๆ และส่งคืน 43 ในที่สุดคนที่สามยอมรับสองจำนวนเต็ม x และ y และกลับสู่ความสงบสุข
หลังจากอ่านคำจำนวนมากในที่สุดฉันก็สามารถยกตัวอย่างการแสดงออกของแลมบ์ดาครั้งแรก
คลาสสาธารณะ FirstLambdaexpression {public String variable = "ตัวแปรระดับคลาส"; void public static main (string [] arg) {ใหม่ FirstLambdaexpression () .lambdaexpression ();} โมฆะสาธารณะ Lambdaexpression () String nonfinalVariable = "นี่ไม่ใช่ตัวแปรสุดท้าย"; ; System.out.println ("->" "" " ผลลัพธ์คือ:
-> เมธอดตัวแปรโลคัล-> ตัวแปรระดับคลาส
คุณสามารถเปรียบเทียบความแตกต่างระหว่างการใช้การแสดงออกของแลมบ์ดาและคลาสภายในที่ไม่ระบุชื่อ เราสามารถพูดได้อย่างชัดเจนว่าการเขียนหมวดหมู่ที่ไม่ระบุชื่อโดยใช้นิพจน์แลมบ์ดาแก้ปัญหาของการมองเห็นตัวแปร คุณสามารถดูคำอธิบายประกอบในรหัส
ไวยากรณ์ Lambda Expression ทั่วไปรวมถึงรายการพารามิเตอร์คำหลักของลูกศร "->" เป็นร่างกายหลัก เรื่องอาจเป็นนิพจน์ (คำสั่งหนึ่งบรรทัด) หรือประโยคหลายบรรทัด หากเป็นนิพจน์มันจะถูกคำนวณและส่งคืน ทำลายและดำเนินการต่อสามารถใช้งานได้ภายในวัฏจักรเท่านั้น
ทำไมต้องเลือกแบบฟอร์มไวยากรณ์พิเศษนี้เพราะปัจจุบันสไตล์นี้มักจะอยู่ใน C# และ Scala ซึ่งเป็นงานเขียนทั่วไปของการแสดงออกของแลมบ์ดา การออกแบบไวยากรณ์นี้โดยทั่วไปช่วยแก้ความซับซ้อนของประเภทที่ไม่ระบุชื่อ แต่ในเวลาเดียวกันเขาก็มีความยืดหยุ่นมากเช่นกัน ผลของการแสดงออกเป็นค่าตอบแทนของเขาเอง ความยืดหยุ่นนี้สามารถทำให้รหัสง่ายขึ้น
การแสดงออกของแลมบ์ดาใช้เป็นแบบไม่ระบุชื่อดังนั้นพวกเขาจึงสามารถใช้อย่างยืดหยุ่นในโมดูลอื่น ๆ หรือการแสดงออกของแลมบ์ดาอื่น ๆ (นิพจน์แลมบ์ดาซ้อน)
// Lambda Exposition ถูกล้อมรอบด้วยพารามิเตอร์วิธีการ/ประเภทอินเตอร์เฟส/target เป็นประเภทพารามิเตอร์วิธีการ (() -> {system.out.println ("ทำงานในเธรดที่แตกต่างกัน");});
หากคุณดูนิพจน์แลมบ์ดาอย่างใกล้ชิดคุณจะเห็นว่าประเภทอินเทอร์เฟซเป้าหมายไม่ได้เป็นส่วนหนึ่งของนิพจน์ คอมไพเลอร์ช่วยอนุมานประเภทและสภาพแวดล้อมโดยรอบของการแสดงออกของแลมบ์ดา
นิพจน์แลมบ์ดาต้องมีประเภทเป้าหมายและสามารถปรับให้เข้ากับประเภทเป้าหมายที่เป็นไปได้ เมื่อประเภทเป้าหมายเป็นอินเทอร์เฟซเงื่อนไขต่อไปนี้จะต้องตรงกับการรวบรวมอย่างถูกต้อง:
เนื่องจากคอมไพเลอร์สามารถรู้ประเภทพารามิเตอร์และหมายเลขผ่านคำสั่งประเภทเป้าหมายในนิพจน์แลมบ์ดาจึงสามารถละเว้นการประกาศประเภทพารามิเตอร์ได้
ตัวเปรียบเทียบ c = (s1, s2) -> s1.comparetoignorecase (S2);
ยิ่งไปกว่านั้นหากวิธีการที่ประกาศในประเภทเป้าหมายได้รับเพียงพารามิเตอร์เดียวเท่านั้น (หลายครั้งเป็นกรณี) วงเล็บขนาดเล็กของพารามิเตอร์สามารถเขียนได้เช่น:
ActionListenr ListenR = Event-> event.tHen ();
คำถามที่ชัดเจนมากมาทำไมแลมบ์ดาแสดงถึงชื่อวิธีที่ระบุ?
คำตอบคือ: Lambda Expression สามารถใช้สำหรับอินเตอร์เฟสการทำงานเท่านั้นในขณะที่อินเตอร์เฟสการทำงานมีเพียงวิธีเดียวเท่านั้น
เมื่อเรากำหนดอินเทอร์เฟซที่ใช้งานได้เพื่อสร้างนิพจน์แลมบ์ดาคอมไพเลอร์สามารถรับรู้ลายเซ็นของอินเทอร์เฟซการทำงานของกฎหมายจีนและตรวจสอบว่านิพจน์ที่กำหนดตรงกับหรือไม่
ไวยากรณ์ที่ยืดหยุ่นนี้ช่วยให้เราหลีกเลี่ยงการใช้ privem แนวตั้งที่ไม่ระบุชื่อและจะไม่นำ privem แนวนอน (ประโยคหนึ่งทางยาวมาก)
ไวยากรณ์การแสดงออกของแลมบ์ดาเกี่ยวข้องกับบริบท แต่นี่ไม่ใช่ครั้งแรก ผู้ประกอบการไดมอนด์ที่เพิ่มโดย Java SE 7 ยังมีแนวคิดนี้ซึ่งอนุมานตามบริบท
เป็นโมฆะ Invoke (runnable r) {r.run ()} void future revoke (callable r) {return c.compute ()} // ด้านบนเป็นสองวิธี onal interfacefuture s = revoke () -> "เสร็จสิ้น"); / คำเรียกใดจะถูกเรียก?
คำตอบสำหรับคำถามข้างต้นคือการโทรหาวิธีการรับพารามิเตอร์ที่เรียกได้ ในกรณีนี้คอมไพเลอร์จะได้รับการแก้ไขผ่านการโหลดของประเภทพารามิเตอร์ที่แตกต่างกัน เมื่อมีวิธีการโหลดมากกว่าหนึ่งวิธีคอมไพเลอร์จะตรวจสอบความเข้ากันได้ของนิพจน์แลมบ์ดาและประเภทเป้าหมายที่สอดคล้องกัน พูดง่ายๆคือเมธอด Invoke ด้านบนคาดว่าจะกลับมา แต่มีเพียงวิธีการเรียกใช้เดียวเท่านั้นที่มีค่าส่งคืน
การแสดงออกของแลมบ์ดาสามารถแปลงเป็นประเภทเป้าหมายที่ระบุได้อย่างชัดเจนตราบใดที่พวกเขาเข้ากันได้กับประเภทที่สอดคล้องกัน เมื่อดูที่โปรแกรมต่อไปนี้ฉันใช้ callable สามประเภทและพวกเขาทั้งหมดแปลงเป็นประเภทคลาส
คลาสสาธารณะ FirstWithLambDaexpressions {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {listl = arrayslist (callial)-> "callable 1", (โทรสามารถ) ()-> "callable 2", (เรียกได้) (เรียกได้))-> "callable 3"); ) {e1.PrintStackTrace ();} E.Shutdown ();} โมฆะสาธารณะ Dumplist (รายการ) พ่น InterptException, ExecutionExcepti บน {สำหรับ (อนาคตในอนาคต: รายการ) {System.out.println (future.get.get ()); }}}ดังที่เราได้กล่าวถึงก่อนหน้านี้หมวดหมู่ที่ไม่ระบุชื่อไม่สามารถเข้าถึงตัวแปรที่ไม่ใช่รอบรองชนะเลิศในสภาพแวดล้อมโดยรอบ แต่ไม่มีขีด จำกัด ดังกล่าวในการแสดงออกของแลมบ์ดา
ในปัจจุบันอินเทอร์เฟซการทำงานที่กำหนดนั้นใช้ได้เฉพาะกับอินเทอร์เฟซ ฉันพยายามสร้างนิพจน์แลมบ์ดาของวิธีนามธรรมเพียงวิธีเดียว แต่มีข้อผิดพลาดในการรวบรวม จากข้อมูลของ JSR -335 การแสดงออกของแลมบ์ดาเวอร์ชันในอนาคตอาจรองรับคลาสการทำงาน
วิธีการอ้างอิง
วิธีการอ้างอิงเป็นวิธีการอ้างอิงโดยไม่ต้องโทร
การแสดงออกของแลมบ์ดาช่วยให้เราสามารถกำหนดวิธีที่ไม่ระบุชื่อและใช้เป็นอินสแตนซ์ของอินเตอร์เฟสการทำงาน วิธีการนั้นคล้ายคลึงกับการแสดงออกของแลมบ์ดา
ระบบ :: getProperty "abc" :: playstring :: specialsuper :: tostringarraylist :: ใหม่
คำสั่งข้างต้นแสดงไวยากรณ์ทั่วไปของวิธีการและการอ้างอิงไปยังตัวสร้าง ที่นี่เราได้เห็นตัวละครในการดำเนินงานใหม่ ":::: Double Colon) ฉันไม่รู้ชื่อที่แน่นอนในฐานะผู้ดำเนินการนี้ แต่ JSR หมายถึงมันเป็นตัวแยกและหน้า Wikipedia หมายถึงการดำเนินการวิเคราะห์ขอบเขต . เป็นข้อมูลอ้างอิงภายในช่วงของการสอนนี้เราจะใช้มันเป็นผู้แบ่งแยกดินแดน
การอ้างอิงเป้าหมายหรือตัวรับสัญญาณถูกวางไว้ด้านหลังผู้ให้บริการและตัวคั่น รูปแบบการแสดงออกที่สามารถอ้างถึงวิธีการ ในคำสั่งสุดท้ายชื่อของวิธีการคือ "ใหม่" นิพจน์นี้เสนอราคาวิธีโครงสร้างของคลาส ArrayList (อ้างอิงถึงตัวสร้างในส่วนถัดไป)
ก่อนที่คุณจะเข้าใจสิ่งนี้ฉันต้องการให้คุณเห็นความแข็งแกร่งของวิธีการที่ยกมา
นำเข้า java.util.arrays; นำเข้า java.util.list; = {พนักงานใหม่ ("Nick"), พนักงานใหม่ ("Robin"), พนักงานใหม่ ("Josh"), พนักงานใหม่ ("Andy"), พนักงานใหม่ ("Mark")}; ก่อนการเรียงลำดับ: "); dumpemployee (พนักงาน); array.sort (พนักงานพนักงาน :: myCompare); system.out.println (" หลังจากเรียงลำดับ: "); mployees);] พนักงาน) {สำหรับ (พนักงาน EMP: อาร์เรย์ Aslist (พนักงาน)) {System.out.print (emp.name+",");} system.out.println (); (พนักงาน EMP1, EMP2) {return emp1.name.compareto (emp2.name);}} ผลลัพธ์คือ:
ก่อนเรียงลำดับ: Nick, Robin, Josh, Andy, Mark, After Sort: Andy, Josh, Mark, Nick, Robin,
ผลลัพธ์ไม่พิเศษ วิธีการคงที่ MyCompare ได้รับวัตถุพนักงานสองวัตถุและส่งคืนชื่อของพวกเขาเพื่อเปรียบเทียบ
ในวิธีการหลักฉันสร้างอาร์เรย์ที่แตกต่างกันของพนักงานและส่งผ่านไปยังอาร์เรย์วิธีการเพื่ออ้างอิงไปยังอาร์เรย์ของนิพจน์ (พนักงาน :: myCompare)
เดี๋ยวก่อนถ้าเราดู Javadoc คุณจะพบว่าพารามิเตอร์ที่สองของวิธีการเรียงลำดับคือประเภท Corarator แต่เราผ่านการอ้างอิงวิธีการคงที่ของพนักงาน ปัญหาสำคัญอยู่ที่นี่
ลองมาดูกันว่าทำไม array.sort วิธีการคาดว่าอินสแตนซ์ของตัวเปรียบเทียบและตัวเปรียบเทียบนี้เป็นอินเทอร์เฟซที่ใช้งานได้ซึ่งหมายความว่าเขามีวิธีเดียวเท่านั้นนั่นคือเปรียบเทียบ ที่นี่เรายังส่งต่อการแสดงออกของแลมบ์ดาอย่างร้ายกาจซึ่งให้การใช้วิธีการ compaare ในนิพจน์นี้ แต่ในตัวเราชั้นเรียนพนักงานของเรามีวิธีการเปรียบเทียบอยู่แล้ว เป็นเพียงว่าชื่อของพวกเขาแตกต่างกัน
เมื่อมีหลายวิธีที่มีชื่อเดียวกันคอมไพเลอร์จะเลือกการจับคู่ที่ดีที่สุดตามประเภทเป้าหมาย เพื่อทำความเข้าใจให้ดูตัวอย่าง:
สาธารณะ int myCompare (พนักงาน EMP1, พนักงาน EMP2) {return emp1.name.compareto (emp2.name);} // วิธีอื่นที่มีชื่อเดียวกันกับ {{) {{) {{return int1.compareto (int2);} ฉันสร้างอาร์เรย์ที่แตกต่างกันสองแบบสำหรับการเรียงลำดับ
พนักงาน [] พนักงาน = {พนักงานใหม่ ("Nick"), พนักงานใหม่ ("Robin"), พนักงานใหม่ ("Josh"), พนักงานใหม่ ("Andy"), พนักงานใหม่ ("Mark")}; ins = {1, 4, 8, 2, 3, 8, 6}; ตอนนี้ฉันเรียกใช้รหัสสองบรรทัดต่อไปนี้
Arrays.sort (พนักงานพนักงาน :: MyCompare);
ที่นี่วิธีการอ้างอิงในรหัสสองบรรทัดเหมือนกัน (พนักงาน :: MyCompare)
อย่าเข้าใจผิดด้วยวิธีการคงที่เรายังสามารถสร้างการอ้างอิงถึงวิธีการตัวอย่าง สำหรับวิธีการคงที่เราใช้ชื่อคลาส :: ชื่อวิธีการอ้างอิงวิธีการเขียน
ตัวอย่างข้างต้นค่อนข้างดี แต่เราไม่จำเป็นต้องเขียนวิธีการเปรียบเทียบจำนวนเต็มเนื่องจากจำนวนเต็มได้ดำเนินการเทียบเคียงได้และให้วิธีการเปรียบเทียบการใช้งาน ดังนั้นเราจึงใช้บรรทัดต่อไปนี้โดยตรง:
arrays.sort (ints, จำนวนเต็ม :: compereto);
เห็นสิ่งนี้คุณรู้สึกสับสนเล็กน้อยหรือไม่? เลขที่? จากนั้นให้ฉันสับสนที่นี่ วิธีการสมาชิกมีการอ้างอิง :: มันควรจะเป็นวัตถุมาก่อน แต่ทำไมประโยคที่นี่จึงถูกต้องตามกฎหมาย
คำตอบคือ: คำสั่งประเภทนี้อนุญาตให้ใช้ในบางประเภทเฉพาะ จำนวนเต็มเป็นชนิดข้อมูลและสำหรับประเภทข้อมูลคำสั่งนี้ได้รับอนุญาต
หากเราเปลี่ยนวิธีการของพนักงาน MyCompare เป็นแบบไม่คงที่จากนั้นใช้: พนักงาน :: MyCompare จะมีข้อผิดพลาดในการรวบรวม: ไม่พบวิธีที่เหมาะสม
การอ้างอิงวิธีการสร้างสรรค์
การอ้างอิงตัวสร้างถูกใช้เป็นคลาสที่อ้างอิงตัวสร้างโดยไม่ได้ระบุสถาบัน
การอ้างอิงวิธีการสร้างสรรค์เป็นคุณสมบัติใหม่ของ Javase 8 เราสามารถสร้างการอ้างอิงไปยังวิธีการสร้างสรรค์และส่งผ่านเป็นพารามิเตอร์ไปยังประเภทเป้าหมาย
เมื่อเราใช้มันเพื่ออ้างอิงเราอ้างวิธีหนึ่งที่มีอยู่เพื่อใช้ ในทำนองเดียวกันเมื่อใช้การอ้างอิงวิธีการสร้างสรรค์เราจะสร้างการอ้างอิงถึงวิธีการสร้างสรรค์ที่มีอยู่
ในส่วนก่อนหน้านี้เราได้เห็นชื่อไวยากรณ์ที่อ้างอิงโดย Constructor :: ใหม่ซึ่งดูเหมือนการอ้างอิงวิธีการ การอ้างอิงถึงวิธีที่สร้างขึ้นนี้สามารถกำหนดให้กับอินสแตนซ์ของอินเตอร์เฟสการทำงานของเป้าหมาย อาจมีตัวสร้างหลายตัวในชั้นเรียน
สำหรับฉันมันเป็นเรื่องยากที่จะเขียนวิธีการสร้างสรรค์ครั้งแรก ในท้ายที่สุดฉันใช้เวลาทำงานหนักมานานและในที่สุด "อ่าฉันพบ ... " ดูขั้นตอนต่อไปนี้
Public Class ConstructorReferences {public static void main (string [] ar) {myInterface ใน = myclass :: new; } ผลลัพธ์คือ:
-> com.myclass@34e5307e
สิ่งนี้ดูน่าอัศจรรย์เล็กน้อยใช่ไหม
ตัวอย่างนี้กระตุ้นปัญหาอื่นในใจของฉัน: วิธีการสร้างอินสแตนซ์วิธีการสร้างสรรค์ด้วยพารามิเตอร์? ดูขั้นตอนด้านล่าง:
Public Class ConstructorReferences {โมฆะสาธารณะคงที่หลัก (String [] AR) {EmlpoyeProder Provider = Employee :: New; ; อายุ) {this.name = name; ผลลัพธ์คือ:
-> ชื่อพนักงาน: John-> อายุพนักงาน: 30
ก่อนที่จะอ่านบทความนี้มาดูคุณสมบัติที่ยอดเยี่ยมที่สุดในวิธี Javase8-Default
วิธีการเริ่มต้น
Javase8 จะแนะนำแนวคิดที่เรียกว่าวิธีเริ่มต้น อินเทอร์เฟซรุ่น Java รุ่นแรกมีอินเทอร์เฟซที่เข้มงวดมาก ในเวอร์ชัน Java ที่กำลังจะมาถึงการใช้งานเริ่มต้นของวิธีการในอินเทอร์เฟซได้รับอนุญาต ดูไร้สาระมากนักดูสิ่งต่อไปนี้:
ระดับสาธารณะเริ่มต้น {public static void main (string [] ar) {อินสแตนซ์ normalInterface = normalinterfaceimpl (); System.out.println ("-> mydefaultMethod");}} คลาส NormalInterfaceimpl impremelemerInterface {@Override สาธารณะโมฆะ mynormalmethod () {) system.out.println ("-> mynormalmethod"); ผลลัพธ์คือ:
-> mydefaultmethod
อินเทอร์เฟซข้างต้นประกาศสองวิธี แต่คลาสการใช้งานของอินเทอร์เฟซนี้จะตระหนักถึงหนึ่งในนั้นเท่านั้นเนื่องจาก MyDefaultMethod ใช้ตัวดัดแปลงเริ่มต้นและมีบล็อกวิธีการสำหรับการใช้งานเริ่มต้น กฎการโหลดหนักของจีเอ็มยังคงมีผลอยู่ที่นี่ หากคลาสการใช้งานใช้วิธีการในอินเทอร์เฟซมันจะเป็นวิธีการในคลาสการโทรเมื่อการโทรมิฉะนั้นการใช้งานเริ่มต้นจะถูกเรียก
อินเทอร์เฟซของอินเทอร์เฟซพาเรนต์แบบรวมสามารถเพิ่มเปลี่ยนและลบการใช้งานเริ่มต้นของอินเทอร์เฟซหลัก
อินเทอร์เฟซ ParentInterface {Void เริ่มต้น (); -> เริ่มแรก ");} เป็นโมฆะ retialyDefault (); // ตอนนี้เป็นวิธีปกติ} ในตัวอย่างนี้ ParentInterface กำหนดวิธีการสองวิธีเป็นเรื่องปกติและอีกวิธีหนึ่งถูกนำมาใช้โดยค่าเริ่มต้น
ลองนึกภาพคลาสที่สืบทอดมาจากคลาส C ตระหนักถึงอินเตอร์เฟส I และ C มีวิธีการและวิธีการที่ให้วิธีการเริ่มต้นซึ่งให้วิธีการเริ่มต้นเข้ากันได้ ในกรณีนี้วิธีการใน C จะให้ความสำคัญกับวิธีการเริ่มต้นใน I และแม้แต่วิธีการใน C ยังคงเป็นลำดับความสำคัญเมื่อวิธีการเป็นนามธรรม
คลาสสาธารณะ defaultMethods {โมฆะสาธารณะคงที่หลัก (สตริง [] ar) {interfaxe impl = ใหม่ normalInterfaceimpl (); impl.defaultMethod (); ;}} อินเตอร์เฟส interfaxe {โมฆะสาธารณะ defaultMethod () ค่าเริ่มต้น {system.out.println ("-> interfaxe"); ผลลัพธ์คือ:
-> parentclass
ตัวอย่างที่สองคือคลาสของฉันได้ใช้อินเทอร์เฟซที่แตกต่างกันสองแบบ แต่อินเทอร์เฟซทั้งสองทั้งสองให้คำสั่งเดียวกันด้วยวิธีการใช้งานเริ่มต้นที่เหมือนกัน ในกรณีนี้คอมไพเลอร์จะไม่สามารถหาสิ่งที่เกิดขึ้นได้ สามารถทำได้ในวิธีต่อไปนี้
คลาสสาธารณะ defaultMethods {โมฆะสาธารณะคงที่หลัก (สตริง [] ar) {firstinterface impl = normalinterfampl (); );}} อินเตอร์เฟส secondInterface {โมฆะสาธารณะ defaultMethod () ค่าเริ่มต้น {system.out.println ("-> secondInterface"); ผลลัพธ์คือ:
-> SecondInterface
ตอนนี้เราได้อ่านการแนะนำการปิด Java ในบทความนี้เราได้ติดต่อกับอินเทอร์เฟซที่ใช้งานได้และการปิด Java ซึ่งเข้าใจการแสดงออกของแลมบ์ดาของ Java การอ้างอิงวิธีการและการอ้างอิงตัวสร้าง และเรายังเขียนตัวอย่าง Hello World ของการแสดงออกของแลมบ์ดา
Javase8 กำลังจะมาเร็ว ๆ นี้