문제

i'm in following situation:

public class SuperClass
{
        public static Object superClassStaticField;
}

public class ChildClass extends SuperClass
{
... some methods and fields
}

I have a method which looks like this:

...modifiers... void action(Class <? extends SuperClass> cls)
{
...
}

i would like to reach all elements whit reflection including superclass static fields which i (later in ChildClass) initalize, but looks like here is some logic fails in reflection:

The superClassStaticField is in the Superclass, so if i try to reach with:

cls.getClass().get[Declared]Field("superClassStaticField");

i will get java.lang.NoSuchFieldException

So i must reach trouth the SuperClass:

SuperClass.class.getDeclaredField("superClassStaticField").get(null);

will work successfully, but if there is more than one ChildClass works in same Runtime, my program getting crazy. I think beacuse all method reach same Object wich is declared in SuperClass.

But how can i reach the actually given class static field?

i tried:

SuperClass.class.getDeclaredField("superClassStaticField").get(cls);

But the result is same.

How can i reach it?

Edit: i would like get/set now only static fields, create a new instance is not safe, (sour it's have empty constructor? and will modify nothing?)

도움이 되었습니까?

해결책

But how can i reach the actually given class static field?

There is only a single static field. You don't end up with one static field per subclass. It sounds like you need to take a different approach. We can't give you much advice about what that approach should be, as we don't know what you're trying to achieve. Perhaps a Map<Class, Object> is what you're after?

다른 팁

Firstly, static fields belong to the actual class in which they're defined; they are not accessible via reflection from a reference from the subclass. That is, using reflection:

SuperClass.field // OK - the field is declared on SuperClass
SubClass.field // Not found - the field is not declared on SubClass

You can find the field though using reflection by climbing up the hierarchy (repeatedly) trying to find it on the super class of the class you're inspecting:

clz.getSuperclass().getField("superClassStaticField")

You may have to go up through multiple super classes depending on how deep your hierarchy is.

Finally, because the field belongs to the super class, and there is only one super class for all your subclasses, all subclasses will use the same superclass field.

I know my answer comes little late. I created a view methods that can do exactly this:

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import lombok.NonNull;

public final class ReflectionExtensions
{
    public static Field[] getAllDeclaredFields(final @NonNull Class<?> cls,
        List<String> ignoreFieldNames)
    {
        Field[] declaredFields = getDeclaredFields(cls, ignoreFieldNames);
        Class<?> superClass = cls.getSuperclass();
        if (superClass != null && superClass.equals(Object.class))
        {
            return declaredFields;
        }
        List<Field> fields = new ArrayList<>(Arrays.asList(declaredFields));
        while (superClass != null
            && !(superClass.getSuperclass() != null && superClass.equals(Object.class)))
        {
            fields.addAll(Arrays.asList(getDeclaredFields(superClass, ignoreFieldNames)));
            superClass = superClass.getSuperclass();
        }
        return fields.toArray(newArrayInstance(Field.class, fields.size()));
    }
    
    public static Field[] getDeclaredFields(final @NonNull Class<?> cls,
        List<String> ignoreFieldNames) throws SecurityException
    {
        Field[] declaredFields = cls.getDeclaredFields();
        return Arrays.stream(declaredFields)
            .filter(field -> !ignoreFieldNames.contains(field.getName())).toArray(Field[]::new);
    }
    
    public static <T> T[] newArrayInstance(final @NonNull Class<T> cls, final int length)
    {
        return (T[])Array.newInstance(cls, length);
    }
    public static String[] getDefaultIgnoreFieldNames()
    {
        return new String[] { "serialVersionUID", "$jacocoData" };
    }
}

and a unit test for it:

import io.github.astrapi69.test.objects.Member;
import io.github.astrapi69.test.objects.Person;
import io.github.astrapi69.test.objects.PremiumMember;
import org.testng.annotations.Test;

import java.lang.reflect.Field;

import static org.testng.AssertJUnit.assertEquals;

public class ReflectionExtensionsTest
{

    @Test
    public void testGetAllDeclaredFields()
    {
        int expected;
        int actual;
        Field[] allDeclaredFields;

        allDeclaredFields = io.github.astrapi69.reflection.ReflectionExtensions.getAllDeclaredFields(
            Person.class,
            io.github.astrapi69.reflection.ReflectionExtensions.getDefaultIgnoreFieldNames());
        expected = 5;
        actual = allDeclaredFields.length;
        assertEquals(expected, actual);

        allDeclaredFields = io.github.astrapi69.reflection.ReflectionExtensions.getAllDeclaredFields(
            Member.class,
            io.github.astrapi69.reflection.ReflectionExtensions.getDefaultIgnoreFieldNames());
        expected = 7;
        actual = allDeclaredFields.length;
        assertEquals(expected, actual);

        allDeclaredFields = io.github.astrapi69.reflection.ReflectionExtensions.getAllDeclaredFields(
            PremiumMember.class,
            ReflectionExtensions.getDefaultIgnoreFieldNames());
        expected = 8;
        actual = allDeclaredFields.length;
        assertEquals(expected, actual);
    }
}
    

The test classes are from test-object repository.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top