Java, как я могу с отражением проверить, если поле инициализировано или является значением по умолчанию? - PullRequest
8 голосов
/ 28 августа 2011

Итак, должен быть прямой вопрос.

Допустим, у меня есть класс с большим количеством полей, таких как:

String thizz;
long that;
boolean bar;

Как я могу, с отражением, увидеть, если поляthizz, that и bar были инициализированы или им присвоены значения по умолчанию: null, 0 и false?

Ответы [ 6 ]

21 голосов
/ 29 августа 2011

У вас есть только 7 примитивных типов и один ссылочный тип для проверки. Если вы сгруппируете все типы чисел вместе, у вас будет только четыре значения для проверки.

Object o =
for (Field field : o.getClass().getDeclaredFields()) {
 Class t = field.getType();
 Object v = field.get(o);
 if(t == boolean.class && Boolean.FALSE.equals(v)) 
   // found default value
 else if(t == char.class && ((Character) v).charValue() == 0)
   // found default value
 else if(t.isPrimitive() && ((Number) v).doubleValue() == 0)
   // found default value
 else if(v == null)
   // found default value
}  
6 голосов
/ 10 ноября 2014

Ответ Питера Лори отлично работает для меня, за исключением полей типа примитивных данных char, что вызывает следующее исключение в моем коде:

java.lang.ClassCastException: java.lang.Character cannot be cast to java.lang.Number

Поэтому я добавилchar case:

Object o =
for (Field field : o.getClass().getDeclaredFields()) {
 Class t = field.getType();
 Object v = field.get(o);
 if (boolean.class.equals(t) && Boolean.FALSE.equals(v)) 
   // found default value
 else if (char.class.equals(t) && ((Character) v) != Character.MIN_VALUE)
   // found default value
 else if (t.isPrimitive() && ((Number) v).doubleValue() == 0)
   // found default value
 else if(!t.isPrimitive() && v == null)
   // found default value
}  

Character.MIN_VALUE равно '\u0000', что является значением по умолчанию char в соответствии с Документацией Java по примитивным типам данных .

6 голосов
/ 28 августа 2011

Тебе не нужно отражение ...

if (thizz == null) {
    //it's not initialized
}
if (that == 0) {
   //it's not initialized
}
if(bar == false) {
    //it's not initialized
}

Однако их можно было инициализировать, а затем восстановить их значения по умолчанию. Если вы действительно хотите знать, были ли они инициализированы, вы можете сделать что-то вроде этого:

private boolean isFooInitialized = false;
private Foo foo;
public void setFoo(Foo foo) {
    this.foo = foo;
    isFooInitialized = foo != null;
}

/ редактировать Чтобы получить все поля из класса, проверьте Class.getDeclaredFields () . Это даст все поля, а не только публичные.

Отсюда вы можете проверить тип поля и получить его значение:

Foo foo = ...
Field[] fooFields = foo.getClass().getDeclaredFields();
for (Field fooField : fooFields) {
    Class<?> fooFieldClass = fooField.getClass();
    if (fooFieldClass.equals(int.class)) {
        if (fooField.getInt(foo) == 0) {
            // not initialized
        }
    } else if (fooFieldClass.equals(double.class)) {
        if (fooField.getDouble(foo) == 0) {
            // not initialized
        }
    } else if (fooFieldClass.equals(boolean.class)) {
        if (fooField.getBoolean(foo) == false) {
            // not initialized
        }
    } else if (fooFieldClass.equals(float.class)) {
        if (fooField.getFloat(foo) == 0) {
            // not initialized
        }
    } else if (fooFieldClass.equals(char.class)) {
        if (fooField.getChar(foo) == 0) {
            // not initialized
        }
    } else if (fooFieldClass.equals(byte.class)) {
        if (fooField.getByte(foo) == 0) {
            // not initialized
        }
    } else if (fooFieldClass.equals(long.class)) {
        if (fooField.getLong(foo) == 0) {
            // not initialized
        }
    } else if (fooField.get(foo) == null) {
        // not initialized
    }
}
3 голосов
/ 21 ноября 2016

Вы можете создать новый экземпляр с помощью отражения (автоматически инициализируется значением по умолчанию) и сравнить ваш объект с этим экземпляром по умолчанию.

//default Object filled with default values:
Object defaultObject = yourObject.getClass().newInstance();
for (final Field field : yourObject.getClass().getDeclaredFields()) {
  final Object value = field.get(yourObject);
  if (value == null || value.equals(field.get(defaultObject))) {
    // found default value
  }
}

PS: Это решение также решило проблему с символом, упомянутым Кристофом Вейсом.

1 голос
/ 29 августа 2011

Суть этого:

Field[] fields = yourObject.getClass().getFields();
for(Field f : fields)
{
  Class<?> k = f.getType();
  // depending on k, methods like f.getInt(yourObject),
  // f.getFloat(yourObject), 
  // f.getObject(hourObject) to get each member.
}

Теперь, это позволяет только читать открытые поля.

В качестве альтернативы, если ваш объект следует соглашениям именования getX / setX, вы можете использовать getMethods () и искать методы с именами "getXxx" и "setXxx", чтобы сделать вывод о существовании настраиваемых полей - и вызывать эти получатели для просмотра для ожидаемых значений по умолчанию.

1 голос
/ 29 августа 2011

Это должно привести вас в правильном направлении.

    Class clazz = Class.forName("your.class");
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
      String dataType = field.getType().getName();
      if (dataType.equals("java.lang.String")) {
          System.out.println("found a string");
      }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...