জাভা প্রতিবিম্ব ব্যবহার করে উত্তরাধিকার সূত্রে প্রাপ্ত নাম / মানগুলি পুনরুদ্ধার করা


128

আমি একটি জাভা অবজেক্ট 'চাইল্ডওবজ' যা 'প্যারেন্টওবজ' থেকে প্রসারিত। এখন, জাভা প্রতিবিম্ব প্রক্রিয়াটি ব্যবহার করে, উত্তরাধিকারসূত্রে প্রাপ্ত বৈশিষ্ট্যগুলি সহ চাইল্ডওবিজে-এর সমস্ত বৈশিষ্ট্য নাম এবং মানগুলি পাওয়া সম্ভব কিনা?

Class.getFields আমাকে সর্বজনীন বৈশিষ্ট্যের অ্যারে দেয় এবং Class.getDeclaredFields আমাকে সমস্ত ক্ষেত্রের অ্যারে দেয় তবে এর মধ্যে কোনওটি উত্তরাধিকার সূত্রে প্রাপ্ত ক্ষেত্রের তালিকাকে অন্তর্ভুক্ত করে না।

উত্তরাধিকারসূত্রে প্রাপ্ত বৈশিষ্ট্যগুলিও পুনরুদ্ধার করার কোনও উপায় আছে?

উত্তর:


173

না, আপনার নিজের এটি লিখতে হবে। এটি Class.getSuperClass () এ ডাকা একটি সাধারণ পুনরাবৃত্তির পদ্ধতি :

public static List<Field> getAllFields(List<Field> fields, Class<?> type) {
    fields.addAll(Arrays.asList(type.getDeclaredFields()));

    if (type.getSuperclass() != null) {
        getAllFields(fields, type.getSuperclass());
    }

    return fields;
}

@Test
public void getLinkedListFields() {
    System.out.println(getAllFields(new LinkedList<Field>(), LinkedList.class));
}

2
হ্যাঁ. যে সম্পর্কে চিন্তা। তবে এটির অন্য কোনও উপায় আছে কিনা তা পরীক্ষা করে দেখতে চেয়েছিলেন। ধন্যবাদ। :)
বীরা

7
কোনও পরিবর্তনীয় তর্ককে পাস করা এবং এটি ফিরিয়ে দেওয়া সম্ভবত কোনও দুর্দান্ত নকশা নয়। fields.addAll (type.getDeclaredFields ()); অ্যাড সহ লুপের জন্য বর্ধিত হওয়ার চেয়ে প্রচলিত হবে।
টম হাটিন -

আমি কমপক্ষে এটি (স্ট্যাকওভারফ্লোতে) সংকলন করার প্রয়োজনীয়তাটি অনুভব করব এবং সম্ভবত কিছুটা অ্যারে.এএসলিস্টে যুক্ত করব।
টম হাটিন -

দেখে মনে হয় যে আপনার কোডটি সমস্ত ক্ষেত্রগুলি সংগ্রহ করে, এছাড়াও ব্যক্তিগত এবং স্থিতিশীল ক্ষেত্রগুলি যা উত্তরাধিকার সূত্রে প্রাপ্ত হয় না।
পিটার ভারহাস

90
    public static List<Field> getAllFields(Class<?> type) {
        List<Field> fields = new ArrayList<Field>();
        for (Class<?> c = type; c != null; c = c.getSuperclass()) {
            fields.addAll(Arrays.asList(c.getDeclaredFields()));
        }
        return fields;
    }

9
এটি আমার পছন্দসই সমাধান, তবে আমি এটিকে "getAllFields" বলব কারণ এটি প্রদত্ত শ্রেণীর ক্ষেত্রগুলিকেও ফিরিয়ে দেয়।
পিনো

3
যদিও আমি খুব বেশি পুনরাবৃত্তি পছন্দ করি (এটি মজাদার!) তবে আমি এই পদ্ধতির পাঠযোগ্যতা এবং আরও স্বজ্ঞাত পরামিতিগুলি (নতুন কালেকশনটি পাস করার প্রয়োজন নেই) পছন্দ করি না, তবে (ক্লজটির জন্য অন্তর্নিহিত) আর ক্ষেত্রগুলিতে কোনও পুনরাবৃত্তি হবে না নিজেদের.
রেমি মরিন

এটি দেখায় পুনরাবৃত্তি অপ্রয়োজনীয় এবং .. আমি সংক্ষিপ্ত কোড পছন্দ করি! ধন্যবাদ! :)
কুম্ভ শক্তি

অনেক বছরের মধ্যে আমি সর্বদা মনে করি যে এর জন্য প্রাথমিক মানটি কেবলমাত্র একটি পূর্ণসংখ্যা, @ ভিরার প্রশ্নের সাথে আমি মনে করি যে কেবল পুনরাবৃত্তিকেই এটি সমাধান করতে পারে, @ এসকো লুনটোলা আপনার আদেশটি দুর্দান্ত।
তোয়া আকিরা

@ এসকো: আপনাকে অনেক ধন্যবাদ দিন বাঁচাল! এটি সংক্ষিপ্ত এবং নির্দোষভাবে কাজ করে!
গৌরব

37

যদি আপনি এটি সম্পাদন করতে কোনও লাইব্রেরির উপর নির্ভর করতে চান তবে অ্যাপাচি কমন্স ল্যাং সংস্করণ 3.2+ সরবরাহ করে FieldUtils.getAllFieldsList:

import java.lang.reflect.Field;
import java.util.AbstractCollection;
import java.util.AbstractList;
import java.util.AbstractSequentialList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang3.reflect.FieldUtils;
import org.junit.Assert;
import org.junit.Test;

public class FieldUtilsTest {

    @Test
    public void testGetAllFieldsList() {

        // Get all fields in this class and all of its parents
        final List<Field> allFields = FieldUtils.getAllFieldsList(LinkedList.class);

        // Get the fields form each individual class in the type's hierarchy
        final List<Field> allFieldsClass = Arrays.asList(LinkedList.class.getFields());
        final List<Field> allFieldsParent = Arrays.asList(AbstractSequentialList.class.getFields());
        final List<Field> allFieldsParentsParent = Arrays.asList(AbstractList.class.getFields());
        final List<Field> allFieldsParentsParentsParent = Arrays.asList(AbstractCollection.class.getFields());

        // Test that `getAllFieldsList` did truly get all of the fields of the the class and all its parents 
        Assert.assertTrue(allFields.containsAll(allFieldsClass));
        Assert.assertTrue(allFields.containsAll(allFieldsParent));
        Assert.assertTrue(allFields.containsAll(allFieldsParentsParent));
        Assert.assertTrue(allFields.containsAll(allFieldsParentsParentsParent));
    }
}

6
পরিস্ফুটন! আমি চাকা পুনর্নবীকরণ না ভালবাসা। এই জন্য চিয়ার্স।
জোশুয়া পিন্টার 21

6

আপনাকে কল করতে হবে:

Class.getSuperclass().getDeclaredFields()

প্রয়োজনীয় হিসাবে উত্তরাধিকার শ্রেণিবিন্যাস পুনরুদ্ধার করা।



4

পুনরাবৃত্তির সমাধানগুলি ঠিক আছে, কেবলমাত্র ছোট সমস্যা হ'ল তারা ঘোষিত এবং উত্তরাধিকার সূত্রে প্রাপ্ত সদস্যদের একটি সুপারসেট ফেরত দেয়। নোট করুন যে getDeclaredFields () পদ্ধতিটি ব্যক্তিগত পদ্ধতিও দেয়। সুতরাং আপনি পুরো সুপারক্লাসের শ্রেণিবিন্যাস নেভিগেট করার কারণে আপনি সুপারক্লাসে ঘোষিত সমস্ত ব্যক্তিগত ক্ষেত্র অন্তর্ভুক্ত করবেন এবং সেগুলি উত্তরাধিকার সূত্রে প্রাপ্ত হবে না।

একটি Modifier.is প্রজাতন্ত্র সহ একটি সাধারণ ফিল্টার || Modifier.is সুরক্ষিত ভবিষ্যদ্বাণীটি করবে:

import static java.lang.reflect.Modifier.isPublic;
import static java.lang.reflect.Modifier.isProtected;

(...)

List<Field> inheritableFields = new ArrayList<Field>();
for (Field field : type.getDeclaredFields()) {
    if (isProtected(field.getModifiers()) || isPublic(field.getModifiers())) {
       inheritableFields.add(field);
    }
}

2
private static void addDeclaredAndInheritedFields(Class<?> c, Collection<Field> fields) {
    fields.addAll(Arrays.asList(c.getDeclaredFields())); 
    Class<?> superClass = c.getSuperclass(); 
    if (superClass != null) { 
        addDeclaredAndInheritedFields(superClass, fields); 
    }       
}

উপরের "ডিড ইউম্যানইটটাইম টোমহ ..." সমাধানের কার্যকারী সংস্করণ


2

স্প্রিং ইউজ লাইব্রেরির সাহায্যে, আপনি কোনও নির্দিষ্ট বৈশিষ্ট্য শ্রেণিতে বিদ্যমান কিনা তা পরীক্ষা করতে ব্যবহার করতে পারেন:

Field field = ReflectionUtils.findRequiredField(YOUR_CLASS.class, "ATTRIBUTE_NAME");

log.info(field2.getName());

এপিআই ডক:
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/util/ReflectionUtils.html

অথবা

 Field field2 = ReflectionUtils.findField(YOUR_CLASS.class, "ATTRIBUTE_NAME");

 log.info(field2.getName());

এপিআই ডক:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/ReflectionUtils.html

@cheers



1

সংক্ষিপ্ত এবং কম অবজেক্টের সাথে ইনস্ট্যান্টেশনযুক্ত? ^^

private static Field[] getAllFields(Class<?> type) {
    if (type.getSuperclass() != null) {
        return (Field[]) ArrayUtils.addAll(getAllFields(type.getSuperclass()), type.getDeclaredFields());
    }
    return type.getDeclaredFields();
}

এইচআই @ অ্যালেক্সিস লেগ্রোস: অ্যারে ইউটিলস প্রতীক খুঁজে পাবে না।
তোয়া আকিরা

1
এই ক্লাসটি অ্যাপাচি কমন্স ল্যাং থেকে।
অ্যালেক্সিস লেগারস

এই প্রশ্নটির অনুরোধটি পরিচালনা করতে আপাচে ইতিমধ্যে একটি FieldUtils.getAllFields ফাংশন রয়েছে।
তোয়া আকিরা

1

গেটফিল্ডস (): সমস্ত বর্গক্ষেত্রকে পুরো শ্রেণীর শ্রেণিবিন্যাস এবং
getDeclaredFields (): সমস্ত ক্ষেত্র পায়, তাদের পরিবর্তক ছাড়াই কেবলমাত্র বর্তমান শ্রেণীর জন্য। সুতরাং, আপনাকে জড়িত সমস্ত শ্রেণিবিন্যাসের জন্য পেতে হবে।
আমি সম্প্রতি org.apache.commons.lang3.reflect.FieldUtils থেকে এই কোডটি দেখেছি

public static List<Field> getAllFieldsList(final Class<?> cls) {
        Validate.isTrue(cls != null, "The class must not be null");
        final List<Field> allFields = new ArrayList<>();
        Class<?> currentClass = cls;
        while (currentClass != null) {
            final Field[] declaredFields = currentClass.getDeclaredFields();
            Collections.addAll(allFields, declaredFields);
            currentClass = currentClass.getSuperclass();
        }
        return allFields;
}

0
private static void addDeclaredAndInheritedFields(Class c, Collection<Field> fields) {
    fields.addAll(Arrays.asList(c.getDeclaredFields()));
    Class superClass = c.getSuperclass();
    if (superClass != null) {
        addDeclaredAndInheritedFields(superClass, fields);
    }
}

0

এটি @ ব্যবহারকারী 1079877 দ্বারা গৃহীত উত্তরের একটি পুনর্নির্মাণ। এটি এমন কোনও সংস্করণ যা ফাংশনটির প্যারামিটারটি সংশোধন করে না এবং কিছু আধুনিক জাভা বৈশিষ্ট্যও ব্যবহার করে।

public <T> Field[] getFields(final Class<T> type, final Field... fields) {
    final Field[] items = Stream.of(type.getDeclaredFields(), fields).flatMap(Stream::of).toArray(Field[]::new);
    if (type.getSuperclass() == null) {
        return items;
    } else {
        return getFields(type.getSuperclass(), items);
    }
}

এই বাস্তবায়নটি আরও বেশি সংক্ষিপ্ত হয়ে ডাকে:

var fields = getFields(MyType.class);

0

ফিল্ড ইউটিলেস দ্বারা চিহ্নিত করা হয়নি এমন কয়েকটি দাবানল রয়েছে - বিশেষত কৃত্রিম ক্ষেত্রগুলি (যেমন জ্যাকোকো দ্বারা ইনজেকশনের) এবং প্রতিটি এনামের জন্য একটি এনাম ধরণের কোর্সের ক্ষেত্র রয়েছে এবং যদি আপনি কোনও বস্তুর গ্রাফকে ট্র্যাভার করে চলেছেন তবে সমস্ত ক্ষেত্র এবং তারপরে এগুলির প্রত্যেকের ক্ষেত্রগুলি পাওয়া ইত্যাদি then আপনি যখন এনামকে আঘাত করবেন তখন আপনি একটি অসীম লুপে প্রবেশ করবেন। একটি বর্ধিত সমাধান (এবং সত্য বলতে আমি নিশ্চিত যে এটি অবশ্যই কোথাও কোনও লাইব্রেরিতে বাস করতে পারে!) হ'ল:

/**
 * Return a list containing all declared fields and all inherited fields for the given input
 * (but avoiding any quirky enum fields and tool injected fields).
 */
public List<Field> getAllFields(Object input) {
    return getFieldsAndInheritedFields(new ArrayList<>(), input.getClass());
}

private List<Field> getFieldsAndInheritedFields(List<Field> fields, Class<?> inputType) {
    fields.addAll(getFilteredDeclaredFields(inputType));
    return inputType.getSuperclass() == null ? fields : getFieldsAndInheritedFields(fields, inputType.getSuperclass());

}

/**
 * Where the input is NOT an {@link Enum} type then get all declared fields except synthetic fields (ie instrumented
 * additional fields). Where the input IS an {@link Enum} type then also skip the fields that are all the
 * {@link Enum} instances as this would lead to an infinite loop if the user of this class is traversing
 * an object graph.
 */
private List<Field> getFilteredDeclaredFields(Class<?> inputType) {
    return Arrays.asList(inputType.getDeclaredFields()).stream()
                 .filter(field -> !isAnEnum(inputType) ||
                         (isAnEnum(inputType) && !isSameType(field, inputType)))
                 .filter(field -> !field.isSynthetic())
                 .collect(Collectors.toList());

}

private boolean isAnEnum(Class<?> type) {
    return Enum.class.isAssignableFrom(type);
}

private boolean isSameType(Field input, Class<?> ownerType) {
    return input.getType().equals(ownerType);
}

স্পকে টেস্ট ক্লাস (এবং গ্রোভি সিন্থেটিক ফিল্ড যুক্ত করে):

class ReflectionUtilsSpec extends Specification {

    def "declared fields only"() {

        given: "an instance of a class that does not inherit any fields"
        def instance = new Superclass()

        when: "all fields are requested"
        def result = new ReflectionUtils().getAllFields(instance)

        then: "the fields declared by that instance's class are returned"
        result.size() == 1
        result.findAll { it.name in ['superThing'] }.size() == 1
    }


    def "inherited fields"() {

        given: "an instance of a class that inherits fields"
        def instance = new Subclass()

        when: "all fields are requested"
        def result = new ReflectionUtils().getAllFields(instance)

        then: "the fields declared by that instance's class and its superclasses are returned"
        result.size() == 2
        result.findAll { it.name in ['subThing', 'superThing'] }.size() == 2

    }

    def "no fields"() {
        given: "an instance of a class with no declared or inherited fields"
        def instance = new SuperDooperclass()

        when: "all fields are requested"
        def result = new ReflectionUtils().getAllFields(instance)

        then: "the fields declared by that instance's class and its superclasses are returned"
        result.size() == 0
    }

    def "enum"() {

        given: "an instance of an enum"
        def instance = Item.BIT

        when: "all fields are requested"
        def result = new ReflectionUtils().getAllFields(instance)

        then: "the fields declared by that instance's class and its superclasses are returned"
        result.size() == 3
        result.findAll { it.name == 'smallerItem' }.size() == 1
    }

    private class SuperDooperclass {
    }

    private class Superclass extends SuperDooperclass {
        private String superThing
    }


    private class Subclass extends Superclass {
        private String subThing
    }

    private enum Item {

        BIT("quark"), BOB("muon")

        Item(String smallerItem) {
            this.smallerItem = smallerItem
        }

        private String smallerItem

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