2010-08-11 12 views
6

मैं एक नया ClassLoader बना देता हूं और इसे एक नया Class परिभाषित करता हूं, जिसका अर्थ है कि नई कक्षा एक नए नामस्थान में होनी चाहिए, जो यह है, AFAIK। अजीब बात यह है कि, जब मैं नई कक्षा पर Class.getPackage पर कॉल करता हूं, तो यह मेरे मुख्य नामस्थान में किसी भी अन्य वर्ग पर getPackage पर कॉल करके लौटाए गए सटीक वही ऑब्जेक्ट देता है।कक्षा.getPackage अलग-अलग पैकेजों से कक्षाओं के लिए एक ही पैकेज क्यों लौटाता है?

JVM spec के अनुसार

:

एक वर्ग के क्रम पैकेज या इंटरफ़ेस पैकेज नाम और वर्ग या अंतरफलक के निर्णायक वर्ग लोडर से निर्धारित होता है।

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

तो जब मैं ऐसा करता हूं तो मुझे कैसे परिणाम मिलता है मुझे दोनों कक्षाओं पर getPackage से एक ही परिणाम मिलता है?

package pkg; 
import java.io.*; 

// Yes, you can try commenting this class, you'll get the same result. 
class LoadedClass { 
    LoadedClass() { 
     System.out.println("LoadedClass init"); 
    } 
} 

class MyClassLoader extends ClassLoader { 
    Class<?> defineClass(String name, byte[] b) { 
     return defineClass(name, b, 0, b.length); 
    } 
} 

class Main { 
    public static void main(String[] args) throws Exception { 
     MyClassLoader mcl = new MyClassLoader(); 

     // load compiled class from file 
     FileInputStream fileinputstream = new FileInputStream(
      "/home/me/test/pkg/LoadedClass.class" /* <- point to whever these classes 
                * are being compiled to. */ 
     ); 
     int numberBytes = fileinputstream.available(); 
     byte classBytes[] = new byte[numberBytes]; 
     fileinputstream.read(classBytes); 
     fileinputstream.close(); 

     Class<?> lc = mcl.defineClass("pkg.LoadedClass", classBytes); 
     Package myPackage = Main.class.getPackage(); 
     Package lcPackage = lc.getPackage(); 
     System.out.println("lc package: " + lcPackage); 
     System.out.println("my package: " + myPackage); 
     System.out.println("lc ClassLoader: " + lc.getClassLoader()); 
     System.out.println("lc ClassLoader parent: " + 
          lc.getClassLoader().getParent()); 
     System.out.println("my ClassLoader: " + Main.class.getClassLoader()); 
     System.out.println("are they equal? " + (lcPackage == myPackage)); 
     if (lcPackage == myPackage) { 
      System.out.println("okay... we should be able to instantiate " + 
           "the package if that's true, lets try"); 
      lc.newInstance(); // boom as expected 
     } 
    } 
} 

यह आउटपुट:

lc package: package pkg 
my package: package pkg 
lc ClassLoader: [email protected] 
lc ClassLoader parent: [email protected] 
my ClassLoader: [email protected] 
are they equal? true 
okay... we should be able to instantiate the package if that's true, lets try 
Exception in thread "main" java.lang.IllegalAccessException: Class pkg.Main can not access a member of class pkg.LoadedClass with modifiers "" 
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65) 
    at java.lang.Class.newInstance0(Class.java:349) 
    at java.lang.Class.newInstance(Class.java:308) 
    at pkg.Main.main(Main.java:42) 

जैसी उम्मीद थी, आप सामान्य रूप से प्रतिबिंब के माध्यम से इस भरी हुई वर्ग का दृष्टांत नहीं कर सकते, क्योंकि पैकेज-निजी और यह एक में है

यहाँ मेरी परीक्षा है अलग पैकेज (समान नाम, अलग नामस्थान), जो सही AFAIK है, क्योंकि यह प्रकार की सुरक्षा लागू कर रहा है।

बस सोच रहा है क्योंकि मैं पिछले कुछ दिनों में जेवीएम और सुरक्षा वास्तुकला का अध्ययन कर रहा हूं और इस तरह की छोटी सूक्ष्मताएं ढूंढ रहा हूं इसलिए इसका कारण बनाना मुश्किल है।

उत्तर

5

getPackage विधि underspecified है। रिटर्न पैकेज वस्तु इस विशेष वर्ग लोडर में के लिए पैकेज foo परिभाषित,

ClassLoader.getPackage ("foo"), या यदि इस वर्ग लोडर पैकेज foo को परिभाषित नहीं किया: यहाँ क्या bug 4256589 इसके बारे में कहते हैं है विधि देता है कि अभिभावक वर्ग लोडर ने foo, यदि कोई हो, के लिए परिभाषित किया है।

मेरे लिए, यह कहना है कि Package वस्तु getPackage द्वारा दिया कि क्या classloader "परिभाषित" एक कक्षाएं पैकेज ही है, या अगर यह अपनी मूल classloader में उस पैकेज पाया पर निर्भर करता है। और व्यवहार देख रहा है इस के साथ संगत लगता है।

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

+0

हाँ, मूल क्लासलोडर को बुलाया जा रहा था। "लेकिन क्या यह वास्तव में कोई फर्क पड़ता है कि एक पैकेज ऑब्जेक्ट या एकाधिक पैकेज ऑब्जेक्ट्स हैं?"मुझे लगता है कि यह एक दुर्लभ उपयोग-मामला है, लेकिन मैंने जो ओपनजेडके कार्यान्वयन किया है, वह पाठ्यक्रम के प्रतिबिंब में पैकेज चेक करता है, और यह पता चला है कि यह 'GetPackage' –

+0

I को कॉल करने के बजाय क्लासलोडर और पूरी तरह से योग्य नाम की तुलना करता है। अनुमान लगाएं कि यह एक कारण है कि ओएसजीआई लोग 'स्प्लिट पैकेज' (संकुल जो जार फाइलों, बंडलों, क्लासलोडर्स में फैले हुए हैं) से नफरत करते हैं। – Thilo

+0

@ लोंगपोक - मेरा * "क्या यह वास्तव में कोई फर्क पड़ता है ..." * बिंदु यह है कि एक बार जब आप इस विसंगति को समझें कि आप इसके चारों ओर प्रोग्राम कर सकते हैं, जैसे कोड आपको मिला है। –

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