जावा में क्लास की विशेषताओं पर लूप कैसे करें?


85

मैं गतिशील रूप से जावा में एक वर्ग विशेषताओं पर कैसे लूप कर सकता हूं।

उदाहरण के लिए:

public class MyClass{
    private type1 att1;
    private type2 att2;
    ...

    public void function(){
        for(var in MyClass.Attributes){
            System.out.println(var.class);
        }
    }
}

क्या यह जावा में संभव है?

जवाबों:


100

आप जो भी मांग रहे हैं, उसे करने के लिए कोई भाषाई समर्थन नहीं है।

आप परावर्तन का उपयोग करके प्रतिबिंब के समय (उदाहरण के Class.getDeclaredFields()लिए एक सरणी प्राप्त करने के लिए Field) के प्रकार पर विचार कर सकते हैं , लेकिन आप जो करने की कोशिश कर रहे हैं, उसके आधार पर यह सबसे अच्छा समाधान नहीं हो सकता है।

यह सभी देखें

संबंधित सवाल


उदाहरण

यहाँ केवल एक ही उदाहरण दिखाया गया है कि प्रतिबिंब क्या करने में सक्षम है।

import java.lang.reflect.*;

public class DumpFields {
    public static void main(String[] args) {
        inspect(String.class);
    }
    static <T> void inspect(Class<T> klazz) {
        Field[] fields = klazz.getDeclaredFields();
        System.out.printf("%d fields:%n", fields.length);
        for (Field field : fields) {
            System.out.printf("%s %s %s%n",
                Modifier.toString(field.getModifiers()),
                field.getType().getSimpleName(),
                field.getName()
            );
        }
    }
}

उपरोक्त स्निपेट के सभी घोषित क्षेत्रों का निरीक्षण करने के लिए प्रतिबिंब का उपयोग करता है class String; यह निम्नलिखित उत्पादन का उत्पादन करता है:

7 fields:
private final char[] value
private final int offset
private final int count
private int hash
private static final long serialVersionUID
private static final ObjectStreamField[] serialPersistentFields
public static final Comparator CASE_INSENSITIVE_ORDER

प्रभावी जावा 2 संस्करण, आइटम 53: प्रतिबिंब के लिए इंटरफेस को प्राथमिकता दें

ये हैं पुस्तक के अंश:

एक को देखते हुए Classवस्तु, आप प्राप्त कर सकते हैं Constructor, Methodऔर Fieldउदाहरणों कंस्ट्रक्टर्स, तरीके और वर्ग के क्षेत्रों का प्रतिनिधित्व। [वे] आपको उनके अंतर्निहित समकक्षों को प्रतिबिंबित करने में हेरफेर करते हैं । यह शक्ति, हालांकि, एक मूल्य पर आती है:

  • आप संकलन-समय जाँच के सभी लाभ खो देते हैं।
  • चिंतनशील पहुंच के लिए आवश्यक कोड अनाड़ी और क्रिया है।
  • प्रदर्शन से ग्रस्त हैं।

एक नियम के रूप में, वस्तुओं को क्रम में सामान्य अनुप्रयोगों में प्रतिबिंबित नहीं किया जाना चाहिए।

कुछ परिष्कृत अनुप्रयोग हैं जिन्हें प्रतिबिंब की आवश्यकता होती है। उदाहरणों में [... उद्देश्य पर छोड़ दिया गया ...] शामिल हैं यदि आपको कोई संदेह है कि क्या आपका आवेदन इन श्रेणियों में से एक में आता है, तो यह संभव नहीं है।


वास्तव में, खेतों के मूल्य के अनुसार, मैं प्रत्येक क्षेत्र का मूल्य लिखना या नहीं लिखना चाहता हूं?
ज़कारिया

@ ज़करिया: हाँ, आप इसे प्रतिबिंब के साथ पूरा कर सकते हैं, लेकिन यह इस बात पर निर्भर करता है कि आप क्या करने की कोशिश कर रहे हैं, बहुत बेहतर डिज़ाइन हैं।
पॉलिजेनेबेलिकेंट्स

वास्तव में, मेरे पास एक वर्ग से उत्पन्न करने के लिए एक रिपोर्ट है, और उन क्षेत्रों को वर्ग के मूल्य के आधार पर जो मैं उन क्षेत्रों को रखना चाहता हूं या नहीं करना चाहता हूं, सबसे अच्छा डिजाइन क्या है जिसे मैं लागू कर सकता हूं।
जकारिया

1
@ ज़करिया: आगे बढ़ो और फिर प्रतिबिंब का प्रयास करो। वहाँ है Field.getकि आप एक क्षेत्र के मूल्यों को प्रतिबिंबित पढ़ने के लिए उपयोग कर सकते हैं। यदि यह है private, तो आप उस के साथ चारों ओर प्राप्त करने में सक्षम हो सकते हैं setAccessible। हां, प्रतिबिंब बहुत शक्तिशाली है और यह आपको privateखेतों का निरीक्षण करने , खेतों को अधिलेखित finalकरने, privateनिर्माण करने वालों को आमंत्रित करने आदि जैसे काम करने देता है । यदि आपको डिजाइन पहलू के साथ और सहायता की आवश्यकता है, तो आपको शायद एक नया प्रश्न बहुत अधिक जानकारी के साथ लिखना चाहिए। शायद आपको पहली जगह में इन कई विशेषताओं की आवश्यकता नहीं है (जैसे उपयोग enumया List, आदि)।
पॉलीजेन लुब्रीकेंट जूल

1
जेनेरिक का यहाँ कोई उपयोग नहीं है। बस करोstatic void inspect(Class<?> klazz)
user102008

45

सीधे खेतों तक पहुंचना वास्तव में जावा में अच्छी शैली नहीं है। मैं सुझाव दूंगा कि आपके बीन के खेतों के लिए गेट्टर और सेटर के तरीके और फिर java.beans पैकेज से इंट्रोस्पेक्टर और बीनइन्फो कक्षाओं का उपयोग करना।

MyBean bean = new MyBean();
BeanInfo beanInfo = Introspector.getBeanInfo(MyBean.class);
for (PropertyDescriptor propertyDesc : beanInfo.getPropertyDescriptors()) {
    String propertyName = propertyDesc.getName();
    Object value = propertyDesc.getReadMethod().invoke(bean);
}

क्या केवल बीन के गुणों को पाने का कोई तरीका है, वर्ग का नहीं? से बचें MyBean.class getPropertyDescriptors द्वारा लौटाया गया
hbprotoss

@hbprotoss यदि मैं आपको सही ढंग से समझता हूं, तो आप propertyDesc.getReadMethod().getDeclaringClass() != Object.classदूसरे पैरामीटर के रूप में विश्लेषण को रोकने के लिए एक वर्ग निर्दिष्ट कर सकते हैं या आप एक वर्ग को निर्दिष्ट कर सकते हैं getBeanInfo(MyBean.class, Object.class)
जोर्न होर्स्टमन

20

जबकि मैं Jörn के जवाब से सहमत हूं कि अगर आपकी कक्षा JavaBeabs युक्ति के अनुरूप है, तो यह एक अच्छा विकल्प है यदि यह नहीं है और आप स्प्रिंग का उपयोग करते हैं।

स्प्रिंग में ReflectionUtils नाम का एक वर्ग है जो कुछ बहुत ही शक्तिशाली कार्यक्षमता प्रदान करता है, जिसमें doWithFields (क्लास, कॉलबैक) , एक विज़िटर-स्टाइल विधि शामिल है जो आपको कॉलबैक ऑब्जेक्ट का उपयोग करके इस तरह से एक फ़ील्ड फ़ील्ड पर पुनरावृति करने देता है:

public void analyze(Object obj){
    ReflectionUtils.doWithFields(obj.getClass(), field -> {

        System.out.println("Field name: " + field.getName());
        field.setAccessible(true);
        System.out.println("Field value: "+ field.get(obj));

    });
}

लेकिन यहां एक चेतावनी दी गई है: वर्ग को "केवल आंतरिक उपयोग के लिए" के रूप में लेबल किया गया है, जो कि मेरे पूछने पर अफ़सोस की बात है


13

क्लास फ़ील्ड पर पुनरावृति करने और ऑब्जेक्ट से मान प्राप्त करने का सरल तरीका:

 Class<?> c = obj.getClass();
 Field[] fields = c.getDeclaredFields();
 Map<String, Object> temp = new HashMap<String, Object>();

 for( Field field : fields ){
      try {
           temp.put(field.getName().toString(), field.get(obj));
      } catch (IllegalArgumentException e1) {
      } catch (IllegalAccessException e1) {
      }
 }

एक वर्ग शायद या कोई वस्तु।
रिकी

@Rickey वैसे भी प्रत्येक फ़ील्ड को लूप करके विशेषताओं के लिए एक नया मान सेट करने के लिए है?
हाइपरफेकब

@hyperfkcb उन संपत्तियों / फ़ील्ड के मूल्यों को बदलने का प्रयास करते समय आपको एक संशोधन अपवाद मिल सकता है, जिनसे आप अधिक परेशान हो रहे हैं।
रिकी

6

Java में Reflection (java.reflection। *) है, लेकिन मैं Apache Beanutils जैसी लाइब्रेरी देखने का सुझाव दूंगा, यह सीधे प्रतिबिंब का उपयोग करने की तुलना में प्रक्रिया को बहुत कम बालों वाला बना देगा।


0

यहां एक समाधान है जो गुणों को वर्णानुक्रम से सॉर्ट करता है और उन सभी को उनके मूल्यों के साथ प्रिंट करता है:

public void logProperties() throws IllegalArgumentException, IllegalAccessException {
  Class<?> aClass = this.getClass();
  Field[] declaredFields = aClass.getDeclaredFields();
  Map<String, String> logEntries = new HashMap<>();

  for (Field field : declaredFields) {
    field.setAccessible(true);

    Object[] arguments = new Object[]{
      field.getName(),
      field.getType().getSimpleName(),
      String.valueOf(field.get(this))
    };

    String template = "- Property: {0} (Type: {1}, Value: {2})";
    String logMessage = System.getProperty("line.separator")
            + MessageFormat.format(template, arguments);

    logEntries.put(field.getName(), logMessage);
  }

  SortedSet<String> sortedLog = new TreeSet<>(logEntries.keySet());

  StringBuilder sb = new StringBuilder("Class properties:");

  Iterator<String> it = sortedLog.iterator();
  while (it.hasNext()) {
    String key = it.next();
    sb.append(logEntries.get(key));
  }

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