คลาสนามธรรมใน Java


274

"คลาสนามธรรม" ใน Java คืออะไร?


35
+1 คำถามนี้เป็นพื้นฐานและพื้นฐานเป็นแบบคลาสสิคสำหรับ SO ฉันประหลาดใจที่ไม่ได้ถามที่นี่มาก่อน
Yuval

6
-1 สำหรับความคิดเห็นของ Clement (ถ้าทำได้); lmgtfy ไม่ใช่คำตอบที่เป็นประโยชน์ สำหรับเหตุผลที่อ่านเช่นmeta.stackexchange.com/questions/5280/embrace-the-non-googlers
Jonik

26
@tuergeist มันไม่เกี่ยวข้องหาก Google เป็นเรื่องง่ายตราบใดที่ยังไม่เคยมีการถามเกี่ยวกับ SO มาก่อน ใครบอกว่าคำถามเริ่มต้นเกี่ยวกับภาษาการเขียนโปรแกรมไม่ได้อยู่ในนั้น
Jonik

12
สิ่งหนึ่งที่ฉันชอบเกี่ยวกับ SO ก็คือคุณจะได้รับคำตอบที่ย่อแน่นดีและตรงประเด็นโดยไม่มี BS ปกติที่พบในส่วนที่เหลือของเว็บ ... +1 สำหรับคำถาม!
Anders Hansson

1
ดังนั้นไม่ควรจะมีหางยาว! J&J พูดถึงสิ่งนี้เกี่ยวกับพอดคาสต์ 56 ...
kwutchak

คำตอบ:


342

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

  1. กำหนดวิธีการที่สามารถใช้โดยคลาสย่อยที่สืบทอด
  2. กำหนดวิธีการนามธรรมซึ่ง subclass รับมรดกต้องดำเนินการ
  3. จัดให้มีอินเตอร์เฟสทั่วไปซึ่งอนุญาตให้คลาสย่อยสลับกับคลาสย่อยอื่นทั้งหมด

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

abstract public class AbstractClass
{
    abstract public void abstractMethod();
    public void implementedMethod() { System.out.print("implementedMethod()"); }
    final public void finalMethod() { System.out.print("finalMethod()"); }
}

โปรดสังเกตว่า "abstractMethod ()" ไม่มีเนื้อความของเมธอด ด้วยเหตุนี้คุณจึงไม่สามารถทำสิ่งต่อไปนี้:

public class ImplementingClass extends AbstractClass
{
    // ERROR!
}

ไม่มีวิธีการที่ใช้abstractMethod()! ดังนั้นจึงมีทางสำหรับ JVM new ImplementingClass().abstractMethod()ที่จะรู้ว่าสิ่งที่มันควรจะทำอย่างไรเมื่อได้รับบางสิ่งบางอย่างที่ไม่เหมือนใคร

นี่ถูกต้องImplementingClassแล้ว

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
}

ขอให้สังเกตว่าคุณไม่ได้มีการกำหนดหรือimplementedMethod() พวกเขาถูกกำหนดไว้แล้วโดยfinalMethod()AbstractClass

ImplementingClassนี่คือที่ถูกต้องอีก

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

implementedMethod()ในกรณีนี้คุณได้แทนที่

อย่างไรก็ตามเนื่องจากfinalคำหลักทำให้เป็นไปไม่ได้

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
    public void finalMethod() { System.out.print("ERROR!"); }
}

คุณไม่สามารถทำสิ่งนี้ได้เนื่องจากการใช้งานของfinalMethod()in AbstractClassถูกทำเครื่องหมายว่าเป็นการใช้งานขั้นสุดท้ายของfinalMethod(): จะไม่มีการอนุญาตให้มีการใช้งานอื่น ๆ

ตอนนี้คุณยังสามารถใช้คลาสนามธรรมได้สองครั้ง:

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

// In a separate file.
public class SecondImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("second abstractMethod()"); }
}

คุณสามารถเขียนวิธีอื่นได้แล้ว

public tryItOut()
{
    ImplementingClass a = new ImplementingClass();
    AbstractClass b = new ImplementingClass();

    a.abstractMethod();    // prints "abstractMethod()"
    a.implementedMethod(); // prints "Overridden!"     <-- same
    a.finalMethod();       // prints "finalMethod()"

    b.abstractMethod();    // prints "abstractMethod()"
    b.implementedMethod(); // prints "Overridden!"     <-- same
    b.finalMethod();       // prints "finalMethod()"

    SecondImplementingClass c = new SecondImplementingClass();
    AbstractClass d = new SecondImplementingClass();

    c.abstractMethod();    // prints "second abstractMethod()"
    c.implementedMethod(); // prints "implementedMethod()"
    c.finalMethod();       // prints "finalMethod()"

    d.abstractMethod();    // prints "second abstractMethod()"
    d.implementedMethod(); // prints "implementedMethod()"
    d.finalMethod();       // prints "finalMethod()"
}

ขอให้สังเกตว่าแม้ว่าเราจะประกาศชนิดจะแสดง นี่เป็นเพราะวัตถุที่เราสร้างอินสแตนซ์นั้นแท้จริงแล้วเป็นของซึ่งถูกแทนที่แน่นอน (คุณอาจเคยเห็นสิ่งนี้เรียกว่า polymorphism)bAbstractClass"Overriden!"ImplementingClassimplementedMethod()

หากเราต้องการเข้าถึงสมาชิกที่เฉพาะเจาะจงสำหรับคลาสย่อยเฉพาะเราจะต้องส่งไปที่คลาสย่อยนั้นก่อน:

// Say ImplementingClass also contains uniqueMethod()
// To access it, we use a cast to tell the runtime which type the object is
AbstractClass b = new ImplementingClass();
((ImplementingClass)b).uniqueMethod();

สุดท้ายคุณไม่สามารถทำสิ่งต่อไปนี้:

public class ImplementingClass extends AbstractClass, SomeOtherAbstractClass
{
    ... // implementation
}

สามารถขยายได้ครั้งละหนึ่งคลาสเท่านั้น หากคุณต้องการขยายหลายคลาสพวกเขาจะต้องเป็นอินเทอร์เฟซ คุณสามารถทำได้:

public class ImplementingClass extends AbstractClass implements InterfaceA, InterfaceB
{
    ... // implementation
}

นี่คืออินเทอร์เฟซตัวอย่าง:

interface InterfaceA
{
    void interfaceMethod();
}

นี่เป็นพื้นเหมือนกับ:

abstract public class InterfaceA
{
    abstract public void interfaceMethod();
}

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

ต่อไปนี้ผิดกฎหมาย:

interface InterfaceB
{
    void interfaceMethod() { System.out.print("ERROR!"); }
}

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


5
@Imagist -1 สำหรับคำอธิบายที่ไม่ถูกต้องสำหรับคำสั่ง c.implementedMethod (); // พิมพ์ "ImplementMethod ()" มันจะพิมพ์ "Overriden!" เสมอ
Sachin Kumar

2
@Sachin ฉันเสียเวลาไปครึ่งชั่วโมงกว่าจะเข้าใจว่าทำไมมันถึงพิมพ์ "ImplementMethod ()" จากนั้นฉันก็เห็นความคิดเห็นของคุณ มีบางสิ่งเปลี่ยนแปลงกับ java หรือคนอื่นมองข้ามความผิดพลาดหรือไม่?
Rounak

@SachinKumar เนื่องจากการขาดการตอบสนองของผู้เขียนฉันได้ดำเนินการเองเพื่อแก้ไขข้อผิดพลาดนี้ CMIIW
Mateen Ulhaq

@SachinKumar ฉันมาช้าไปหน่อยที่เกมนี้ แต่คุณจะบอกว่าการเปรียบเทียบที่ดีจะเป็นการประกาศวิธีการ (แต่ไม่มีการนำไปใช้) ในไฟล์ส่วนหัว C ++?
Schwaitz

5
@SachinKumar ทำไมจะc.implementedMethod()พิมพ์ "Overriden!" ไม่แทนที่SecondImplementingClass implementedMethod()
John Red

75

คลาส Java กลายเป็นนามธรรมภายใต้เงื่อนไขดังต่อไปนี้:

1. วิธีการอย่างน้อยหนึ่งวิธีถูกทำเครื่องหมายเป็นนามธรรม:

public abstract void myMethod()

ในกรณีนั้นคอมไพเลอร์บังคับให้คุณทำเครื่องหมายคลาสทั้งหมดว่าเป็นนามธรรม

2. ชั้นถูกทำเครื่องหมายเป็นนามธรรม:

abstract class MyClass

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

การใช้งานทั่วไป:

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

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


1
Nitpick: 'เงื่อนไข' ที่สองซ้ำซ้อนเนื่องจากคุณสามารถประกาศเมธอด abstract ในคลาสที่มีการประกาศอย่างชัดเจนว่าเป็นนามธรรมเท่านั้น
สตีเฟ่น C

2
ตกลงคำแนะนำไม่ถูกต้องจริง ๆ หรือเขียนดีมันเป็นรูปแบบเพียงอย่างเดียว
เที่ยงไหม

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

1
นี่เป็นเพียงผิดธรรมดา คลาสนามธรรมไม่จำเป็นต้องมีวิธีนามธรรมใด ๆ คุณสามารถสร้างคลาสนามธรรมโดยไม่ต้องใช้วิธีหรือด้วยวิธีที่เป็นรูปธรรมเท่านั้น
Jorn

1
ช้าไปกว่า 10 ปีสำหรับเกม แต่นี่เป็นคำตอบที่แม่นยำที่สุด @Jorn คุณกำลังสับสนกับคำตอบที่ฉันคิด ฉันแน่ใจว่ามันส่อให้เห็นว่าabstractคำหลักนั้นเป็นสิ่งที่จำเป็นสำหรับชั้นเรียนที่จะเป็นนามธรรม แต่คลาสคอนกรีตไม่สามารถมีabstract วิธีการได้ ดังนั้นถ้าคลาสของคุณมีabstractเมธอดมันจะต้องประกาศเป็นabstractคลาสของคอมไพเลอร์
Rakib

24

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

สิ่งสำคัญของคลาสนามธรรม

  • คลาสนามธรรมอาจมีหรือไม่มีวิธีนามธรรมซึ่งอาจเป็นวิธีที่ไม่เป็นนามธรรม

    วิธีนามธรรมเป็นวิธีการที่ประกาศโดยไม่มีการใช้งาน (โดยไม่ต้องใส่เครื่องหมายและตามด้วยเครื่องหมายอัฒภาค) ดังนี้:

    เช่น abstract void moveTo(double deltaX, double deltaY);

  • หากคลาสมีวิธีนามธรรมอย่างน้อยหนึ่งคลาสดังนั้นคลาสนั้นต้องเป็นนามธรรม

  • คลาส Abstract อาจไม่ได้สร้างอินสแตนซ์ (คุณไม่ได้รับอนุญาตให้สร้างออบเจ็กต์คลาส Abstract)

  • ในการใช้คลาสนามธรรมคุณต้องสืบทอดคลาสนี้จากคลาสอื่น ให้การใช้งานกับวิธีนามธรรมทั้งหมดในนั้น

  • ถ้าคุณสืบทอดคลาส abstract คุณต้องจัดเตรียมการประยุกต์ใช้กับเมธอด abstract ทั้งหมดในคลาสนั้น

ประกาศคลาส abstract การระบุabstractคีย์เวิร์ดก่อนคลาสระหว่างการประกาศทำให้เป็นนามธรรม ดูรหัสด้านล่าง:

abstract class AbstractDemo{ }

ประกาศเมธอด abstract การ ระบุabstractคีย์เวิร์ดก่อนเมธอดระหว่างการประกาศทำให้เป็นนามธรรม ดูรหัสด้านล่าง

abstract void moveTo();//no body

ทำไมเราต้องเรียนนามธรรม

ในแอปพลิเคชั่นการวาดภาพเชิงวัตถุคุณสามารถวาดวงกลมสี่เหลี่ยมเส้นโค้ง Bezier และวัตถุกราฟิกอื่น ๆ อีกมากมาย วัตถุเหล่านี้ทั้งหมดมีสถานะบางอย่าง (สำหรับ ex -: ตำแหน่ง, การวางแนว, สีของเส้น, สีเติม) และพฤติกรรม (สำหรับ ex -: moveTo, หมุน, ปรับขนาด, วาดรูป) เหมือนกัน สถานะและพฤติกรรมเหล่านี้บางอย่างนั้นเหมือนกันสำหรับวัตถุกราฟิกทั้งหมด (เช่น: เติมสีตำแหน่งและ moveTo) คนอื่น ๆ ต้องการการใช้งานที่แตกต่างกัน (เช่นปรับขนาดหรือวาดรูป) วัตถุกราฟิกทั้งหมดจะต้องสามารถวาดหรือปรับขนาดตัวเองพวกเขาเพียงแค่แตกต่างในวิธีที่พวกเขาทำ

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

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

abstract class GraphicObject {

  void moveTo(int x, int y) {
    // Inside this method we have to change the position of the graphic 
    // object according to x,y     
    // This is the same in every GraphicObject. Then we can implement here. 
  }

  abstract void draw(); // But every GraphicObject drawing case is 
                        // unique, not common. Then we have to create that 
                        // case inside each class. Then create these    
                        // methods as abstract 
  abstract void resize();
}

การใช้เมธอด abstract ในคลาสย่อย แต่ละคลาสย่อยที่ไม่ใช่ abstract ของGraphicObjectเช่นCircleและRectangleต้องจัดเตรียมการประยุกต์ใช้สำหรับdrawและresizeเมธอด

class Circle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here   
  }
}
class Rectangle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here
  }
}

ภายในmainวิธีที่คุณสามารถเรียกวิธีการทั้งหมดเช่นนี้

public static void main(String args[]){
   GraphicObject c = new Circle();
   c.draw();
   c.resize();
   c.moveTo(4,5);   
}

วิธีเพื่อให้ได้นามธรรมใน Java

มีสองวิธีในการทำให้เกิดนามธรรมใน java

  • ระดับนามธรรม (0 ถึง 100%)
  • อินเทอร์เฟซ (100%)

คลาสนามธรรมกับตัวสร้างสมาชิกข้อมูลวิธีการ ฯลฯ

abstract class GraphicObject {

  GraphicObject (){
    System.out.println("GraphicObject  is created");
  }
  void moveTo(int y, int x) {
       System.out.println("Change position according to "+ x+ " and " + y);
  }
  abstract void draw();
}

class Circle extends GraphicObject {
  void draw() {
    System.out.println("Draw the Circle");
  }
}

class TestAbstract {  
 public static void main(String args[]){

   GraphicObject  grObj = new Circle ();
   grObj.draw();
   grObj.moveTo(4,6);
 }
}

เอาท์พุท:

GraphicObject  is created
Draw the Circle
Change position according to 6 and 4

จำกฎสองข้อ:

  • หากชั้นเรียนมีวิธีนามธรรมที่เป็นรูปธรรมและวิธีรูปธรรมไม่กี่รูปแบบให้ประกาศเป็นabstractชั้นเรียน

  • interfaceถ้าชั้นมีเพียงวิธีการที่เป็นนามธรรมประกาศว่ามันเป็น

อ้างอิง:


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

กฎทั้งสองให้ออกไป
LiNKeR


3

เพียงแค่พูดคุณสามารถคิดถึงคลาสนามธรรมได้เหมือนอินเทอร์เฟซที่มีความสามารถเพิ่มขึ้นอีกเล็กน้อย

คุณไม่สามารถสร้างอินเทอร์เฟซซึ่งยกตัวอย่างเช่นคลาสนามธรรม

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

public abstract class MyAbstractClass{
  public abstract void DoSomething();
}

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

ตัวอย่าง:

public abstract class MyAbstractClass{

  public int CalculateCost(int amount){
     //do some default calculations
     //this can be overriden by subclasses if needed
  }

  //this MUST be implemented by subclasses
  public abstract void DoSomething();
}

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

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

3

จากเอกสาร Oracle

วิธีการและชั้นนามธรรม:

คลาสนามธรรมเป็นคลาสที่มีการประกาศนามธรรมซึ่งอาจมีหรือไม่มีวิธีนามธรรม

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

วิธีนามธรรมเป็นวิธีการที่ประกาศโดยไม่มีการใช้งาน (โดยไม่ต้องใส่เครื่องหมายและตามด้วยเครื่องหมายอัฒภาค)เช่นนี้

abstract void moveTo(double deltaX, double deltaY);

ถ้าคลาสมีเมธอด abstract คลาสนั้นต้องถูกประกาศเป็นนามธรรมเช่นเดียวกับใน:

public abstract class GraphicObject {
   // declare fields
   // declare nonabstract methods
   abstract void draw();
}

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

ตั้งแต่abstract classesและinterfacesมีความเกี่ยวข้องให้ดูที่คำถามด้านล่าง SE:

อะไรคือความแตกต่างระหว่างอินเตอร์เฟสและคลาสนามธรรม?

ฉันจะอธิบายความแตกต่างระหว่างอินเทอร์เฟซกับคลาสนามธรรมได้อย่างไร


3

รับคำตอบของคุณที่นี่:

Abstract class vs Interface ใน Java

คลาสนามธรรมสามารถมีวิธีสุดท้ายได้หรือไม่?

BTW - เป็นคำถามที่คุณถามเมื่อเร็ว ๆ นี้ ลองคิดคำถามใหม่เพื่อสร้างชื่อเสียง ...

แก้ไข:

เพิ่งรู้ว่าผู้โพสต์ของคำถามนี้และคำถามที่อ้างอิงมีชื่อเดียวกันหรืออย่างน้อยก็คล้ายกัน แต่ user-id นั้นต่างกันเสมอ ดังนั้นอย่างใดอย่างหนึ่งมีปัญหาทางเทคนิค Keyur ที่มีปัญหาในการเข้าสู่ระบบอีกครั้งและหาคำตอบสำหรับคำถามของเขาหรือนี่เป็นเกมประเภทหนึ่งที่สร้างความบันเทิงให้กับชุมชน SO);


และที่ว่าทำไมฉันจะตรวจสอบ 'ชุมชนวิกิพีเดีย' - ไม่ควรเพิ่ม reputiation ผ่านปฏิกิริยาในคำถามเหล่านั้น;)
แอนเดรี Dolk

1

นอกจากนี้เล็กน้อยจากการโพสต์ทั้งหมดเหล่านี้

บางครั้งคุณอาจต้องการประกาศคลาส แต่ยังไม่รู้วิธีกำหนดวิธีทั้งหมดที่เป็นของคลาสนั้น ตัวอย่างเช่นคุณอาจต้องการที่จะประกาศระดับที่เรียกว่านักเขียนและรวมอยู่ในนั้นเป็นวิธีการที่สมาชิกเรียกว่า การเขียน () อย่างไรก็ตามคุณไม่ทราบวิธีเขียนโค้ด()เนื่องจากมีความแตกต่างกันสำหรับอุปกรณ์ Writer แต่ละประเภท แน่นอนคุณวางแผนที่จะจัดการสิ่งนี้ด้วยการรับคลาสย่อยของ Writer เช่น Printer, Disk, Network และ Console


1

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

abstract class Foo {
    abstract void someMethod();
}

หรือโดยอ้อม

interface IFoo {
    void someMethod();
}

abstract class Foo2 implements IFoo {
}

อย่างไรก็ตามชั้นเรียนสามารถเป็นนามธรรมโดยไม่ต้องมีวิธีการที่เป็นนามธรรม มันเป็นวิธีที่จะป้องกันการฉับพลันโดยตรงเช่น

abstract class Foo3 {
}

class Bar extends Foo3 {

}

Foo3 myVar = new Foo3(); // illegal! class is abstract
Foo3 myVar = new Bar(); // allowed!

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

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

abstract class Processor {
    protected abstract int[] filterInput(int[] unfiltered);

    public int process(int[] values) {
        int[] filtered = filterInput(values);
        // do something with filtered input
    }
}

class EvenValues extends Processor {
    protected int[] filterInput(int[] unfiltered) {
        // remove odd numbers
    }
}

class OddValues extends Processor {
    protected int[] filterInput(int[] unfiltered) {
        // remove even numbers
    }
}

1

โซลูชัน - คลาสพื้นฐาน (นามธรรม)

public abstract class Place {

String Name;
String Postcode;
String County;
String Area;

Place () {

        }

public static Place make(String Incoming) {
        if (Incoming.length() < 61) return (null);

        String Name = (Incoming.substring(4,26)).trim();
        String County = (Incoming.substring(27,48)).trim();
        String Postcode = (Incoming.substring(48,61)).trim();
        String Area = (Incoming.substring(61)).trim();

        Place created;
        if (Name.equalsIgnoreCase(Area)) {
                created = new Area(Area,County,Postcode);
        } else {
                created = new District(Name,County,Postcode,Area);
        }
        return (created);
        }

public String getName() {
        return (Name);
        }

public String getPostcode() {
        return (Postcode);
        }

public String getCounty() {
        return (County);
        }

public abstract String getArea();

}

1
ลองจัดรูปแบบรหัสทั้งหมดเป็นรหัสและโปรดเพิ่มคำอธิบายตอนนี้อาจถือได้ว่าเป็นคำตอบ
NomeN

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

0

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

กล่าวอีกนัยหนึ่งคลาสที่มีการประกาศด้วยคำหลักที่เป็นนามธรรมเป็นที่รู้จักกันเป็นคลาสนามธรรมใน java มันสามารถมีนามธรรม (วิธีโดยไม่ต้องร่างกาย) และวิธีการที่ไม่ใช่นามธรรม (วิธีการที่มีร่างกาย)

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

abstract class Bike{  
  abstract void run();  
}  

class Honda4 extends Bike{  
    void run(){
        System.out.println("running safely..");
    }  

    public static void main(String args[]){  
       Bike obj = new Honda4();  
       obj.run();  
    }  
} 

0

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


0

คลาสที่มีทั้งวิธีที่เป็นรูปธรรมและไม่ใช่รูปธรรมเช่นมีหรือไม่มีตัว

  1. วิธีที่ไม่มีการนำไปใช้จะต้องมีคำหลัก 'นามธรรม'
  2. คลาสนามธรรมไม่สามารถสร้างอินสแตนซ์ได้

-1

มันไม่ทำอะไรเลยเพียงแค่สร้างเทมเพลตทั่วไปที่จะแชร์ให้กับคลาสย่อย

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