โอเวอร์โหลดด้วยประเภทผลตอบแทนที่แตกต่างกันใน Java?


104

เหตุใดจึงไม่สามารถโอเวอร์โหลดฟังก์ชันได้เพียงแค่เปลี่ยนประเภทการส่งคืน จะมีการเปลี่ยนแปลงใน Java เวอร์ชันอนาคตหรือไม่?

อย่างไรก็ตามสำหรับการอ้างอิงสิ่งนี้เป็นไปได้ใน C ++ หรือไม่?


1
เป็นไปได้ที่จะทำซ้ำFunction overloading ตามประเภท return?
KNU

KNU คำตอบอื่นแตกต่างกันตรงที่ถามคำถามโดยทั่วไปไม่ใช่คำเฉพาะภาษา สิ่งที่น่าสนใจก็คือคำตอบที่ได้รับการยอมรับของคำถามอื่น ๆ จะดำเนินต่อไปโดยระบุว่า Java JVM อนุญาตให้ดำเนินการด้วยการจัดการภายใน
J Woodchuck

คำตอบ:


157

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

public int foo() {...}
public float foo() {..}

...
foo(); // which one?

3
ฉันคิดเสมอว่าถ้าเราทำบางอย่างเช่น int i = foo () หรือ float f = foo () มันจะรู้ว่าอันไหน แต่ถ้าคำสั่งนั้นเป็นเพียงฟังก์ชันที่คอมไพเลอร์ไม่รู้ ฉันได้รับรู้ ขอบคุณ.
nunos

7
@nunos แม้ว่าจะเป็น float f = foo () คอมไพเลอร์จะไม่สามารถคิดออกได้เนื่องจากทั้งสอง int จะเป็นอินพุตที่ถูกต้องสำหรับ float เปรียบเทียบ float f = 7; (is 7 a float or int?)
NomeN

5
@NomeN แต่คำพูดของคุณชี้ให้เห็นว่า func (int i) และ func (float i) จะแยกไม่ออกสำหรับคอมไพเลอร์ - และเราทุกคนรู้ว่านี่ไม่เป็นความจริง Oded ให้เหตุผลที่แท้จริง (ดูคำตอบถัดไป) - เกี่ยวกับลายเซ็นของวิธีการ และ btw. 7 เป็นจำนวนเต็มแน่นอนในขณะที่ 7.0 หรือ 7f เป็น float ;-)
Ta Sas

7
7.0 ไม่ได้ก็float double
fredoverflow

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

48

เหตุผลก็คือการโอเวอร์โหลดใน Java จะได้รับอนุญาตสำหรับเมธอดที่มีลายเซ็นต่างกันเท่านั้น

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

ดูการกำหนดวิธีการจากบทช่วยสอน Java


4
แต่ทำไมพิมพ์กลับไม่ใช่ส่วนหนึ่งของลายเซ็น
andho

51
โอ้ "เพียงเพราะ"! ฉันเห็น.
andho

3
ประเภทการส่งคืนเป็นส่วนหนึ่งของลายเซ็นวิธีการ เพียงแค่ดูการแยกชิ้นส่วนชั้นเรียน
konmik

2
จริงๆแล้วมันไม่ใช่ @konmik - ไม่ใช่ตามกฎของการโอเวอร์โหลด ลองมัน. ชื่อเมธอดเดียวกันประเภทพารามิเตอร์เดียวกันในลำดับเดียวกันประเภทผลตอบแทนที่แตกต่างกัน จะไม่รวบรวม
Oded

3
ใช่เพราะประเภทกลับไม่ได้เป็นส่วนหนึ่งของลายเซ็น ลายเซ็นคือ - ชื่อของวิธีการ + ประเภทและลำดับของพารามิเตอร์ อ่านลิงก์ที่ฉันให้ไว้ในคำตอบของฉัน: "ลายเซ็นของวิธีการที่ระบุไว้ข้างต้นคือ: calculateAnswer(double, int, double, double)" ดูว่าไม่รวมประเภทการคืนสินค้า @konmik
Oded

22

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


3
ฉันรู้สึกงุนงงเมื่อเห็นสิ่งนี้ครั้งแรก ขอขอบคุณที่อธิบายว่าเหตุใดจึงเป็นไปได้!
Dylan Knowles

2
การโอเวอร์โหลดและการเอาชนะนั้นแตกต่างกัน การบรรทุกเกินพิกัดไม่ (จำเป็น) เกี่ยวข้องกับการถ่ายทอดทางพันธุกรรม
senseiwu

3
คำตอบนี้อาจฟังดูเข้าใจผิดสำหรับมือใหม่ใน Java เนื่องจากไม่เกี่ยวข้องกับการโอเวอร์โหลดเลยมันเป็นการลบล้างสิ่งอื่น ๆ โดยสิ้นเชิง
azizbekian

4

Overloaded วิธีการใน java อาจมีประเภทการส่งคืนที่แตกต่างกันเนื่องจากอาร์กิวเมนต์นั้นแตกต่างกันด้วย

ตรวจสอบโค้ดตัวอย่าง

public class B {

    public String greet() {
        return "Hello";
    }

    //This will work
    public StringBuilder greet(String name) {
        return new StringBuilder("Hello " + name);
    }

    //This will not work
    //Error: Duplicate method greet() in type B
    public StringBuilder greet() {
        return new StringBuilder("Hello Tarzan");
    }

}

โดยพื้นฐานแล้วประเภทผลตอบแทนไม่ได้ถูกนำมาพิจารณามีเพียงข้อโต้แย้งเท่านั้นที่น่าเศร้า แต่เป็นความจริง
Alexander Mills

1

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


1

ประเภทการส่งคืนไม่สำคัญในขณะที่ใช้วิธีการมากเกินไป เราต้องมั่นใจว่าไม่มีความคลุมเครือ!

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


0

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

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

Compile Time Error ดีกว่า Run Time Error ดังนั้นคอมไพเลอร์ java จึงแสดงข้อผิดพลาดเวลาคอมไพเลอร์หากคุณประกาศวิธีการเดียวกันที่มีพารามิเตอร์เดียวกัน


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

-2

ไม่มีทางเป็นไปได้จริงๆที่คุณสามารถโอเวอร์โหลดได้โดยไม่มีอาร์กิวเมนต์หรือประเภทข้อมูลของอาร์กิวเมนต์

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