जावा: सबपैकेज दृश्यता?


150

मेरी परियोजना में मेरे दो पैकेज हैं: odp.projऔर odp.proj.test। कुछ विधियाँ हैं जो मैं इन दो पैकेजों में केवल कक्षाओं में ही देखना चाहता हूँ। मैं यह कैसे कर सकता हूँ?

EDIT: यदि जावा में किसी सबपैकेज की कोई अवधारणा नहीं है, तो क्या इसका कोई तरीका है? मेरे पास कुछ विधियाँ हैं जो मैं केवल परीक्षक और उस पैकेज के अन्य सदस्यों के लिए उपलब्ध होना चाहता हूँ। क्या मुझे बस एक ही पैकेज में सब कुछ फेंक देना चाहिए? व्यापक प्रतिबिंब का उपयोग करें?




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

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

जवाबों:


165

आप नहीं कर सकते। जावा में एक सबपैकेज की कोई अवधारणा नहीं है, इसलिए odp.projऔर odp.proj.testपूरी तरह से अलग पैकेज हैं।


10
हालांकि मुझे यह इस तरह से पसंद है, यह भ्रमित कर रहा है कि अधिकांश आईडीई एक साथ एक ही नाम के साथ पैकेज डालते हैं। स्पष्टीकरण के लिए धन्यवाद।
जैकसोफ़ 1

यह कड़ाई से सटीक नहीं है: जेएलएस उप- पैकेज को परिभाषित करता है, हालांकि उनके पास एकमात्र भाषा का महत्व है "एक शीर्ष स्तर के प्रकार के समान सरल नाम के साथ एक उप-पैकेज वाले पैकेज के खिलाफ" निषेध करना। मैंने इस प्रश्न का उत्तर विस्तार से बताते हुए अभी-अभी जोड़ा है।
एम। जस्टिन

59

आपके पैकेज के नाम संकेत देते हैं कि यहां आवेदन इकाई परीक्षण के लिए है। विशिष्ट पैटर्न का उपयोग उन कक्षाओं को करने के लिए किया जाता है जिन्हें आप परीक्षण करना चाहते हैं और यूनिट टेस्ट कोड एक ही पैकेज में (आपके मामले में odp.proj) लेकिन विभिन्न स्रोत पेड़ों में। इसलिए आप अपनी कक्षाओं को src/odp/projऔर अपने परीक्षण कोड में डालेंगे test/odp/proj

जावा में "पैकेज" एक्सेस मॉडिफायर है जो डिफ़ॉल्ट एक्सेस संशोधक है जब कोई भी निर्दिष्ट नहीं होता है (यानी आप सार्वजनिक, निजी या संरक्षित निर्दिष्ट नहीं करते हैं)। "पैकेज" एक्सेस संशोधक के साथ, केवल कक्षाओं में odp.projविधियों तक पहुंच होगी। लेकिन ध्यान रखें कि जावा में, एक्सेस मॉडिफायर का उपयोग नियमों को लागू करने पर निर्भर नहीं किया जा सकता है क्योंकि प्रतिबिंब के साथ, कोई भी एक्सेस संभव है। पहुँच संशोधक केवल विचारोत्तेजक हैं (जब तक कि एक प्रतिबंधक सुरक्षा प्रबंधक मौजूद नहीं है)।


11

यह कोई विशेष संबंध नहीं है odp.projऔर odp.proj.test- वे केवल स्पष्ट रूप से संबंधित के रूप में नामित होने के लिए होते हैं।

यदि odp.proj.test पैकेज केवल परीक्षण प्रदान कर रहा है तो आप एक ही पैकेज नाम ( odp.proj) का उपयोग कर सकते हैं । ग्रहण और नेटबीन्स जैसे आईडीई एक ही पैकेज के नाम के साथ, लेकिन JUnit शब्दार्थ के साथ अलग फ़ोल्डर ( src/main/java/odp/projऔर src/test/java/odp/proj) बनाएंगे ।

ध्यान दें कि ये आईडीई तरीकों के लिए परीक्षण उत्पन्न करेंगे odp.projऔर इसमें मौजूद परीक्षण विधियों के लिए उपयुक्त फ़ोल्डर नहीं बनाएंगे।


5

जब मैं इंटेलीज में ऐसा करता हूं, तो मेरा स्रोत पेड़ इस तरह दिखता है:

src         // source root
- odp
   - proj   // .java source here
- test      // test root
  - odp
     - proj // JUnit or TestNG source here

4

संपादित करें: यदि जावा में एक सबपैकेज की कोई अवधारणा नहीं है, तो क्या इसके आसपास कोई रास्ता है? मेरे पास कुछ विधियाँ हैं जो मैं केवल परीक्षक और उस पैकेज के अन्य सदस्यों के लिए उपलब्ध होना चाहता हूँ।

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

इकाई परीक्षणों के लिए, और यदि यह बहुत कुछ फिर से लिखे बिना संभव है, तो उसी पैकेज का उपयोग करने के लिए सुझावों का पालन करें।


3

जैसा कि अन्य लोगों ने समझाया है, जावा में "सबपैकेज" जैसी कोई चीज नहीं है: सभी पैकेज अलग-थलग हैं और उनके माता-पिता से कुछ भी विरासत में नहीं मिला है।

संरक्षित क्लास के सदस्यों को दूसरे पैकेज से एक्सेस करने का एक आसान तरीका है क्लास का विस्तार करना और सदस्यों को ओवरराइड करना।

उदाहरण के लिए, ClassInAपैकेज में पहुंच के लिए a.b:

package a;

public class ClassInA{
    private final String data;

    public ClassInA(String data){ this.data = data; }

    public String getData(){ return data; }

    protected byte[] getDataAsBytes(){ return data.getBytes(); }

    protected char[] getDataAsChars(){ return data.toCharArray(); }
}

उस पैकेज में एक क्लास करें जो आपके लिए आवश्यक तरीकों को ओवरराइड करता है ClassInA:

package a.b;

import a.ClassInA;

public class ClassInAInB extends ClassInA{
    ClassInAInB(String data){ super(data); }

    @Override
    protected byte[] getDataAsBytes(){ return super.getDataAsBytes(); }
}

यह आपको दूसरे पैकेज में कक्षा के स्थान पर ओवरराइडिंग क्लास का उपयोग करने देता है:

package a.b;

import java.util.Arrays;

import a.ClassInA;

public class Driver{
    public static void main(String[] args){
        ClassInA classInA = new ClassInA("string");
        System.out.println(classInA.getData());
        // Will fail: getDataAsBytes() has protected access in a.ClassInA
        System.out.println(Arrays.toString(classInA.getDataAsBytes()));

        ClassInAInB classInAInB = new ClassInAInB("string");
        System.out.println(classInAInB.getData());
        // Works: getDataAsBytes() is now accessible
        System.out.println(Arrays.toString(classInAInB.getDataAsBytes()));
    }
}

ध्यान दें कि यह केवल संरक्षित सदस्यों के लिए काम करता है, जो कि फैली हुई कक्षाओं (इनहेरिटेंस) के लिए दिखाई देते हैं, न कि पैकेज-प्राइवेट सदस्यों के लिए जो केवल एक ही पैकेज के भीतर कक्षाओं को उप / विस्तारित करने के लिए दिखाई देते हैं। उम्मीद है कि यह किसी की मदद करता है!


3

यहाँ ज्यादातर जवाबों में कहा गया है कि जावा में एक सबपैकेज जैसी कोई चीज नहीं है, लेकिन यह कड़ाई से सटीक नहीं है। यह शब्द जावा भाषा विनिर्देश में जावा 6 के रूप में वापस आ गया है, और शायद आगे पीछे (जावा के पुराने संस्करणों के लिए जेएलएस का स्वतंत्र रूप से सुलभ संस्करण नहीं लगता है)। जावा 6 के बाद से JPG में उपपैकेज की भाषा बहुत ज्यादा नहीं बदली है।

जावा 13 जेएलएस :

एक पैकेज के सदस्य इसके उप पैकेज हैं और सभी शीर्ष स्तरीय वर्ग प्रकार और पैकेज के सभी संकलन इकाइयों में घोषित शीर्ष स्तरीय इंटरफ़ेस प्रकार हैं।

उदाहरण के लिए, जावा एसई प्लेटफॉर्म एपीआई में:

  • पैकेज javaसबपैकेज है awt, applet, io, lang, net, और util, लेकिन कोई संकलन इकाइयों।
  • पैकेज java.awtमें उप नाम दिया गया है image, साथ ही कई संकलन इकाइयाँ हैं जिनमें वर्ग और इंटरफ़ेस प्रकार की घोषणाएँ हैं।

उप-पैकेज अवधारणा प्रासंगिक है, जैसा कि संकुल और वर्ग / इंटरफेस के बीच नामकरण की बाधाओं को लागू करता है:

एक पैकेज में एक ही नाम के दो सदस्य या संकलन-समय त्रुटि परिणाम नहीं हो सकते हैं।

यहाँ कुछ उदाहरण हैं:

  • क्योंकि पैकेज java.awtमें एक सबपैकेज है image, यह (या नहीं) नाम के वर्ग या इंटरफ़ेस प्रकार की घोषणा को शामिल नहीं कर सकता है image
  • यदि उस पैकेज में mouseएक नाम और एक सदस्य प्रकार Buttonहै (जिसे तब के रूप में संदर्भित किया जा सकता है mouse.Button), तो पूरी तरह से योग्य नाम के साथ कोई भी पैकेज नहीं हो सकता है mouse.Buttonया नहीं mouse.Button.Click
  • यदि com.nighthacks.java.jagकिसी प्रकार का पूरी तरह से योग्य नाम है, तो कोई भी पैकेज नहीं हो सकता है जिसका पूरी तरह से योग्य नाम com.nighthacks.java.jagया तो है com.nighthacks.java.jag.scrabble

हालाँकि, यह नामकरण प्रतिबंध भाषा द्वारा उप-पैकेजों को दिए जाने वाला एकमात्र महत्व है:

संकुल के लिए पदानुक्रमित नामकरण संरचना पारंपरिक तरीके से संबंधित संकुल के आयोजन के लिए सुविधाजनक है, लेकिन उस पैकेज में घोषित एक शीर्ष स्तर प्रकार के समान सरल नाम के साथ एक उप-पैकेज वाले निषेध के अलावा अपने आप में कोई महत्व नहीं है। ।

उदाहरण के लिए, नाम के एक पैकेज के बीच कोई विशेष पहुँच रिश्ता है oliverऔर एक अन्य पैकेज नामित oliver.twist, या नामित संकुल के बीच evelyn.woodऔर evelyn.waugh। अर्थात्, पैकेज में कोड नाम किसी भी अन्य पैकेज में कोड की तुलना में oliver.twistपैकेज के भीतर घोषित प्रकारों तक बेहतर पहुंच नहीं है oliver


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

किसी भी विधि को सार्वजनिक कर दिया जा सकता है और (सहित सभी संकुल odp.projऔर odp.proj.test) दिया तरीकों का उपयोग करने में सक्षम हो जाएगा, या विधि पैकेज निजी (डिफ़ॉल्ट दृश्यता) बनाया जा सकता है, और सभी कोड सीधे करने के लिए की जरूरत का उपयोग है कि यह में डाल दिया जाना चाहिए विधि के रूप में एक ही (उप) पैकेज।

उस ने कहा, जावा में एक बहुत मानक अभ्यास स्रोत कोड के रूप में एक ही पैकेज में परीक्षण कोड डालना है, लेकिन फ़ाइल सिस्टम पर एक अलग स्थान पर है। उदाहरण के लिए, में Maven निर्माण उपकरण, सम्मेलन में इन स्रोत और परीक्षण फ़ाइलें डाल करने के लिए किया जाएगा src/main/java/odp/projऔर src/test/java/odp/projक्रमश:। जब बिल्ड टूल इसे संकलित करता है, तो फ़ाइलों के दोनों सेट odp.projपैकेज में समाप्त हो जाते हैं , लेकिन केवल srcफाइलें उत्पादन की कलाकृतियों में शामिल होती हैं; उत्पादन फ़ाइलों को सत्यापित करने के लिए परीक्षण फ़ाइलों का उपयोग केवल बिल्ड समय पर किया जाता है। इस सेटअप के साथ, परीक्षण कोड स्वतंत्र रूप से किसी भी पैकेज के निजी या संरक्षित कोड का परीक्षण कर सकता है, क्योंकि वे उसी पैकेज में होंगे।

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


0

एक्सेस मोडिफायर को विधि के सामने रखे बिना आप कहते हैं कि यह पैकेज निजी है।
निम्नलिखित उदाहरण देखें।

package odp.proj;
public class A
{
    void launchA() { }
}

package odp.proj.test;
public class B
{
    void launchB() { }
}

public class Test
{
    public void test()
    {
        A a = new A();
        a.launchA()    // cannot call launchA because it is not visible
    }
}

0

PackageVanishHelper वर्ग के साथ, और PackageVanishHelperFactory जमे हुए से पहले इसे निजी रखें, हम कहीं भी LaunchA (PackageVanishHelper द्वारा) विधि शुरू कर सकते हैं :)

package odp.proj;
public class A
 {
    void launchA() { }
}

public class PackageVisibleHelper {

    private final PackageVisibleHelperFactory factory;

    public PackageVisibleHelper(PackageVisibleHelperFactory factory) {
        super();
        this.factory = factory;
    }

    public void launchA(A a) {
        if (factory == PackageVisibleHelperFactory.INSTNACNE && !factory.isSampleHelper(this)) {
            throw new IllegalAccessError("wrong PackageVisibleHelper ");
        }
        a.launchA();
    }
}


public class PackageVisibleHelperFactory {

    public static final PackageVisibleHelperFactory INSTNACNE = new PackageVisibleHelperFactory();

    private static final PackageVisibleHelper HELPER = new PackageVisibleHelper(INSTNACNE);

    private PackageVisibleHelperFactory() {
        super();
    }

    private boolean frozened;

    public PackageVisibleHelper getHelperBeforeFrozen() {
        if (frozened) {
            throw new IllegalAccessError("please invoke before frozen!");
        }
        return HELPER;
    }

    public void frozen() {
        frozened = true;
    }

    public boolean isSampleHelper(PackageVisibleHelper helper) {
        return HELPER.equals(helper);
    }
}
package odp.proj.test;

import odp.proj.A;
import odp.proj.PackageVisibleHelper;
import odp.proj.PackageVisibleHelperFactory;

public class Test {

    public static void main(String[] args) {

        final PackageVisibleHelper helper = PackageVisibleHelperFactory.INSTNACNE.getHelperBeforeFrozen();
        PackageVisibleHelperFactory.INSTNACNE.frozen();


        A a = new A();
        helper.launchA(a);

        // illegal access       
        new PackageVisibleHelper(PackageVisibleHelperFactory.INSTNACNE).launchA(a); 
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.