리플렉션 일반 Get 필드 값


132

리플렉션을 통해 필드 값을 받으려고합니다. 문제는 필드 유형을 모르고 값을 얻는 동안 결정해야한다는 것입니다.

이 코드는이 예외와 함께 발생합니다.

java.lang.String 필드 com .... fieldName을 java.lang.String으로 설정할 수 없습니다.

Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);

Class<?> targetType = field.getType();
Object objectValue = targetType.newInstance();

Object value = field.get(objectValue);

캐스팅을 시도했지만 컴파일 오류가 발생합니다.

field.get((targetType)objectValue)

또는

targetType objectValue = targetType.newInstance();

어떻게해야합니까?


4
API를 살펴보면 인수 field.get()object아닙니다 objectValue.
akaIDIOT

답변:


144

이전에 대답 한 것처럼 다음을 사용해야합니다.

Object value = field.get(objectInstance);

때로는 선호되는 또 다른 방법은 게터를 동적으로 호출하는 것입니다. 예제 코드 :

public static Object runGetter(Field field, BaseValidationObject o)
{
    // MZ: Find the correct method
    for (Method method : o.getMethods())
    {
        if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + 3)))
        {
            if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase()))
            {
                // MZ: Method found, run it
                try
                {
                    return method.invoke(o);
                }
                catch (IllegalAccessException e)
                {
                    Logger.fatal("Could not determine method: " + method.getName());
                }
                catch (InvocationTargetException e)
                {
                    Logger.fatal("Could not determine method: " + method.getName());
                }

            }
        }
    }


    return null;
}

또한 클래스가 다른 클래스에서 상속 될 때 필드를 재귀 적으로 결정해야합니다. 예를 들어, 주어진 클래스의 모든 필드를 가져 오는 것;

    for (Class<?> c = someClass; c != null; c = c.getSuperclass())
    {
        Field[] fields = c.getDeclaredFields();
        for (Field classField : fields)
        {
            result.add(classField);
        }
    }

1
슈퍼 클래스를 직접 반복해야한다는 것은 사실이 아닌 것 같습니다. c.getFields () 또는 c.getField ()는 각 구현 인터페이스에서 필드를 자동으로 검색하고 모든 수퍼 클래스를 통해 재귀 적으로 검색합니다. 따라서 getDeclaredX에서 getX로 전환하면 충분합니다.
Przemysław Ładyński

3
실제로 getFields () 루틴을 사용하면 모든 수퍼 클래스와 인터페이스의 필드를 가져올 수 있지만 공용 클래스 만 가져올 수 있습니다. 일반적으로 필드는 개인 / 보호로 설정되며 게터 / 세터를 통해 노출됩니다.
Marius

@Marius, 패키지가 무엇인지 알 수 BaseValidationObject있습니까?
randytan

내 개인 코드 저장소에 포함 된 @Randytan은 Object로 바꿀 수 있습니다. 정적 로거 호출에도 동일하게 적용되며 자신의 로거 (인스턴스)로 바꿉니다.
Marius

@Marius object클래스에는 메소드가 없습니다 getMethods(). 조언이 있습니까?
randytan

127

필드의 메소드 를 얻으려면 객체 를 전달해야 하므로

  Field field = object.getClass().getDeclaredField(fieldName);    
  field.setAccessible(true);
  Object value = field.get(object);

6
field.get (object)에서 객체를 사용해야하는 이유를 알고 있습니까? 필드 자체가 해당 객체에서 비롯된 이유는 무엇입니까?
serup

18
@serup 아니오, Field 객체는 실제 인스턴스와 연결되지 않은 Class 객체에서 가져옵니다. ( object.getClass()의지 반환 당신이 Class 객체)
드미트리 Spikhalskiy

1
object스 니펫에 정의되어 있지 않으므로 독자는이를 사용하는 방법을 이해할 수 없습니다.
Ghilteras

이 경우 @Ghilteras, 그들은 아직 반사를 사용하지 않아야하며 기본 기술을 먼저 얻지 않아야합니다 🤷🏻‍♂️. 리플렉션은 변수가 object대상 오브젝트 / 인스턴스를 의미한다는 것을 설명 할 수 없을 정도로 고급 주제 입니다. 나는 독자들이 실제로이 object답변의 내용에 대해 완전히 괜찮다고 생각합니다 .
Dmitry Spikhalskiy

@RajanPrasad 실제로는 아닙니다. 질문에 'object'라는 이름의 단일 객체가 있습니다. 다른 개체에는 다른 이름이 있습니다. 답은 질문과 가능한 한 명확하게하기 위해 질문에 사용 된 이름에 대해 정확하고 조정됩니다. 그것이 당신에게 효과가 없다면-더 명확하게하는 방법을 모르겠으며 다른 대답을 시도하거나 아마도 아직 반사를 피해야합니다.
Dmitry Spikhalskiy

19

기본 설정 클래스의 toString () 구현에서 리플렉션을 사용하여 클래스 멤버 및 값을 확인합니다 (간단하고 빠른 디버깅).

내가 사용하는 단순화 된 코드 :

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();

    Class<?> thisClass = null;
    try {
        thisClass = Class.forName(this.getClass().getName());

        Field[] aClassFields = thisClass.getDeclaredFields();
        sb.append(this.getClass().getSimpleName() + " [ ");
        for(Field f : aClassFields){
            String fName = f.getName();
            sb.append("(" + f.getType() + ") " + fName + " = " + f.get(this) + ", ");
        }
        sb.append("]");
    } catch (Exception e) {
        e.printStackTrace();
    }

    return sb.toString();
}

나는 또한 검색했기 때문에 그것이 누군가를 도울 수 있기를 바랍니다.


12

달성하려는 것이 분명하지는 않지만 코드에서 명백한 오류를 발견했습니다 Field.get(). 필드를 포함하는 객체가 해당 필드의 (가능한) 값이 아닌 인수로 예상됩니다. 그래서 당신은해야 field.get(object)합니다.

필드 값을 찾는 것처럼 보이므로 다음과 같이 얻을 수 있습니다.

Object objectValue = field.get(object);

필드 유형을 인스턴스화 할 필요가없고 빈 / 기본 값을 만들 필요가 없습니다. 또는 내가 놓친 것이있을 수 있습니다.


2
object정의되지 않은 경우 독자가 답변을 적용하는 방법을 이해할 수 없습니다.
Ghilteras

10
 Integer typeValue = 0;
 try {
     Class<Types> types = Types.class;
     java.lang.reflect.Field field = types.getDeclaredField("Type");
     field.setAccessible(true);
     Object value = field.get(types);
     typeValue = (Integer) value;
 } catch (Exception e) {
     e.printStackTrace();
 }

4

잘못된 인수로 get을 호출하고 있습니다.

그것은해야한다:

Object value = field.get(object);

2
object정의되지 않은, 독자는 답변에 예를 적용하는 방법을 이해할 수 없습니다
Ghilteras

2

Kotlin에 솔루션을 게시했지만 Java 객체에서도 작동 할 수 있습니다. 모든 객체가이 함수를 사용할 수 있도록 함수 확장을 만듭니다.

fun Any.iterateOverComponents() {

val fields = this.javaClass.declaredFields

fields.forEachIndexed { i, field ->

    fields[i].isAccessible = true
    // get value of the fields
    val value = fields[i].get(this)

    // print result
    Log.w("Msg", "Value of Field "
            + fields[i].name
            + " is " + value)
}}

이 웹 페이지를 살펴보십시오 : https://www.geeksforgeeks.org/field-get-method-in-java-with-examples/


1
    ` 
//Here is the example I used for get the field name also the field value
//Hope This will help to someone
TestModel model = new TestModel ("MyDate", "MyTime", "OUT");
//Get All the fields of the class
 Field[] fields = model.getClass().getDeclaredFields();
//If the field is private make the field to accessible true
fields[0].setAccessible(true);
//Get the field name
  System.out.println(fields[0].getName());
//Get the field value
System.out.println(fields[0].get(model));
`
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.