2010-01-19 31 views
33

कोड का नमूना:क्या जावा प्रतिबिंब का उपयोग करके नेस्टेड क्लास का उदाहरण बनाना संभव है?

public class Foo 
{ 
    public class Bar 
    { 
     public void printMesg(String body) 
     { 
      System.out.println(body); 
     } 
    } 
    public static void main(String[] args) 
    { 
     // Creating new instance of 'Bar' using Class.forname - how? 
    }   
} 

यह वर्ग बार इसका नाम मिला है की नया उदाहरण बनाने के लिए संभव है? मैं का उपयोग करने की कोशिश की:

Class c = Class.forName("Foo$Bar") 

यह वर्ग पाता है, लेकिन जब मैं c.newInstance का उपयोग करें() यह InstantiationException फेंकता है।

+4

nitpick:।। कि एक नेस्टेड वर्ग नहीं है, यह एक सदस्य आंतरिक है कक्षा। नेस्टेड क्लास स्थिर हैं, और आपने जिस तंत्र की कोशिश की है, उसे आसानी से तत्काल किया जाता है। – skaffman

+0

'इंस्टेंटेशन एक्सेप्शन' का विवरण क्या था? –

+4

आंतरिक कक्षाएं नेस्टेड क्लास का एक प्रकार है (यदि मुझे जेएलएस शब्दावली सही तरीके से याद है) –

उत्तर

54

ऐसा करने के लिए आपको कुछ हुप्स से कूदने की आवश्यकता है।

एक निर्माता वस्तु निर्दिष्ट सार्वजनिक वर्ग के निर्माता इस क्लास वस्तु द्वारा प्रतिनिधित्व किया दर्शाता है कि रिटर्न: सबसे पहले, आप Class.getConstructor() उपयोग करने के लिए Constructor वस्तु आप आह्वान करना चाहते हैं खोजने की जरूरत है। पैरामीटर टाइप पैरामीटर क्लास ऑब्जेक्ट्स का है जो घोषित आदेश में कन्स्ट्रक्टर के औपचारिक पैरामीटर प्रकार, की पहचान करता है। यदि यह कक्षा ऑब्जेक्ट एक गैर-स्थैतिक संदर्भ में घोषित एक आंतरिक वर्ग का प्रतिनिधित्व करता है, तो औपचारिक पैरामीटर प्रकारों में स्पष्ट संलग्न उदाहरण पहला पैरामीटर शामिल है।

और फिर आप Constructor.newInstance() का उपयोग करें:

तो निर्माता की घोषणा के वर्ग एक गैर स्थिर संदर्भ में एक आंतरिक वर्ग है, निर्माता के लिए पहला तर्क संलग्न किए जाने की जरूरत है उदाहरण

+0

यही मुझे चाहिए। पूर्ण स्पष्टीकरण के लिए धन्यवाद! – kars7e

+0

उत्कृष्ट स्पष्टीकरण! – Jorge

2

हां। याद रखें कि आपको बाहरी उदाहरण को आंतरिक कक्षा में खिलाने की आवश्यकता है। कन्स्ट्रक्टर खोजने के लिए javap का उपयोग करें। बुराई Class.newInstance पर भरोसा करने के बजाय आपको java.lang.reflect.Constructor पर जाना होगा। क्योंकि (-target 1.4 संभालने या बाद में, अब छुपा हुआ) आप सुपर निर्माता (अवैध हुआ करता था) कॉल करने से पहले एक उदाहरण मैदान के एक काम मिल

Compiled from "Foo.java" 
public class Foo$Bar extends java.lang.Object{ 
    final Foo this$0; 
    public Foo$Bar(Foo); 
    public void printMesg(java.lang.String); 
} 

javap -c निर्माता पर दिलचस्प है।

public Foo$Bar(Foo); 
    Code: 
    0: aload_0 
    1: aload_1 
    2: putfield  #1; //Field this$0:LFoo; 
    5: aload_0 
    6: invokespecial #2; //Method java/lang/Object."<init>":()V 
    9: return 
+0

मैंने पहले कभी जवाप के बारे में नहीं सुना है। मुझे अच्छा उपकरण दिखाने के लिए Thx :)। – kars7e

7

त्वरित और गंदे कोड:

Foo.Bar.class.getConstructors()[0].newInstance(new Foo()); 

स्पष्टीकरण: आपको बार को अपने संलग्न फू के बारे में बताना होगा।

+1

यह गंदा है, लेकिन यह छोटा है और साथ ही काम करता है :)। धन्यवाद। – kars7e

+0

जो अधिकांश समस्या को बढ़ाता है क्योंकि बार स्थिर नहीं हो सकता है और/या यहां तक ​​कि दिखाई नहीं दे सकता है ... – Snicolas

+2

एर्म, मेरा जवाब मानता है कि कक्षा स्थिर नहीं है? और यदि कक्षा अदृश्य थी तो ओपी को अवैध त्रुटि प्राप्त होगी, एक इंस्टेंटेशन अपवाद नहीं ... – meriton

25

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

यहां एक SSCCE है जो सभी चीजों को प्रदर्शित करता है।

package mypackage; 

import java.lang.reflect.Modifier; 

public class Parent { 

    public static class Nested { 
     public Nested() { 
      System.out.println("Nested constructed"); 
     } 
    } 

    public class Inner { 
     public Inner() { 
      System.out.println("Inner constructed"); 
     } 
    } 

    public static void main(String... args) throws Exception { 
     // Construct nested class the normal way: 
     Nested nested = new Nested(); 

     // Construct inner class the normal way: 
     Inner inner = new Parent().new Inner(); 

     // Construct nested class by reflection: 
     Class.forName("mypackage.Parent$Nested").newInstance(); 

     // Construct inner class by reflection: 
     Object parent = Class.forName("mypackage.Parent").newInstance(); 
     for (Class<?> cls : parent.getClass().getDeclaredClasses()) { 
      if (!Modifier.isStatic(cls.getModifiers())) { 
       // This is an inner class. Pass the parent class in. 
       cls.getDeclaredConstructor(new Class[] { parent.getClass() }).newInstance(new Object[] { parent }); 
      } else { 
       // This is a nested class. You can also use it here as follows: 
       cls.getDeclaredConstructor(new Class[] {}).newInstance(new Object[] {}); 
      } 
     } 
    } 
} 

यह उत्पादन चाहिए

 
Nested constructed 
Inner constructed 
Nested constructed 
Inner constructed 
Nested constructed 
+2

उत्कृष्ट और पूर्ण उदाहरण! – Jorge

1

अन्य उत्तर तुम क्या आप क्या करना चाहते कैसे कर सकते हैं समझा दिया है।

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

एक (गैर स्थैतिक) आंतरिक वर्ग उदाहरण बनाना प्रतिबिंबित रूप से टूटा encapsulation की "गंध" है।

-1

यहाँ नेस्टेड वर्ग के लिए एक जवाब (स्थिर भीतरी): मेरे मामले में मैं अपनी पूरी तरह से योग्य नाम से प्रकार प्राप्त करने के लिए की जरूरत है

Class.forName(somePackage.innerClass$outerClass).getConstructor().newInstance(); 

'$' महत्वपूर्ण है!

एक डॉट के साथ आपको कक्षा "package.innerClass.outerClass" कक्षा के लिए ClassNotFoundException मिलेगा। अपवाद :-(missleading है

+0

यह संकलित नहीं करता है, न ही 'innerClass $ outerClass' सही का क्रम है ... –

0

यह पूरी तरह से इष्टतम नहीं है, लेकिन यह भीतरी वर्गों और भीतरी स्थिर कक्षाओं की गहराई के लिए काम करता

public <T> T instantiateClass(final Class<T> cls) throws CustomClassLoadException { 
    try { 
     List<Class<?>> toInstantiate = new ArrayList<Class<?>>(); 
     Class<?> parent = cls; 
     while (! Modifier.isStatic(parent.getModifiers()) && parent.isMemberClass()) { 
      toInstantiate.add(parent); 
      parent = parent.getDeclaringClass(); 
     } 
     toInstantiate.add(parent); 
     Collections.reverse(toInstantiate); 
     List<Object> instantiated = new ArrayList<Object>(); 
     for (Class<?> current : toInstantiate) { 
      if (instantiated.isEmpty()) { 
       instantiated.add(current.newInstance()); 
      } else { 
       Constructor<?> c = current.getConstructor(instantiated.get(instantiated.size() - 1).getClass()); 
       instantiated.add(c.newInstance(instantiated.get(instantiated.size() - 1))); 
      } 
     } 
     return (T) instantiated.get(instantiated.size() - 1); 
    } catch (InstantiationException e) { 
     throw new CustomClassLoadException("Failed to load class.", e); 
    } catch (IllegalAccessException e) { 
     throw new CustomClassLoadException("Failed to load class.", e); 
    } catch (SecurityException e) { 
     throw new CustomClassLoadException("Failed to load class.", e); 
    } catch (NoSuchMethodException e) { 
     throw new CustomClassLoadException("Failed to load class.", e); 
    } catch (IllegalArgumentException e) { 
     throw new CustomClassLoadException("Failed to load class.", e); 
    } catch (InvocationTargetException e) { 
     throw new CustomClassLoadException("Failed to load class.", e); 
    } 
} 
संबंधित मुद्दे