जावा प्रतिबिंब में getFields और getDeclaredFields के बीच अंतर क्या है


195

मैं जावा प्रतिबिंब का उपयोग करते समय getFieldsविधि और विधि के बीच अंतर के बारे में थोड़ा भ्रमित हूं getDeclaredFields

मैंने पढ़ा है कि getDeclaredFieldsआपको कक्षा के सभी क्षेत्रों तक पहुँच प्रदान करता है और यह getFieldsकेवल सार्वजनिक क्षेत्रों को लौटाता है। यदि यह मामला है, तो आप हमेशा उपयोग क्यों नहीं करेंगे getDeclaredFields?

क्या कोई इस बारे में विस्तार से बता सकता है, और दो तरीकों के बीच का अंतर समझा सकता है, और कब / क्यों आप एक दूसरे का उपयोग करना चाहेंगे?


3
getFieldसुपरक्लास से विरासत में मिला क्षेत्र मिल सकता है लेकिन getDeclaredFieldनहीं। getDeclaredFieldअपने आप को उस कक्षा तक सीमित करें जिस पर आप फ़ंक्शन को कॉल करते हैं।
user2336315

@ user2336315 जो सही है, हालांकि getFieldनिजी सदस्यों तक नहीं पहुंच सकता है
Madbreaks

जवाबों:


258

getFields ()

सभी publicक्षेत्र पूरे वर्ग पदानुक्रम तक।

getDeclaredFields ()

सभी क्षेत्रों, उनकी पहुँच की परवाह किए बिना, लेकिन केवल वर्तमान वर्ग के लिए, कोई आधार वर्ग नहीं जो वर्तमान वर्ग से विरासत में मिला हो।

सभी क्षेत्रों को पदानुक्रम प्राप्त करने के लिए, मैंने निम्नलिखित कार्य लिखा है:

public static Iterable<Field> getFieldsUpTo(@Nonnull Class<?> startClass, 
                                   @Nullable Class<?> exclusiveParent) {

   List<Field> currentClassFields = Lists.newArrayList(startClass.getDeclaredFields());
   Class<?> parentClass = startClass.getSuperclass();

   if (parentClass != null && 
          (exclusiveParent == null || !(parentClass.equals(exclusiveParent)))) {
     List<Field> parentClassFields = 
         (List<Field>) getFieldsUpTo(parentClass, exclusiveParent);
     currentClassFields.addAll(parentClassFields);
   }

   return currentClassFields;
}

exclusiveParentकक्षा से खेतों की बहाली को रोकने के लिए प्रदान की जाती है Object। यह हो सकता है nullयदि आप Objectफ़ील्ड चाहते हैं।

स्पष्ट करने के लिए, Lists.newArrayListअमरूद से आता है।

अपडेट करें

FYI करें, उपरोक्त कोड GitHub पर ReflectionUtils में मेरे LibEx प्रोजेक्ट में प्रकाशित हुआ है ।


8
शानदार उत्तर, लेकिन यह ध्यान दिया जाना चाहिए कि सुपरक्लास में निजी क्षेत्रों का उपयोग वर्तमान वर्ग के उदाहरणों Field#getऔर इसी तरह के तरीकों से नहीं किया जा सकता है । दूसरे शब्दों में, यह दृष्टिकोण वर्तमान वर्ग को अपने सुपरक्लास के निजी इंटरफ़ेस तक पहुंचने की अनुमति नहीं देता है, उसी तरह ठेठ संकलन नहीं है।
FThompson 16

4
@Vulcan सच जब तक कोड के माध्यम से गुंजाइश बदलने के लिए प्रतिबिंब का उपयोग करने के लिए लिखा है setAccessibleऔर जगह में कोई सुरक्षा प्रबंधक नहीं है
जॉन बी

थोड़ा नाइट, होना चाहिए "(कोई बात नहीं पहुंच)" नहीं "(कोई फर्क नहीं पड़ता गुंजाइश)"। सभी क्षेत्रों में एक ही गुंजाइश है, अर्थात्, वर्ग का शरीर
यशस्वी

@ आयुष थैंक्स अपडेट किया गया।
जॉन बी

1
यह नहीं होता। चूँकि privateखेतों को केवल उसी तक पहुँचा जा सकता है getDeclaredFieldsजिसके द्वारा वर्ग-विशिष्ट है। प्रत्येक क्षेत्र (यहां तक ​​कि एक ही प्रकार और नाम के साथ) अलग-अलग Fieldउदाहरण होंगे।
जॉन बी

7

जैसा कि पहले ही उल्लेख किया गया है, Class.getDeclaredField(String)केवल उन क्षेत्रों को देखता Classहै जिसमें से आप इसे कहते हैं।

यदि आप पदानुक्रम Fieldमें खोज करना चाहते Classहैं, तो आप इस सरल कार्य का उपयोग कर सकते हैं:

/**
 * Returns the first {@link Field} in the hierarchy for the specified name
 */
public static Field getField(Class<?> clazz, String name) {
    Field field = null;
    while (clazz != null && field == null) {
        try {
            field = clazz.getDeclaredField(name);
        } catch (Exception e) {
        }
        clazz = clazz.getSuperclass();
    }
    return field;
}

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

/**
 * Sets {@code value} to the first {@link Field} in the {@code object} hierarchy, for the specified name
 */
public static void setField(Object object, String fieldName, Object value) throws Exception {
    Field field = getField(object.getClass(), fieldName);
    field.setAccessible(true);
    field.set(object, value);
}

यदि अभी भी नहीं मिला है, तो थोड़ी सी भी त्रुटि को संशोधित करेंtry try { field = clazz.getDeclaredField(name); } catch (NoSuchFieldException e) { clazz = clazz.getSuperclass(); if(clazz==null){ throw e; } }
स्वेन धेंस

5

public Field[] getFields() throws SecurityException

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

विशेष रूप से, यदि यह वर्ग ऑब्जेक्ट किसी वर्ग का प्रतिनिधित्व करता है, तो यह विधि इस वर्ग के सार्वजनिक क्षेत्रों और उसके सभी सुपरक्लेसेस को वापस कर देती है। यदि यह क्लास ऑब्जेक्ट एक इंटरफ़ेस का प्रतिनिधित्व करता है, तो यह विधि इस इंटरफ़ेस के क्षेत्र और उसके सभी सुपरडिनफेसेस को वापस कर देती है।

सरणी वर्ग के लिए अंतर्निहित लंबाई फ़ील्ड इस पद्धति से परिलक्षित नहीं होती है। उपयोगकर्ता कोड को सरणियों में हेरफेर करने के लिए कक्षा एरे के तरीकों का उपयोग करना चाहिए।


public Field[] getDeclaredFields() throws SecurityException

इस ऑब्जेक्ट द्वारा दर्शाए गए क्लास या इंटरफ़ेस द्वारा घोषित सभी फ़ील्ड्स को दर्शाती फ़ील्ड ऑब्जेक्ट्स की एक सरणी देता है । यह सार्वजनिक, संरक्षित, डिफ़ॉल्ट (पैकेज) का उपयोग, और निजी शामिल क्षेत्रों, लेकिन शामिल नहीं विरासत में मिला क्षेत्रों। दिए गए एरे में तत्व क्रमबद्ध नहीं हैं और किसी विशेष क्रम में नहीं हैं। यदि क्लास या इंटरफ़ेस कोई फ़ील्ड घोषित नहीं करता है, या यदि यह क्लास ऑब्जेक्ट एक आदिम प्रकार, एक सरणी क्लास, या शून्य का प्रतिनिधित्व करता है, तो यह विधि लंबाई 0 की एक सरणी देता है।


और क्या होगा अगर मुझे सभी मूल वर्गों से सभी क्षेत्रों की आवश्यकता है? कुछ कोड की आवश्यकता है, उदाहरण के लिए https://stackoverflow.com/a/35103361/755804 :

public static List<Field> getAllModelFields(Class aClass) {
    List<Field> fields = new ArrayList<>();
    do {
        Collections.addAll(fields, aClass.getDeclaredFields());
        aClass = aClass.getSuperclass();
    } while (aClass != null);
    return fields;
}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.