เรายกระดับนามธรรมได้หรือไม่?


573

ในระหว่างการสัมภาษณ์ของฉันฉันถูกถามว่า "ถ้าเราสามารถสร้างคลาสนามธรรมได้หรือไม่"

คำตอบของฉันคือ "ไม่เราไม่สามารถทำได้" แต่ผู้สัมภาษณ์บอกฉันว่า "ผิดเราทำได้"

ฉันโต้เถียงเล็กน้อยเกี่ยวกับเรื่องนี้ จากนั้นเขาบอกให้ฉันลองทำเองที่บ้าน

abstract class my {
    public void mymethod() {
        System.out.print("Abstract");
    }
}

class poly {
    public static void main(String a[]) {
        my m = new my() {};
        m.mymethod();
    }
}

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


2
แม้ว่าจะมีเพียงที่เกี่ยวข้องเล็กน้อยหนึ่งอาจจะสามารถยกตัวอย่างระดับนามธรรมใน C ++: ถ้าคุณได้รับมาชั้นไม่ใช่นามธรรมBจากนามธรรมหนึ่งA, ในส่วนของการก่อสร้างของBอินสแตนซ์ซึ่งประกอบด้วยการทำงานของตัวสร้างประเภทรันไทม์ของวัตถุที่เป็นจริงA Aชั่วคราวเท่านั้น
Vlad

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

3
หรืออาจเป็นผู้สัมภาษณ์ต้องการตรวจสอบความมั่นใจของคุณเกี่ยวกับคำพูดของคุณกับสิ่งที่เขาเสนอ!
ซิด

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

2
นี่ไม่ใช่การตอบคำถาม แต่เป็นการสัมภาษณ์งานใช่ไหม ดังนั้นถ้า Java หรือ C ++ อนุญาตให้สร้างคลาสนามธรรมได้ คุณจะไม่ทำเพราะไม่ใช่สิ่งที่ฉลาดที่จะทำ ใน Objective-C คลาสนามธรรมเป็นเพียงนามธรรมโดยการประชุมและการสร้างอินสแตนซ์เป็นข้อบกพร่อง
gnasher729

คำตอบ:


722

ที่นี่ฉันกำลังสร้างตัวอย่างของชั้นเรียนของฉัน

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

พฤติกรรมนี้มีการระบุไว้อย่างชัดเจนในJLS - ส่วน # 15.9.1 : -

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

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

เน้นการขุด

นอกจากนี้ในJLS - มาตรา # 12.5คุณสามารถอ่านข้อมูลเกี่ยวกับขั้นตอนการสร้างวัตถุ ฉันจะอ้างอิงหนึ่งข้อความจากที่นี่: -

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

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

คุณสามารถอ่านเกี่ยวกับขั้นตอนทั้งหมดในลิงค์ที่ฉันให้ไว้


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

My.java:

abstract class My {
    public void myMethod() {
        System.out.print("Abstract");
    }
}

Poly.java:

class Poly extends My {
    public static void main(String a[]) {
        My m = new My() {};
        m.myMethod();
    }
}

ในตอนนี้ให้รวบรวมทั้งซอร์สไฟล์ของคุณ:

javac My.java Poly.java

ตอนนี้ในไดเรกทอรีที่คุณรวบรวมซอร์สโค้ดคุณจะเห็นไฟล์คลาสต่อไปนี้:

My.class
Poly$1.class  // Class file corresponding to anonymous subclass
Poly.class

ดูคลาสนั้น - Poly$1.class. มันเป็นไฟล์คลาสที่สร้างโดยคอมไพเลอร์ที่สอดคล้องกับคลาสย่อยที่ไม่ระบุชื่อที่คุณสร้างอินสแตนซ์โดยใช้รหัสด้านล่าง:

new My() {};

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

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

Poly$1.class, Poly$2.class, Poly$3.class, ... so on

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


172
@coders คำตอบที่แน่นอนคือ: - คุณไม่สามารถสร้างคลาสนามธรรมของคุณได้อย่างไรก็ตามคุณสามารถสร้างคลาสย่อยที่เป็นรูปธรรมของคลาสนามธรรมของคุณได้
Rohit Jain

16
ในหนึ่งบรรทัดคุณสามารถพูดได้: - คุณไม่สามารถยกตัวอย่างคลาสนามธรรมได้ นั่นคือจุดประสงค์ของคลาสนามธรรม
ราหุล Tripathi

66
ดูเหมือนว่าผู้สัมภาษณ์จะลงทุนในคำตอบของเขามากกว่าที่คุณเป็น ...
Neil T.

7
ตามความคิดเห็นอื่น (พร้อมการอ้างอิง JLS ) "วัตถุได้รับการกล่าวถึงว่าเป็นตัวอย่างของคลาสและซูเปอร์คลาสทั้งหมดของคลาส" - ดังนั้นเราจริง ๆ แล้วเราไม่ได้สร้างอินสแตนซ์ของคลาสนามธรรมที่นี่จริงหรือ คือการยกระดับนามธรรม?
arshajii

6
@ARS ผมบอกว่ามีความแตกต่างระหว่างการเป็นและinstance of instantiatingคุณยกตัวอย่างชั้นเดียวเท่านั้นในขณะที่วัตถุที่คุณสร้างสามารถเป็นอินสแตนซ์ของหลายคลาสได้เนื่องจากการสืบทอด
Simon Forsberg

89

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

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


10
พูดอย่างเคร่งครัด superclass นามธรรมไม่ได้ยกตัวอย่าง มันเป็นนวกรรมิกเรียกว่าเริ่มต้นตัวแปรอินสแตนซ์
การรับรู้

4
ใช่มันคือ: subclassInstance instanceof SuperClassจะคืนค่าจริงดังนั้นวัตถุจึงเป็นอินสแตนซ์ของซูเปอร์คลาสซึ่งหมายความว่าซูเปอร์คลาสได้รับการติดตั้งแล้ว แต่นั่นเป็นเพียงการพูดถึงความหมาย
JB Nizet

5
อาจเป็นความหมายแน่นอน Java กำหนดinstantiationในแง่ของการสร้างวัตถุผ่านคำหลักใหม่ (ซึ่ง ofc คุณไม่สามารถทำกับคลาสนามธรรม) แต่แน่นอนคลาสย่อยคอนกรีตจะรายงานอย่างถูกต้องว่ามันเป็นตัวอย่างของสมาชิกทุกคนในลำดับชั้นของผู้ปกครอง
การรับรู้

11
ย่อหน้าที่ 4.12.6 ของ JLSกล่าวว่า: "วัตถุได้รับการกล่าวถึงว่าเป็นตัวอย่างของคลาสและซูเปอร์คลาสทั้งหมดของคลาสนั้น"
JB Nizet

85

= my() {};หมายความว่ามีการดำเนินการที่ไม่ระบุชื่อไม่ instantiation = my()ที่เรียบง่ายของวัตถุที่ควรจะได้รับ: คุณไม่สามารถยกตัวอย่างคลาสนามธรรมได้


30

เพียงสังเกตคุณสามารถ:

  1. polyขยายทำไมmy? นี่ไร้ประโยชน์ ...
  2. ผลลัพธ์ของการรวบรวมคืออะไร? สามไฟล์: my.class, poly.classและpoly$1.class
  3. ถ้าเราสามารถสร้างอินสแตนซ์ของคลาสนามธรรมได้เราสามารถอินสแตนซ์ของอินเทอร์เฟซด้วย ... แปลก ...


เรายกระดับนามธรรมได้หรือไม่?

ไม่เราทำไม่ได้ สิ่งที่เราสามารถทำได้คือสร้างคลาสนิรนาม (นั่นคือไฟล์ที่สาม) และยกตัวอย่าง


สิ่งที่เกี่ยวกับการสร้างคลาส super หรือไม่?

คลาสที่เป็นนามธรรมไม่ได้ยกตัวอย่างโดยเราแต่ใช้โดยจาวา

แก้ไข: ขอให้เขาทดสอบสิ่งนี้

public static final void main(final String[] args) {
    final my m1 = new my() {
    };
    final my m2 = new my() {
    };
    System.out.println(m1 == m2);

    System.out.println(m1.getClass().toString());
    System.out.println(m2.getClass().toString());

}

ผลลัพธ์คือ:

false
class my$1
class my$2

+1 สำหรับการสังเกต 3: เช่นเราสามารถทำได้Serializable s = new Serializable() {};(ซึ่งค่อนข้างไร้ประโยชน์) และหากติดแท็กลงบนโค้ดของคุณจะให้class my$3(หรืออะไรก็ตามที่อยู่ในชั้นเรียนและหมายเลข)
Reinstate Monica - notmaynard

18

คุณสามารถตอบได้ง่ายๆในบรรทัดเดียว

ไม่คุณไม่สามารถใช้คลาสนามธรรมได้

แต่ผู้สัมภาษณ์ยังไม่เห็นด้วยคุณสามารถบอกเขาได้

สิ่งที่คุณทำได้คือคุณสามารถสร้างคลาสที่ไม่เปิดเผยตัวตน

และตามคลาสนิรนามคลาสที่ประกาศและอินสแตนซ์ที่สถานที่ / บรรทัดเดียวกัน

ดังนั้นอาจเป็นไปได้ว่าผู้สัมภาษณ์สนใจที่จะตรวจสอบระดับความเชื่อมั่นของคุณและเท่าไหร่ที่คุณรู้เกี่ยวกับ OOP


17

ส่วนทางเทคนิคได้รับการคุ้มครองอย่างดีในคำตอบอื่น ๆ และส่วนใหญ่จะลงท้ายด้วย:
"เขาผิดเขาไม่รู้อะไรเลยขอให้เขาเข้าร่วมดังนั้นและเคลียร์ทั้งหมด :)"

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

PS: ฉันไม่รู้ว่าทำไม แต่ฉันมีความรู้สึกว่าผู้สัมภาษณ์ได้อ่านโพสต์นี้


13

คลาสนามธรรมไม่สามารถสร้างอินสแตนซ์ได้ แต่สามารถแบ่งเป็นคลาสย่อยได้ ดูลิงค์นี้

ตัวอย่างที่ดีที่สุดคือ

แม้ว่าคลาส Calender จะมีเมธอดนามธรรม getInstance ()แต่เมื่อคุณพูดCalendar calc=Calendar.getInstance();

calc หมายถึงอินสแตนซ์คลาสของคลาส GregorianCalendar เป็น "GregorianCalendar ขยายปฏิทิน "

Infact annonymous Inner type ช่วยให้คุณสร้างคลาสย่อยที่ไม่มีชื่อของคลาสนามธรรมและอินสแตนซ์ของสิ่งนี้


11

คำตอบทางเทคนิค

คลาสนามธรรมไม่สามารถสร้างอินสแตนซ์ได้นี่คือการกำหนดและออกแบบ

จาก JLS บทที่ 8 คลาส:

คลาสที่มีชื่ออาจถูกประกาศเป็นนามธรรม (§8.1.1.1) และจะต้องประกาศนามธรรมถ้ามันถูกนำไปใช้อย่างไม่สมบูรณ์ คลาสนั้นไม่สามารถสร้างอินสแตนซ์ได้ แต่สามารถขยายได้โดยคลาสย่อย

จาก JSE 6 java doc สำหรับ Classes.newInstance ():

InstantiationException - ถ้าคลาสนี้แทนคลาสนามธรรม, อินเตอร์เฟส, คลาสอาเรย์, ชนิดดั้งเดิมหรือเป็นโมฆะ หรือถ้าชั้นไม่มีตัวสร้าง nullary; หรือหากการสร้างอินสแตนซ์ล้มเหลวด้วยเหตุผลอื่น

แน่นอนว่าคุณสามารถยกระดับคลาสย่อยคอนกรีตของคลาสนามธรรม (รวมถึงคลาสย่อยที่ไม่ระบุชื่อ) และดำเนินการ typecast ของการอ้างอิงวัตถุกับประเภทนามธรรม

มุมมองที่แตกต่างในเรื่องนี้ - การเล่นเป็นทีมและความฉลาดทางสังคม:

ความเข้าใจผิดทางเทคนิคประเภทนี้เกิดขึ้นบ่อยครั้งในโลกแห่งความจริงเมื่อเราจัดการกับเทคโนโลยีที่ซับซ้อนและข้อกำหนดทางกฎหมาย

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

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


7

มันเป็นความจริงที่ดีขึ้นว่าabstract classสามารถไม่ถูก instantiated เป็นคนตอบ

เมื่อโปรแกรมกำหนดคลาสที่ไม่ระบุชื่อคอมไพเลอร์จะสร้างคลาสใหม่ที่มีชื่อแตกต่างกัน (มีรูปแบบEnclosedClassName$nที่nเป็นหมายเลขคลาสที่ไม่ระบุชื่อ)

ดังนั้นหากคุณถอดรหัสคลาส Java นี้คุณจะพบโค้ดดังนี้

ห้องเรียนของฉัน

abstract class my { 
    public void mymethod() 
    { 
        System.out.print("Abstract"); 
    }
} 

โพลี $ 1.class (คลาสที่สร้างของ "คลาสนิรนาม")

class poly$1 extends my 
{
} 

ploly.cass

public class poly extends my
{
    public static void main(String[] a)
    {
        my m = new poly.1(); // instance of poly.1 class NOT the abstract my class

        m.mymethod();
    }
}

4

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


4

เกี่ยวกับคลาสนามธรรม

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

จุดประสงค์ของคลาสนามธรรมคือทำตัวเหมือนฐาน ในลำดับชั้นการสืบทอดคุณจะเห็นคลาสนามธรรมไปทางด้านบน


3

คุณสามารถพูดได้ว่า:
เราไม่สามารถสร้างคลาสนามธรรมได้ แต่เราสามารถใช้newคีย์เวิร์ดเพื่อสร้างอินสแตนซ์ของคลาสนิรนามโดยเพียงแค่เพิ่ม{}เป็นแอพพลิเคชั่นที่ส่วนท้ายของคลาสนามธรรม


3

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

ฉันค่อนข้างมั่นใจว่าคลาสนามธรรมไม่อนุญาตให้เริ่มต้น ดังนั้นฉันจะบอกว่าไม่: คุณไม่สามารถยกระดับนามธรรม แต่คุณสามารถขยาย / รับมัน

คุณไม่สามารถยกตัวอย่างคลาสนามธรรมได้โดยตรง แต่มันไม่ได้หมายความว่าคุณจะไม่สามารถรับอินสแตนซ์ของคลาสได้ ฉันหมายความว่าคุณไม่สามารถยกระดับนามธรรมนามธรรมได้ แต่คุณสามารถ:

  1. สร้างคลาสที่ว่างเปล่า
  2. รับช่วงจากคลาสนามธรรม
  3. ยกตัวอย่างคลาส dervied

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


2

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

   public abstract class AbstractGridManager {
        private LifecicleAlgorithmIntrface lifecicleAlgorithm;
        // ... more private fields

        //Method implemented in concrete Manager implementors 
        abstract public Grid initGrid();

        //Methods common to all implementors
        public Grid calculateNextLifecicle(Grid grid){
            return this.getLifecicleAlgorithm().calculateNextLifecicle(grid);
        }

        public LifecicleAlgorithmIntrface getLifecicleAlgorithm() {
            return lifecicleAlgorithm;
        }
        public void setLifecicleAlgorithm(LifecicleAlgorithmIntrface lifecicleAlgorithm) {
            this.lifecicleAlgorithm = lifecicleAlgorithm;
        }
        // ... more common logic and getters-setters pairs
    }

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

public class FileInputGridManager extends AbstractGridManager {

private String filePath;

//Method implemented in concrete Manager implementors 
abstract public Grid initGrid();

public class FileInputGridManager extends AbstractGridManager {

    private String filePath;

    //Method implemented in concrete Manager implementors 
    abstract public Grid initGrid();

    public Grid initGrid(String filePath) {
        List<Cell> cells = new ArrayList<>();
        char[] chars;
        File file = new File(filePath); // for example foo.txt
        // ... more logic
        return grid;
    }
}

ในที่สุดโรงงานก็มีลักษณะดังนี้:

public class GridManagerFactory {
    public static AbstractGridManager getGridManager(LifecicleAlgorithmIntrface lifecicleAlgorithm, String... args){
        AbstractGridManager manager = null;

        // input from the command line
        if(args.length == 2){
            CommandLineGridManager clManager = new CommandLineGridManager();
            clManager.setWidth(Integer.parseInt(args[0]));
            clManager.setHeight(Integer.parseInt(args[1]));
            // possibly more configuration logic
            ...
            manager = clManager;
        } 
        // input from the file
        else if(args.length == 1){
            FileInputGridManager fiManager = new FileInputGridManager();
            fiManager.setFilePath(args[0]);
            // possibly more method calls from abstract class
            ...
            manager = fiManager ;
        }
        //... more possible concrete implementors
        else{
            manager = new CommandLineGridManager();
        }
        manager.setLifecicleAlgorithm(lifecicleAlgorithm);
        return manager;
    }
}

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


2

ไม่เราไม่สามารถสร้างวัตถุของคลาสนามธรรม แต่สร้างตัวแปรอ้างอิงของคลาสนามธรรม ตัวแปรอ้างอิงใช้เพื่ออ้างถึงวัตถุของคลาสที่ได้รับ (คลาสย่อยของคลาส Abstract)

นี่คือตัวอย่างที่แสดงแนวคิดนี้

abstract class Figure { 

    double dim1; 

    double dim2; 

    Figure(double a, double b) { 

        dim1 = a; 

        dim2 = b; 

    } 

    // area is now an abstract method 

    abstract double area(); 

    }


    class Rectangle extends Figure { 
        Rectangle(double a, double b) { 
        super(a, b); 
    } 
    // override area for rectangle 
    double area() { 
        System.out.println("Inside Area for Rectangle."); 
        return dim1 * dim2; 
    } 
}

class Triangle extends Figure { 
    Triangle(double a, double b) { 
        super(a, b); 
    } 
    // override area for right triangle 
    double area() { 
        System.out.println("Inside Area for Triangle."); 
        return dim1 * dim2 / 2; 
    } 
}

class AbstractAreas { 
    public static void main(String args[]) { 
        // Figure f = new Figure(10, 10); // illegal now 
        Rectangle r = new Rectangle(9, 5); 
        Triangle t = new Triangle(10, 8); 
        Figure figref; // this is OK, no object is created 
        figref = r; 
        System.out.println("Area is " + figref.area()); 
        figref = t; 
        System.out.println("Area is " + figref.area()); 
    } 
}

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


0

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

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