जावा: एक फ़ाइल में कई वर्ग घोषणाएँ


238

जावा में, आप एक फ़ाइल में कई शीर्ष स्तर की कक्षाओं को परिभाषित कर सकते हैं, बशर्ते कि इनमें से अधिकांश सार्वजनिक है (देखें JLS6.6 देखें )। उदाहरण के लिए नीचे देखें।

  1. वहाँ इस तकनीक के लिए एक साफ नाम (के अनुरूप है inner, nested, anonymous)?

  2. जेएलएस का कहना है कि प्रणाली प्रतिबंध को लागू कर सकती है कि ये माध्यमिक कक्षाएं नहीं हो सकती हैं referred to by code in other compilation units of the package, उदाहरण के लिए, उन्हें पैकेज-निजी के रूप में नहीं माना जा सकता है। क्या वास्तव में कुछ ऐसा है जो जावा कार्यान्वयन के बीच बदलता है?

उदाहरण के लिए, PublicClass.java:

package com.example.multiple;

public class PublicClass {
    PrivateImpl impl = new PrivateImpl();
}

class PrivateImpl {
    int implementationData;
}

11
+1 अच्छे प्रश्न। मैंने वास्तव में कभी भी इस मामले पर ज्यादा विचार नहीं किया है, क्योंकि ऐसा करना लगभग आवश्यक नहीं है।
माइकल मायर्स

12
ध्यान दें कि यह एक शातिर विशेषता है; यह संभव नहीं होता अगर जावा में शुरू से ही नेस्टेड कक्षाएं होतीं।
केविन बोर्रिलियन

जवाबों:


120

इस तकनीक के लिए मेरा सुझाया गया नाम (एकल स्रोत फ़ाइल में कई शीर्ष-स्तरीय कक्षाएं सहित) "गड़बड़" होगा। सच में, मुझे नहीं लगता कि यह एक अच्छा विचार है - मैं इस स्थिति में एक नेस्टेड प्रकार का उपयोग करूंगा। फिर यह अनुमान लगाना अभी भी आसान है कि यह किस स्रोत फ़ाइल में है। मुझे विश्वास नहीं है कि इस दृष्टिकोण के लिए एक आधिकारिक शब्द है।

के रूप में कि क्या यह वास्तव में कार्यान्वयन के बीच बदलता है - मुझे इस पर बहुत संदेह है, लेकिन अगर आप इसे पहली जगह में करने से बचते हैं, तो आपको कभी भी देखभाल करने की आवश्यकता नहीं होगी :)


71
मैं नीच नहीं हूं, लेकिन तथ्य यह है कि यह उत्तर कुछ ऐसा है जिसे "मानदंड" कहा जा सकता है (यानी। "आपको" वास्तव में "के बजाय ... हालांकि ...") इसके लिए सबसे अधिक संभावित कारण है। मुझे लगता है कि एक अपमान मिलता है। यह वास्तव में किसी भी प्रश्न का उत्तर नहीं देता है। जैसे किसी चीज को वापस करने के बजाय एक अप्रासंगिक अपवाद को उठाना / एक अपवाद को उठाना, जिसमें विचारों के बजाय वास्तविक तथ्यों के बारे में जानकारी हो।
n611x007

6
मैंने पाया कि मुझे लगता है कि एक नेस्टेड प्रकार का उपयोग करने के लिए @JonSkeet के सुझाव का एक मामूली अपवाद है (जिसे मैं अन्यथा सहमत हूं): यदि मुख्य वर्ग सामान्य है और टाइप पैरामीटर दूसरा वर्ग है, तो दूसरा वर्ग नहीं कर सकता नेस्टेड हो। और अगर दो वर्गों को कसकर युग्मित किया जाता है (जैसे पब्लिकक्लास और प्रश्न में PrivateImpl), तो मुझे लगता है कि PrivateImpl को एक ही फाइल में एक शीर्ष-स्तरीय वर्ग के रूप में रखना एक अच्छा विचार है।
jfritz42

6
@BoomerRogers: नहीं, यह निश्चित रूप से है नहीं "घटक आधारित प्रोग्रामिंग के मुख्य आधार"। यदि आप एक घटक के खिलाफ प्रोग्रामिंग कर रहे हैं, तो आप यह क्यों ध्यान रखेंगे कि स्रोत कोड कैसे व्यवस्थित है? (व्यक्तिगत रूप से मैं सेवा लोकेटर पैटर्न के बजाय निर्भरता इंजेक्शन पसंद करता हूं , लेकिन यह एक अलग मामला है।) अपने दिमाग में अलग एपीआई और स्रोत कोड संगठन - वे बहुत अलग चीजें हैं।
जॉन स्कीट

1
@JonSkeet मुझे rephrase: आपका "जवाब" एक व्यक्तिगत अप्रासंगिक राय है। (यानी "गड़बड़" और "मुझे शक है" जैसे जवाबों का बहुत कम मूल्य है।) इसलिए, आपकी पोस्ट 2 में से किसी भी प्रश्न का उत्तर नहीं देती है। पॉलीजेनिल लुब्रिकेंट्स के उत्तर की जाँच करें, और आप देखेंगे कि वह दोनों का उत्तर देने का प्रबंधन करता है।
bvdb

1
@ बीवीडीबी: (और बहुत सी चीजें हैं जो खराब प्रैक्टिस हैं लेकिन ऐनक द्वारा अनुमति दी जाती है। मैं लोगों से आग्रह करूंगा कि वे public int[] foo(int x)[] { return new int[5][5]; }भले ही वैध क्यों न हों।)
जॉन स्कीट

130

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

मान लीजिए कि आपके पास दो फाइलें हैं, Foo.java और Bar.java।

Foo.java में शामिल हैं:

  • सार्वजनिक वर्ग फू

Bar.java में शामिल हैं:

  • सार्वजनिक वर्ग बार
  • कक्षा बाज

यह भी कहते हैं कि सभी कक्षाएं एक ही पैकेज में हैं (और फाइलें एक ही निर्देशिका में हैं)।

अगर Foo.java बाज को नहीं बल्कि बार को संदर्भित करता है और हम Foo.java को संकलित करने की कोशिश करते हैं तो क्या होगा? इस तरह एक त्रुटि के साथ संकलन विफल रहता है:

Foo.java:2: cannot find symbol
symbol  : class Baz
location: class Foo
  private Baz baz;
          ^
1 error

यह समझ में आता है अगर आप इसके बारे में सोचते हैं। यदि Foo.java Baz को संदर्भित करता है, लेकिन कोई Baz.java (या Baz.class) नहीं है, तो javac को कैसे पता चल सकता है कि किस स्रोत फ़ाइल को देखना है?

यदि आप इसके बजाय एक ही समय में Foo.java और Bar.java को संकलित करने के लिए javac को बताते हैं, या यहां तक ​​कि अगर आपने पहले Bar.java को संकलित किया था (Baz.class को छोड़कर जहाँ javac इसे पा सकते हैं) तो यह त्रुटि दूर हो जाती है। यह आपकी निर्माण प्रक्रिया को बहुत अविश्वसनीय और परतदार बनाता है, हालाँकि।

क्योंकि वास्तविक सीमा, जो अधिक पसंद है "किसी अन्य फ़ाइल से एक शीर्ष-स्तरीय वर्ग का उल्लेख न करें जब तक कि उसका नाम उसी फ़ाइल के रूप में न हो या आप उस वर्ग का भी उल्लेख कर रहे हैं जो उसी फ़ाइल में है जिसका नाम है फ़ाइल के रूप में एक ही बात "पालन करने के लिए कठिन है, लोग आमतौर पर प्रत्येक फ़ाइल में सिर्फ एक शीर्ष स्तर के वर्ग को रखने के लिए बहुत अधिक सरल (हालांकि सख्त) सम्मेलन के साथ जाते हैं। यह भी बेहतर है कि क्या आप कभी इस बारे में अपना विचार बदलते हैं कि कोई वर्ग सार्वजनिक होना चाहिए या नहीं।

कभी-कभी वास्तव में एक अच्छा कारण है कि हर कोई किसी विशेष तरीके से कुछ क्यों करता है।


क्या संकलन को विश्वसनीय बनाने के लिए मावेन कुछ करता है?
डबिन्स्की

23

मेरा मानना ​​है कि आप बस PrivateImplयह कहते हैं कि यह क्या है: ए non-public top-level class। आप भी घोषित कर सकते हैं non-public top-level interfaces

उदाहरण के लिए, SO पर कहीं और: गैर-सार्वजनिक शीर्ष-स्तरीय वर्ग बनाम स्थिर नेस्टेड वर्ग

संस्करणों के बीच व्यवहार में बदलाव के लिए, 1.2.2 में "पूरी तरह से काम किया" कुछ के बारे में यह चर्चा थी। लेकिन सूरज के मंच में 1.4 में काम करना बंद कर दिया: जावा कंपाइलर - एक फाइल में गैर सार्वजनिक शीर्ष स्तर की कक्षाओं की घोषणा करने में असमर्थ


1
इसके साथ मेरा एकमात्र मुद्दा यह है कि आपके पास non-public top level classफ़ाइल में एकमात्र वर्ग हो सकता है, इसलिए यह बहुलता को संबोधित नहीं करता है।
माइकल ब्रूवर-डेविस

मैं चिंता को समझता हूं, लेकिन जैसा कि आप देख सकते हैं कि यह एक शब्दावली है जिसका दूसरों ने ऐतिहासिक उपयोग किया है। अगर मुझे अपना कार्यकाल खुद बनाना है, तो मैं शायद इसे बुलाऊंगा secondary top level types
polygenelubricants

7

आप इस तरह से जितनी चाहें उतनी कक्षाएं लगा सकते हैं

public class Fun {
    Fun() {
        System.out.println("Fun constructor");
    }
    void fun() {
        System.out.println("Fun mathod");
    }
    public static void main(String[] args) {
        Fun fu = new Fun();
        fu.fun();
        Fen fe = new Fen();
        fe.fen();
        Fin fi = new Fin();
        fi.fin();
        Fon fo = new Fon();
        fo.fon();
        Fan fa = new Fan();
        fa.fan();
        fa.run();
    }
}

class Fen {
    Fen() {
        System.out.println("fen construuctor");

    }
    void fen() {
        System.out.println("Fen method");
    }
}

class Fin {
    void fin() {
        System.out.println("Fin method");
    }
}

class Fon {
    void fon() {
        System.out.println("Fon method");
    } 
}

class Fan {
    void fan() {
        System.out.println("Fan method");
    }
    public void run() {
        System.out.println("run");
    }
}

1
@Nenotlep जब आप "सुधार स्वरूपण" करते हैं, तो कृपया यह भी ध्यान रखें कि यह कोड के साथ ही गड़बड़ी नहीं करता है, जैसे बैकस्लैश निकालना।
टॉम

3
इस सवाल का जवाब नहीं है।

4

1. इस तकनीक के लिए एक साफ नाम है (आंतरिक, नेस्टेड, अनाम के अनुरूप)?

मल्टी-क्लास सिंगल-फाइल डेमो।

2. जेएलएस का कहना है कि प्रणाली प्रतिबंध को लागू कर सकती है कि इन माध्यमिक कक्षाओं को पैकेज के अन्य संकलन इकाइयों में कोड द्वारा संदर्भित नहीं किया जा सकता है, उदाहरण के लिए, उन्हें पैकेज-निजी के रूप में नहीं माना जा सकता है। क्या वास्तव में कुछ ऐसा है जो जावा कार्यान्वयन के बीच बदलता है?

मैं किसी भी ऐसे व्यक्ति के बारे में नहीं जानता, जिसके पास वह प्रतिबंध नहीं है - सभी फ़ाइल आधारित कंपाइलर आपको उन फ़ाइलों में स्रोत कोड कक्षाओं को संदर्भित करने की अनुमति नहीं देंगे, जिन्हें कक्षा के नाम के समान नहीं रखा गया है। (यदि आप एक बहु-श्रेणी फ़ाइल संकलित करते हैं, और कक्षाओं को वर्ग पथ पर डालते हैं, तो कोई भी संकलक उन्हें ढूंढ लेगा)


1

प्रभावी जावा 2 संस्करण के अनुसार (आइटम 13):

"यदि एक पैकेज-निजी शीर्ष-स्तरीय वर्ग (या इंटरफ़ेस) का उपयोग केवल एक वर्ग द्वारा किया जाता है, तो शीर्ष-स्तरीय वर्ग को एकमात्र कक्षा का एक निजी नेस्टेड वर्ग बनाने पर विचार करें जो इसका उपयोग करता है (आइटम 22)। यह सभी तक इसकी पहुंच को कम करता है। इसका उपयोग करने वाले एक वर्ग के लिए इसके पैकेज में कक्षाएं। लेकिन यह एक पैकेज-निजी शीर्ष-स्तरीय वर्ग की तुलना में बहुत अधिक सार्वजनिक रूप से सार्वजनिक वर्ग की पहुंच को कम करने के लिए महत्वपूर्ण है: ... "

नेस्टेड क्लास स्थैतिक या गैर-स्थैतिक हो सकता है, जिसके आधार पर सदस्य वर्ग को एन्क्लोजिंग इंस्टेंस (आइटम 22) तक पहुंचने की आवश्यकता होती है।


ओपी नेस्टेड वर्गों के बारे में नहीं पूछ रहा है।
charmoniumQ

0

हां आप बाहरी सार्वजनिक वर्ग के सार्वजनिक स्थैतिक सदस्यों के साथ ऐसा कर सकते हैं, जैसे:

public class Foo {

    public static class FooChild extends Z {
        String foo;
    }

    public static class ZeeChild extends Z {

    }

}

और एक अन्य फ़ाइल जो उपरोक्त संदर्भ देती है:

public class Bar {

    public static void main(String[] args){

        Foo.FooChild f = new Foo.FooChild();
        System.out.println(f);

    }
}

उन्हें एक ही फ़ोल्डर में रखें। संकलन:

javac folder/*.java

और साथ चले:

 java -cp folder Bar

वह उदाहरण प्रश्न का उत्तर नहीं देता है। आप नेस्टेड स्टैटिक क्लासेस का एक उदाहरण दे रहे हैं, जो एक ही फाइल में परिभाषित दो टॉप लेवल क्लास के समान नहीं है।
पेड्रो गार्सिया मदीना

0

बस FYI करें, यदि आप जावा 11+ का उपयोग कर रहे हैं, तो इस नियम का एक अपवाद है: यदि आप अपनी जावा फ़ाइल को सीधे ( बिना कम्पाइल किए ) चलाते हैं । इस मोड में, प्रति फ़ाइल एक सार्वजनिक वर्ग पर कोई प्रतिबंध नहीं है। हालाँकि, mainविधि वाला वर्ग फ़ाइल में पहला होना चाहिए।


-5

नहीं। आप नहीं कर सकते। लेकिन यह स्काला में बहुत संभव है:

class Foo {val bar = "a"}
class Bar {val foo = "b"}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.