জাভাতে কোনও শ্রেণীর বৈশিষ্ট্যগুলি কীভাবে লুপ করবেন?


87

গতিশীলভাবে জাভাতে আমি কোনও শ্রেণীর বৈশিষ্ট্যগুলি কীভাবে লুপ করব।

যেমন:

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

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

জাভাতে এটা কি সম্ভব?

উত্তর:


101

আপনি যা চাইছেন তা করার জন্য কোনও ভাষাগত সমর্থন নেই।

প্রতিচ্ছবি ব্যবহার করে রান-টাইমে কোনও ধরণের সদস্যদের আপনি প্রতিবিম্বিতভাবে অ্যাক্সেস করতে পারেন (উদাহরণস্বরূপ 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দৃষ্টান্ত কনস্ট্রাকটর, পদ্ধতি এবং ক্লাস ক্ষেত্র উপস্থাপন করে। [তারা] আপনাকে তাদের অন্তর্নিহিত অংশগুলিকে প্রতিফলিতভাবে ম্যানিপুলেট করতে দেয় । এই শক্তিটি অবশ্য দামে আসে:

  • সংকলন-সময় যাচাইয়ের সমস্ত সুবিধা আপনি হারাতে পারেন।
  • প্রতিবিম্বিত অ্যাক্সেস সম্পাদন করার জন্য প্রয়োজনীয় কোডটি আনাড়ি এবং ভার্বোস।
  • পারফরম্যান্স ভোগ করে।

একটি নিয়ম হিসাবে, রানটাইমের সময় সাধারণ অ্যাপ্লিকেশনগুলিতে বস্তুর প্রতিফলিতভাবে অ্যাক্সেস করা উচিত নয়।

কয়েকটি পরিশীলিত অ্যাপ্লিকেশন রয়েছে যার প্রতিচ্ছবি প্রয়োজন। উদাহরণগুলির মধ্যে অন্তর্ভুক্ত রয়েছে [... উদ্দেশ্য অনুসারে বাদ দেওয়া ...] যদি আপনার অ্যাপ্লিকেশনটি এই বিভাগগুলির মধ্যে একটির মধ্যে পড়ে কিনা তা নিয়ে আপনার যদি সন্দেহ থাকে তবে সম্ভবত তা হয় না।


আসলে ক্ষেত্রের মান অনুযায়ী, আমি প্রতিটি ক্ষেত্রের মান লিখতে বা লিখতে চাই না?
জাকারিয়া

@ জাকারিয়া: হ্যাঁ, আপনি এটি প্রতিফলন সহকারে অর্জন করতে পারেন, তবে আপনি যা করার চেষ্টা করছেন তার উপর নির্ভর করে আরও ভাল ডিজাইন রয়েছে।
polygenelubricants

আসলে, আমার কাছে একটি ক্লাস থেকে উত্পন্ন করার জন্য একটি প্রতিবেদন আছে এবং আমি যে শ্রেণীর ক্ষেত্রগুলি রাখতে চাই বা তার ক্ষেত্রগুলিতে যে ক্ষেত্রগুলি রাখতে চাই বা তার উপর নির্ভর করে, আমি কী সেরা নকশা প্রয়োগ করতে পারি? "
জাকারিয়া

4
@ জাকারিয়া: এগিয়ে যান এবং তারপরে প্রতিবিম্ব চেষ্টা করুন। আছে Field.getযে আপনার reflectively একটি ক্ষেত্র মান পড়তে ব্যবহার করতে পারেন। যদি এটি হয় তবে আপনি এটির সাথে ঘনিষ্ঠ privateহতে পারবেন setAccessible। হ্যাঁ, প্রতিচ্ছবি খুব শক্তিশালী এবং এটি আপনাকে privateক্ষেত্রগুলি পরিদর্শন করা, ক্ষেত্রগুলিকে ওভাররাইটিং করা final, privateনির্মাণকারীদের অনুরোধ করা ইত্যাদির মতো জিনিসগুলি করতে দেয় যদি আপনার যদি নকশার দিকটি নিয়ে আরও সহায়তার প্রয়োজন হয় তবে আপনার সম্ভবত আরও অনেক তথ্য সহ একটি নতুন প্রশ্ন লিখতে হবে। প্রথমদিকে আপনার এই অনেকগুলি অ্যাট্রিবিউট লাগবে না (যেমন ব্যবহার enumবা Listইত্যাদি)।
বহুবিশ্বেষকারী

4
জেনেরিকের এখানে কোনও ব্যবহার নেই। just dostatic void inspect(Class<?> klazz)
user102008

45

সরাসরি ক্ষেত্রগুলি অ্যাক্সেস করা জাভাতে ভাল স্টাইল নয়। আমি আপনার শিমের ক্ষেত্রগুলির জন্য গেটর এবং সেটার পদ্ধতি তৈরি করার পরামর্শ দিচ্ছি এবং তারপরে জাভা.বিয়ানস প্যাকেজ থেকে ইন্ট্রোস্পেক্টর এবং বিয়ানআইএনফো ক্লাস ব্যবহার করব।

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 এড়ান getPropertyDescripttors দ্বারা ফিরে
hbprotoss

@ hbprotoss যদি আমি আপনাকে সঠিকভাবে বুঝতে পারি তবে আপনি যাচাই propertyDesc.getReadMethod().getDeclaringClass() != Object.classকরতে পারেন বা দ্বিতীয় প্যারামিটারের মতো বিশ্লেষণ বন্ধ করতে কোনও শ্রেণি নির্দিষ্ট করতে পারেন getBeanInfo(MyBean.class, Object.class)
জর্ন হোর্স্টম্যান

20

আমি যদি জার্নের জবাবের সাথে একমত হই তবে যদি আপনার শ্রেণি জাভাবিবসের অনুকূলে মেনে চলে, তবে এখানে ভাল বিকল্প যদি তা না হয় এবং আপনি স্প্রিং ব্যবহার করেন।

স্প্রিংয়ের রিফ্লেকশন ইউটিলেস নামে একটি শ্রেণি রয়েছে যা ডুউইথফিল্ডস (শ্রেণি, কলব্যাক) সহ কিছু খুব শক্তিশালী কার্যকারিতা সরবরাহ করে , একটি দর্শনার্থী-শৈলীর পদ্ধতি যা আপনাকে এই জাতীয় কলব্যাক অবজেক্ট ব্যবহার করে ক্লাসের ক্ষেত্রগুলিতে পুনরাবৃত্তি করতে দেয়:

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));

    });
}

তবে এখানে একটি সতর্কতা রয়েছে: ক্লাসটি "কেবলমাত্র অভ্যন্তরীণ ব্যবহারের জন্য" হিসাবে লেবেলযুক্ত, যদি আপনি আমাকে জিজ্ঞাসা করেন তবে এটি দুঃখের বিষয়


14

শ্রেণীর ক্ষেত্রগুলিতে পুনরাবৃত্তি এবং অবজেক্ট থেকে মানগুলি পাওয়ার সহজ উপায়:

 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) {
      }
 }

সম্ভবত একটি ক্লাস বা কোনও বস্তু।
রিকি

@ রিকি কি প্রতিটি ক্ষেত্রটি লুপ করে গুণাবলীতে নতুন মান নির্ধারণের উপায় আছে?
hyperbkcb

@hyperfkcb আপনি যে বৈশিষ্ট্য / ক্ষেত্রগুলির পুনরাবৃত্তি করছেন তার মান পরিবর্তন করার চেষ্টা করার সময় আপনি একটি পরিবর্তন ব্যতিক্রম পেতে পারেন।
রিকি 18

6

জাভাতে প্রতিবিম্ব রয়েছে (জাভা.রেফ্লেশন। *), তবে আমি অ্যাপাচি বিয়ান্টিলসের মতো লাইব্রেরিটি সন্ধান করার পরামর্শ দিচ্ছি, এটি সরাসরি প্রতিচ্ছবি ব্যবহারের চেয়ে প্রক্রিয়াটিকে অনেক কম লোমশ করে তুলবে।


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());
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.