คุณสามารถเขียนฟังก์ชัน / วิธีเสมือนใน Java ได้ไหม


165

เป็นไปได้ไหมที่จะเขียนเมธอดเสมือนใน Java เหมือนกับที่ใช้ใน C ++?

หรือมีวิธีการ Java ที่เหมาะสมซึ่งคุณสามารถนำไปใช้ที่ก่อให้เกิดพฤติกรรมที่คล้ายกัน? ฉันขอตัวอย่างบางส่วนได้ไหม

คำตอบ:


305

จากวิกิพีเดีย

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


3
นี่คือหนึ่งในคำตอบของJon Skeet
Quazi Irfan

ฉันสงสัยว่าจริงหรือเปล่าเพราะสิ่งที่ฉันได้อ่านใน Java การจัดส่งเมธอดไดนามิกเกิดขึ้นเฉพาะกับวัตถุที่มีการเรียกใช้เมธอด - ตามที่อธิบายไว้ที่นี่ดังนั้นตัวอย่างการอธิบายฟังก์ชันเสมือนสำหรับ C ++ ที่นี่ไม่ถูกต้องสำหรับจาวา
บรอกโคลี

@QuaziIrfan นั่นคือความแตกต่างระหว่าง Java และ C #
Sreekanth Karumanaghat

101

คุณสามารถเขียนฟังก์ชันเสมือนใน Java ได้ไหม

ใช่. ในความเป็นจริงทุกวิธีของอินสแตนซ์ใน Java เป็นเสมือนโดยค่าเริ่มต้น วิธีการบางอย่างเท่านั้นไม่ใช่แบบเสมือน:

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

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

ฟังก์ชันเสมือน "ปกติ"

ตัวอย่างต่อไปนี้มาจากหน้า wikipedia เวอร์ชันเก่าที่กล่าวถึงในคำตอบอื่น

import java.util.*;

public class Animal 
{
   public void eat() 
   { 
      System.out.println("I eat like a generic Animal."); 
   }

   public static void main(String[] args) 
   {
      List<Animal> animals = new LinkedList<Animal>();

      animals.add(new Animal());
      animals.add(new Fish());
      animals.add(new Goldfish());
      animals.add(new OtherAnimal());

      for (Animal currentAnimal : animals) 
      {
         currentAnimal.eat();
      }
   }
}

class Fish extends Animal 
{
   @Override
   public void eat() 
   { 
      System.out.println("I eat like a fish!"); 
   }
}

class Goldfish extends Fish 
{
   @Override
   public void eat() 
   { 
      System.out.println("I eat like a goldfish!"); 
   }
}

class OtherAnimal extends Animal {}

เอาท์พุท:

ฉันกินเหมือนสัตว์ทั่วไป
ฉันกินเหมือนปลา!
ฉันกินเหมือนปลาทอง!
ฉันกินเหมือนสัตว์ทั่วไป

ตัวอย่างกับฟังก์ชั่นเสมือนจริงที่มีส่วนต่อประสาน

วิธีการเชื่อมต่อ Java เป็นเสมือนทั้งหมด พวกเขาจะต้องเป็นเสมือนเพราะพวกเขาอาศัยชั้นเรียนดำเนินการเพื่อให้วิธีการใช้งาน รหัสที่จะดำเนินการจะถูกเลือกในขณะใช้งานเท่านั้น

ตัวอย่างเช่น:

interface Bicycle {         //the function applyBrakes() is virtual because
    void applyBrakes();     //functions in interfaces are designed to be 
}                           //overridden.

class ACMEBicycle implements Bicycle {
    public void applyBrakes(){               //Here we implement applyBrakes()
       System.out.println("Brakes applied"); //function
    }
}

ตัวอย่างกับฟังก์ชั่นเสมือนจริงที่มีคลาสที่เป็นนามธรรม

คล้ายกับอินเทอร์เฟซคลาสนามธรรม ต้องประกอบด้วยวิธีเสมือนเนื่องจากพวกเขาอาศัยการใช้งานคลาสที่ขยาย ตัวอย่างเช่น:

abstract class Dog {                   
    final void bark() {               //bark() is not virtual because it is 
        System.out.println("woof");   //final and if you tried to override it
    }                                 //you would get a compile time error.

    abstract void jump();             //jump() is a "pure" virtual function 
}                                     
class MyDog extends Dog{
    void jump(){
        System.out.println("boing");    //here jump() is being overridden
    }                                  
}
public class Runner {
    public static void main(String[] args) {
        Dog dog = new MyDog();       // Create a MyDog and assign to plain Dog variable
        dog.jump();                  // calling the virtual function.
                                     // MyDog.jump() will be executed 
                                     // although the variable is just a plain Dog.
    }
}

1
นี่จะต้องเป็นคำตอบที่สมบูรณ์ที่สุด มันมี 2 วิธีในการใช้งานฟังก์ชั่นเสมือนจริงเนื่องจาก java ไม่มีคำหลัก ขอบคุณ.
Christopher Bales

คำตอบที่ดีกว่าการอ้างถึง Wikipedia มาจาก c ++ และขี้เกียจกับการศึกษา Java ของฉันบทคัดย่อเป็นสิ่งที่ฉันกำลังมองหา
เดวิด

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

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

1
สายไม่กี่ปีที่นี่ แต่คำตอบที่ยอดเยี่ยม
ทอมโอ

55

ฟังก์ชั่นทั้งหมดใน Java เป็นเสมือนโดยค่าเริ่มต้น

คุณต้องพยายามเขียนฟังก์ชั่นที่ไม่ใช่แบบเสมือนโดยเพิ่มคำหลัก "สุดท้าย"

นี่คือสิ่งที่ตรงกันข้ามกับค่าเริ่มต้น C ++ / C # ฟังก์ชั่นระดับที่ไม่ใช่เสมือนจริงโดยค่าเริ่มต้น; คุณทำได้โดยเพิ่มตัวดัดแปลง "เสมือน"


4
ฟังก์ชั่นส่วนตัวตามที่ระบุไว้ในคำตอบของ Klaus ก็ไม่ใช่แบบเสมือน
Don Larynx

9

ทั้งหมดไม่ใช่ส่วนตัววิธีการเช่นนี้เป็นเสมือนโดยเริ่มต้นใน Java

ใน C ++ เมธอดส่วนตัวสามารถเป็นเสมือนได้ สิ่งนี้สามารถนำไปใช้ประโยชน์สำหรับสำนวนที่ไม่ใช่เสมือนอินเตอร์เฟส (NVI) ใน Java คุณจะต้องทำให้ NVI นั้นสามารถป้องกัน overridable ได้

จากข้อกำหนดภาษา Java, v3:

8.4.8.1 การแทนที่ (โดยวิธีอินสแตนซ์) เมธอดอินสแตนซ์ m1 ที่ประกาศในคลาส C จะแทนที่เมธอดอินสแตนซ์อื่น m2 ซึ่งประกาศในคลาส A iff ต่อไปนี้ทั้งหมดเป็นจริง:

  1. C เป็นคลาสย่อยของ A
  2. ลายเซ็นของ m1 คือการลงนามย่อย (§8.4.2) ของลายเซ็นของ m2
  3. * m2 เป็นแบบสาธารณะป้องกันหรือประกาศด้วยการเข้าถึงเริ่มต้นในแพ็คเกจเดียวกันกับ C หรือ * m1 แทนที่เมธอด m3, m3 แตกต่างจาก m1, m3 แตกต่างจาก m2 เช่น m3 ลบล้าง m2


1

ใน Java ตัวแปรและฟังก์ชั่นสาธารณะ (ไม่ใช่ส่วนตัว) ทั้งหมดเป็นเสมือนโดยค่าเริ่มต้น นอกจากนี้ตัวแปรและฟังก์ชั่นใช้คำสุดท้ายไม่ได้เสมือนจริง


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