मैं अपने सुपर () कॉल के आसपास एक कोशिश ब्लॉक का उपयोग क्यों नहीं कर सकता?

तो, जावा में, आपके कन्स्ट्रक्टर की पहली पंक्ति सुपर को कॉल करने के लिए है ... इसे स्पष्ट रूप से सुपर (), या स्पष्ट रूप से दूसरे कन्स्ट्रक्टर को कॉल करना। मैं क्या जानना चाहता हूं, मैं इसके चारों ओर एक कोशिश क्यों नहीं कर सकता?

मेरा विशिष्ट मामला यह है कि मेरे पास एक परीक्षण के लिए नकली कक्षा है। कोई डिफ़ॉल्ट कन्स्ट्रक्टर नहीं है, लेकिन मैं चाहता हूं कि कोई परीक्षण को पढ़ने के लिए आसान बनाये। मैं कन्स्ट्रक्टर से एक रनटाइम अपवाद में फेंकने वाले अपवादों को भी लपेटना चाहता हूं।

तो, मैं क्या करना चाहता हूं प्रभावी रूप से यह है:

public class MyClassMock extends MyClass {
    public MyClassMock() {
        try {
            super(0);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // Mocked methods
}

लेकिन जावा शिकायत करता है कि सुपर पहला कथन नहीं है।

मेरा कामकाज:

public class MyClassMock extends MyClass {
    public static MyClassMock construct() {
        try {
            return new MyClassMock();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public MyClassMock() throws Exception {
        super(0);
    }

    // Mocked methods
}

क्या यह सबसे अच्छा कामकाज है? जावा ने मुझे पूर्व क्यों नहीं किया?


"क्यों" के रूप में मेरा सबसे अच्छा अनुमान यह है कि जावा मुझे संभावित असंगत स्थिति में एक निर्मित वस्तु नहीं देना चाहता है ... हालांकि, एक नकली करने में, मुझे इसकी परवाह नहीं है। ऐसा लगता है कि मुझे उपर्युक्त करने में सक्षम होना चाहिए ... या कम से कम मुझे पता है कि उपरोक्त मेरे मामले के लिए सुरक्षित है ... या ऐसा लगता है कि यह वैसे भी होना चाहिए।

मैं परीक्षण वर्ग से उपयोग की जाने वाली किसी भी विधि को ओवरराइड कर रहा हूं, इसलिए कोई जोखिम नहीं है कि मैं अनियमित चर का उपयोग कर रहा हूं।

0
ro fr bn
क्या आप वाकई बाइटकोड अभी भी वैध हैं? मुझे लगता है कि मैंने नीचे दिखाए गए परिणामी सुरक्षा छेद का शोषण करने के बाद इसे अवैध कर दिया है।
जोड़ा लेखक Joshua, स्रोत
एक दिलचस्प नोट यह है कि यह पूरी तरह से एक जावा भाषा सीमा है। समकक्ष बाइटकोड पूरी तरह से मान्य है।
जोड़ा लेखक Antimony, स्रोत
क्योंकि नियम इसे अनुमति नहीं देते हैं। JDK spec पढ़ें । यहां तक ​​कि यदि आप कंपाइलर से पहले प्राप्त करते हैं तो सत्यापनकर्ता इसे अस्वीकार कर देगा।
जोड़ा लेखक Hot Licks, स्रोत

7 उत्तर

मैं जावा इंटर्नल की गहरी समझ रखने के लिए अनुमान नहीं लगा सकता, लेकिन यह मेरी समझ है कि, जब एक कंपाइलर को व्युत्पन्न वर्ग को तुरंत चालू करने की आवश्यकता होती है, तो उसे पहले आधार बनाना होगा (और इसके पहले उसका आधार (...)) और उसके बाद उपclass में किए गए एक्सटेंशन पर थप्पड़ मारो।

तो यह असीमित चर या किसी भी तरह का खतरा भी नहीं है। जब आप उप वर्ग 'कन्स्ट्रक्टर से पहले बेस क्लास' कन्स्ट्रक्टर में कुछ करने का प्रयास करते हैं, तो आप मूल रूप से कंपाइलर को बेस ऑब्जेक्ट इंस्टेंस का विस्तार करने के लिए कह रहे हैं जो अभी तक मौजूद नहीं है ।

संपादित करें: आपके मामले में, MyClass मूल ऑब्जेक्ट बन जाता है, और MyClassMock उप-वर्ग है।

0
जोड़ा

मुझे नहीं पता कि जावा को आंतरिक रूप से कैसे कार्यान्वित किया जाता है, लेकिन अगर सुपरक्लास के निर्माता एक अपवाद फेंकते हैं, तो आपके द्वारा विस्तारित कक्षा का एक उदाहरण नहीं है। उदाहरण के लिए, toString() या equals() विधियों को कॉल करना असंभव होगा, क्योंकि अधिकांश मामलों में उन्हें विरासत में मिला है।

जावा कन्स्ट्रक्टर में सुपर() कॉल के चारों ओर कोशिश / पकड़ने की अनुमति दे सकता है यदि आप सुपरक्लास से सभी विधियों को ओवरराइड करते हैं, और 2. आप super.XXX() खंड का उपयोग नहीं करते हैं, लेकिन यह सब बहुत जटिल लगता है मुझे।

0
जोड़ा

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

दूसरे शब्दों में, संकलक सिर्फ आपको रोक नहीं रहा है, यह सभी को रोक रहा है, जिनमें वे सभी नहीं हैं जो यह नहीं जानते कि यह असुरक्षित है और विशेष हैंडलिंग की आवश्यकता है। इसके लिए शायद अन्य कारण भी हैं, क्योंकि सभी भाषाओं में आम तौर पर असुरक्षित चीजें करने का तरीका होता है यदि कोई जानता है कि उनके साथ कैसे निपटना है।

सी # .NET में समान प्रावधान हैं, और आधार निर्माता को कॉल करने वाले निर्माता को घोषित करने का एकमात्र तरीका यह है:

public ClassName(...) : base(...)

ऐसा करने में, बेस कन्स्ट्रक्टर को कन्स्ट्रक्टर के शरीर से पहले बुलाया जाएगा, और आप इस ऑर्डर को नहीं बदल सकते हैं।

0
जोड़ा
कैच ब्लॉक में इसका उपयोग करने से आपको क्यों न रोकें? इसमें रैपिंग अपवादों के सामान्य मामले को शामिल किया गया है।
जोड़ा लेखक Antimony, स्रोत

किसी को अविश्वसनीय कोड से नया SecurityManager ऑब्जेक्ट बनाने से रोकने के लिए किया जाता है।

public class Evil : SecurityManager {
  Evil()
  {
      try {
         super();
      } catch { Throwable t }
      {
      }
   }
}
0
जोड़ा

इसके चारों ओर जाने का एक तरीका एक निजी स्थैतिक कार्य को बुलाकर है। फिर कोशिश करने के लिए समारोह शरीर में कोशिश की जा सकती है।

public class Test  {
  public Test()  {
     this(Test.getObjectThatMightThrowException());
  }
  public Test(Object o)  {
     //...
  }
  private static final Object getObjectThatMightThrowException()  {
     try  {
        return  new ObjectThatMightThrowAnException();
     }  catch(RuntimeException rtx)  {
        throw  new RuntimeException("It threw an exception!!!", rtx);
     }
  }
}
0
जोड़ा
मैंने थोड़ा सा विस्तार किया। बस ए?
जोड़ा लेखक aliteralmind, स्रोत
विस्तृत करने की देखभाल क्यों?
जोड़ा लेखक Unheilig, स्रोत
एक निजी स्थैतिक समारोह क्यों बुला रहा है यहाँ काम करता है? और ओपी द्वारा कोड के साथ क्या गलत है जो आपको लगता है कि काम नहीं करता है?
जोड़ा लेखक Unheilig, स्रोत
सवाल विरासत के बारे में पूछा गया, और इस कोड में इसके बजाय संरचना है
जोड़ा लेखक Daniel Pinyol, स्रोत

मुझे पता है कि यह एक पुराना सवाल है, लेकिन मुझे यह पसंद आया, और इस तरह, मैंने इसे अपने उत्तर देने का फैसला किया। शायद मेरी समझ यह क्यों नहीं की जा सकती है चर्चा और आपके रोचक प्रश्न के भविष्य के पाठकों में योगदान देगा।

मुझे ऑब्जेक्ट निर्माण विफल करने के उदाहरण के साथ शुरू करते हैं।

आइए कक्षा ए को परिभाषित करें, जैसे कि:

class A {
   private String a = "A";

   public A() throws Exception {
        throw new Exception();
   }
}

अब, मान लीजिए कि हम <ए> कोशिश करें ... पकड़ें ब्लॉक में टाइप ए का ऑब्जेक्ट बनाना चाहते हैं।

A a = null;
try{
  a = new A();
}catch(Exception e) {
  //...
}
System.out.println(a);

जाहिर है, इस कोड का आउटपुट होगा: null

जावा का आंशिक रूप से निर्मित संस्करण क्यों नहीं लौटाता है? आखिरकार, निर्माता द्वारा विफलता विफल हो जाती है, ऑब्जेक्ट का name फ़ील्ड पहले ही शुरू हो चुका है, है ना?

खैर, जावा का आंशिक रूप से निर्मित संस्करण वापस नहीं कर सकता क्योंकि ऑब्जेक्ट सफलतापूर्वक बनाया नहीं गया था। वस्तु एक असंगत स्थिति में है, और इसलिए इसे जावा द्वारा त्याग दिया जाता है। आपका वैरिएबल ए भी शुरू नहीं हुआ है, इसे शून्य के रूप में रखा जाता है।

अब, जैसा कि आप जानते हैं, पूरी तरह से एक नई वस्तु का निर्माण करने के लिए, इसके सभी सुपर क्लास पहले शुरू किए जाने चाहिए। यदि सुपर वर्गों में से एक निष्पादित करने में असफल रहा, तो ऑब्जेक्ट की अंतिम स्थिति क्या होगी? यह निर्धारित करना असंभव है।

इस और अधिक विस्तृत उदाहरण को देखो

class A {
   private final int a;
   public A() throws Exception { 
      a = 10;
   }
}

class B extends A {
   private final int b;
   public B() throws Exception {
       methodThatThrowsException(); 
       b = 20;
   }
}

class C extends B {
   public C() throws Exception { super(); }
}

जब सी का कन्स्ट्रक्टर लागू होता है, तो B प्रारंभ करते समय कोई अपवाद होता है, तो अंतिम int variable का मान क्या होगा ख ?

इस प्रकार, ऑब्जेक्ट सी नहीं बनाया जा सकता है, यह फर्जी है, यह कचरा है, यह पूरी तरह से शुरू नहीं हुआ है।

मेरे लिए, यह बताता है कि आपका कोड अवैध क्यों है।

0
जोड़ा

मुझे पता है कि इस प्रश्न में कई जवाब हैं, लेकिन मैं अपनी छोटी सी बात देना चाहता हूं कि इसकी अनुमति क्यों नहीं दी जाएगी, विशेष रूप से यह जवाब देने के लिए कि जावा आपको ऐसा करने की अनुमति क्यों नहीं देता है। तो यहाँ आप जाओ ...

अब, ध्यान रखें कि super() को सबक्लास के कन्स्ट्रक्टर में किसी और चीज़ से पहले बुलाया जाना चाहिए, इसलिए, यदि आपने try और catch अपने super() कॉल के आस-पास ब्लॉक करें, ब्लॉक को इस तरह दिखना होगा:

try {
   super();
   ...
} catch (Exception e) {
   super(); //This line will throw the same error...
   ...
}

यदि सुपर() ब्लॉक में विफल रहता है, तो इसे पहले पकड़ ब्लॉक में निष्पादित किया जाना है, ताकि super पहले चलाया जा सके आपके उपclass के कन्स्ट्रक्टर में कुछ भी। यह आपको शुरुआत में उसी समस्या के साथ छोड़ देता है: यदि कोई अपवाद फेंक दिया जाता है, तो यह पकड़ा नहीं जाता है। (इस मामले में यह पकड़ ब्लॉक में फिर से फेंक दिया जाता है।)

अब, उपर्युक्त कोड जावा द्वारा किसी भी तरह से अनुमति नहीं है। यह कोड पहले सुपर कॉल का आधा निष्पादित कर सकता है, और उसके बाद इसे फिर से कॉल कर सकता है, जो कुछ सुपर क्लास के साथ कुछ समस्याएं पैदा कर सकता है।

अब, कारण यह है कि जावा आपको super() को कॉल करने के बजाय इसके बजाय अपवाद फेंकने का कारण नहीं है क्योंकि अपवाद कहीं और पकड़ा जा सकता है, और प्रोग्राम जारी रहेगा < मजबूत> अपने उपclass ऑब्जेक्ट पर super() को कॉल किए बिना और संभवतः क्योंकि अपवाद आपके ऑब्जेक्ट को पैरामीटर के रूप में ले सकता है और विरासतित आवृत्ति चर के मान को बदलने का प्रयास करता है, जो अभी तक नहीं होगा शुरू किया गया है।

0
जोड़ा