2013-08-09 10 views
7

अगर मुझे यह प्रश्न मुख्य रूप से राय आधारित है, तो मुझे क्षमा करें, लेकिन मुझे लगता है कि यह नहीं है और पसंद के लिए एक अच्छा कारण है। तो, यहां एक उदाहरण है। क्षमा करें, यह वास्तव में लंबे समय से है, लेकिन बहुत ही आसान है:ओवरराइडिंग बनाम ओवरलोडिंग

इंटरफ़ेस:

public interface Shape 
{ 
    double area(); 
} 

को लागू वर्ग 1:

import static java.lang.Math.PI; 

public class Circle implements Shape 
{ 
    private double radius; 

    public Circle(double radius) 
    { 
     this.radius = radius; 
    } 

    public double area() 
    { 
     return PI*radius*radius; 
    } 
} 

को लागू वर्ग 2:

public class Square implements Shape 
{ 
    private double size; 

    public Square(double sideLength) 
    { 
     size = sideLength; 
    } 

    public double area() 
    { 
     return size*size; 
    } 
} 

चालक:

Shape[] shapes = new Shape[]{new Circle (5.3), new Square (2.4)}; 

System.out.println(shapes[0].area()); //prints 88.247... 
System.out.println(shapes[1].area()); //prints 5.76 

यह .area() से काम करता है Circle और Square द्वारा ओवरराइड किया गया है। अब, यहां मेरा प्रश्न वास्तव में शुरू होता है। मान लीजिए कि चालक इन तरीकों है करते हैं:

public static void whatIs(Shape s) 
{ 
    System.out.println("Shape"); 
} 

public static void whatIs(Circle s) 
{ 
    System.out.println("Circle"); 
} 

public static void whatIs(Square s) 
{ 
    System.out.println("Square"); 
} 

अगर हम कहते हैं:

whatIs(shapes[0]); //prints "Shape" 
whatIs(shapes[1]); //prints "Shape" 

यह इसलिए होता है क्योंकि जावा Shape रों के रूप में वस्तुओं की व्याख्या और नहीं Circle और Square

if (shapes[0] instanceof Circle) 
{ 
    whatIs((Circle) shapes[0]); //prints "Circle" 
} 
if (shapes[1] instanceof Square) 
{ 
    whatIs((Square) shapes[1]); //prints "Square" 
} 

अब जब हम एक पृष्ठभूमि है मेरे सवाल है: बेशक हम के माध्यम से वांछित परिणाम प्राप्त कर सकते हैं? "आकार"
किन वजहों से संकलक/भाषा डिजाइन ऐसा है कि whatIs(shapes[0]); प्रिंट होगा करने के लिए योगदान जैसा कि, जावा कंपाइलर संबंधित वस्तुओं के लिए ओवरराइड विधियों के बीच सटीक रूप से अंतर क्यों कर सकता है, लेकिन अधिभारित विधियों को नहीं? विशेष रूप से, अगर केवल तरीकों कि ड्राइवर का उपयोग करने के लिए किया हैं:

public static void whatIs(Circle s) 
{ 
    System.out.println("Circle"); 
} 
public static void whatIs(Square s) 
{ 
    System.out.println("Square"); 
} 

और हम कॉल करने का प्रयास,

whatIs(shapes[0]); 
whatIs(shapes[1]); 

हम दो त्रुटियों (Square के लिए एक और Circle के लिए एक) मिल जाएगा यह दर्शाता है कि:

  • विधि Driver.whatIs (वर्ग) लागू नहीं है
    • वास्तविक तर्क आकार विधि मंगलाचरण रूपांतरण

तो, फिर से, अब है कि हम बुनियादी तथ्य, क्यों जावा की तरह एक स्थिति नहीं संभाल कर सकते हैं मिल गया है द्वारा स्क्वायर के लिए नहीं बदला जा सकता इस? जैसा कि, यह दक्षता चिंताओं के कारण किया जाता है, क्या कुछ डिजाइन निर्णयों के कारण यह संभव नहीं है, क्या यह किसी कारण से बुरा व्यवहार है, आदि?

+0

इसके अलावा, अगर किसी के पास शीर्षक के लिए बेहतर विचार है, तो कृपया कोई सुझाव दें या इसे संपादित करें, मुझे पता है कि यह शायद सबसे अच्छा नहीं है, लेकिन कुछ भी बेहतर नहीं सोच सकता है। उन सभी के लिए धन्यवाद जिन्होंने इस पोस्ट के माध्यम से इसे बनाया! –

+4

मैं आपको [जेएलएस अनुभाग 15.2.2] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2) (ओवरलोडिंग) के माध्यम से जाने का सुझाव देता हूं और [जेएलएस अनुभाग 8.4.8.1] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8.1) (ओवरराइडिंग) –

+1

दिलचस्प सवाल, और @ रोहितजैन टिप्पणी के लिए धन्यवाद, मुझे उनको भी पढ़ना होगा। –

उत्तर

4

जावा कंपाइलर संबंधित वस्तुओं के लिए ओवरराइड विधियों के बीच सटीक रूप से अंतर क्यों कर सकता है, लेकिन ओवरलोडेड विधियों के लिए क्यों नहीं?

यह नहीं हो सकता है।

यह & गारंटी देखकर सख्ती से जांचता है। यदि आपका कोड shapes[0].area() है तो यह जांच करेगा कि Shape में area विधि है और इसे उस ऑब्जेक्ट पर कॉल क्षेत्र() पर संकलित कर देगा। रनटाइम पर मौजूद कंक्रीट ऑब्जेक्ट अब उस विधि के लिए गारंटीकृत है। वास्तव में किस वर्ग से कक्षा का उपयोग किया जाता है वह रनटाइम पर गतिशील रूप से हल किया जाता है।

ओवरलोडेड विधियों को कॉल करना वही काम करता है। कंपाइलर Shape देखता है और इसे "मूल आकार संस्करण में कॉल व्हाटिस() में संकलित करता है। यदि आप इसे बदलना चाहते हैं (और यहां तक ​​कि कोई मूल Shape संस्करण होने की अनुमति नहीं है) तो आपको संकलन समय पर प्रकार निर्धारित करने में सक्षम होना चाहिए।

लेकिन यह AFAIK एक कंपाइलर बनाना असंभव है जो उस बिंदु पर किसी ऑब्जेक्ट के रनटाइम पर निर्धारित प्रकार निर्धारित कर सकता है। उदाहरण के लिए सोचें:

final Shape[] shapes = new Shape[] { new Circle(5.3), new Square(2.4) }; 
    new Thread() { 
     public void run() { 
      shapes[0] = new Square(1.5); 
     } 
    }.start(); 
    whatIs(shapes[0]); 

आपको यह पता लगाने के लिए उस कोड को निष्पादित करना होगा।

संकलक ऑटो आप रनटाइम पर गतिशील विधि मंगलाचरण को प्राप्त करने के लिए की तरह

if (shapes[0] instanceof Circle) 
{ 
    whatIs((Circle) shapes[0]); //prints "Circle" 
} 

कोड उत्पन्न कर सकता है लेकिन ऐसा नहीं है। मुझे कारण पता नहीं है लेकिन कभी-कभी यह साफ-सुथरा होगा। यद्यपि instanceof अक्सर खराब वर्ग के डिजाइन के लिए एक संकेत है - आपको मतभेदों के लिए बाहर से नहीं देखना चाहिए, कक्षा को अलग तरीके से व्यवहार करने दें ताकि बाहरी को जानने की आवश्यकता न हो।

+0

मुझे लगता है कि अब मेरा प्रश्न आपके जैसा ही है, क्योंकि क्यों संकलक अंतिम उदाहरण में कोड को स्वत: उत्पन्न नहीं करता है। फिर भी, आपने मेरे मूल प्रश्न का उत्तर दिया है। धन्यवाद। –

2

whatIs विधियों में से एक को प्रेषण संकलन समय पर संकलक द्वारा तय किया जाता है। संदर्भित ऑब्जेक्ट की वास्तविक श्रेणी के आधार पर area विधियों में से किसी एक को रनटाइम पर निर्णय लिया जाता है।

5

ऑब्जेक्ट उन्मुख सुविधाओं के साथ जावा, पॉलिमॉर्फिज्म का समर्थन करता है, इसलिए area को कॉल करना विशिष्ट उदाहरण के area विधि को कॉल करेगा, जो भी हो। यह रनटाइम पर निर्धारित है।

हालांकि, यह बहुरूपता ओवरलोडेड विधियों के साथ समर्थित नहीं है। Java Language Specification, Section 8.4.9 इस को शामिल किया गया:

जब एक विधि शुरू हो जाती है (§15.12) वास्तविक तर्क (और किसी भी स्पष्ट प्रकार तर्क) और बहस के संकलन समय प्रकारों की संख्या संकलन समय पर इस्तेमाल कर रहे हैं, , विधि के हस्ताक्षर को निर्धारित करने के लिए जो लागू किया जाएगा (§15.12.2)। यदि लागू होने वाली विधि एक उदाहरण विधि है, तो लागू होने वाली वास्तविक विधि गतिशील विधि लुकअप (§15.12.4) का उपयोग करके रन टाइम पर निर्धारित की जाएगी।

यह ओवरलोडेड विधियों के साथ है, विधि को संकलित समय में संकलित समय प्रकारों का उपयोग करके चुना जाता है, पॉलीमोर्फिज्म के साथ रनटाइम पर नहीं।

1

प्रश्न: जावा कंपाइलर संबंधित वस्तुओं के लिए ओवरराइड विधियों के बीच सटीक रूप से अंतर क्यों कर सकता है, लेकिन ओवरलोडेड विधियों नहीं ... जावा इस तरह की स्थिति को क्यों संभाल नहीं सकता है?

ए: आपको प्रश्न पीछे की ओर मिला है।

जावा ALLOWS आप "ओवरलोडिंग" और "ओवरराइडिंग" के बीच अंतर करने के लिए।

यह अनुमान लगाने की कोशिश नहीं करता कि आप माध्य, यह आपको एक या दूसरे का उपयोग करने का विकल्प देता है।

1

ठीक है, एक मूर्ख जवाब के रूप में, आप ठीक इस तरह से (किसी भी प्रकार की जाँच के बिना) काम करने के लिए

class Shape{ 
    public abstract String whatIs(); 
} 

class Square{ 
    public String whatIs(){ return "Square"; } 
} 
class Circle{ 
    public String whatIs(){ return "Circle"; } 
} 

और फिर उन्हें इस

Shape square = new Square(); 
Shape circle = new Circle(); 

System.out.println(square.whatIs()) //prints 'square' 
System.out.println(circle.whatIs()) //prints 'circle 

नहीं की तरह फोन whatis समारोह मिल सकता है आपके द्वारा पूछे गए प्रश्न के सभी जवाब ... लेकिन मैं विरोध नहीं कर सका।

+0

आप सही हैं कि मैंने यह नहीं पूछा है, लेकिन फिर भी, यह दिलचस्प है और मुझे यकीन है कि यह किसी की मदद करेगा। +1 –

संबंधित मुद्दे