Отражение Java - защищенное поле доступа

На самом деле, я забыл: в отличие от того, что я сказал в , мой другой ответ , на самом деле есть какой-то способ сделать это: расширить StringSubject, чтобы переопределить строковое представление, и использовать свой пользовательский предмет:

public static StringSubject assertThatAbbreviatedString(String actual) {
  return assertAbout(abbreviatedStrings()).that(actual);
}

public static Subject.Factory abbreviatedStrings() {
  return AbbreviatedStringSubject::new;
}

private static final class AbbreviatedStringSubject extends StringSubject {
  AbbreviatedStringSubject(FailureMetadata metadata, String actual) {
    super(metadata, actual);
  }

  @Override
  protected String actualCustomStringRepresentation() {
    return "";
    // [Edit: Or maybe you can extract the title from the doc and return that?]
  }
}

Это позволяет вам написать:

assertThatAbbreviatedString("abcdefghijklmnopqrstuvwyz").containsMatch("foo");

И вывод будет примерно таким:

expected to contain a match for: foo
but was                        : 

Если вы хотите иметь возможность подключить конкретное имя, а не , простейшая вещь, вероятно, заключается в использовании assertWithMessage(...).about(...).that(...), который можно снова обернуть вспомогательным методом. (Если assertWithMessage плохо подходит по какой-то причине, я могу использовать по крайней мере еще один подход.)

33
задан Mr_and_Mrs_D 6 December 2013 в 17:12
поделиться

5 ответов

Это должно делать то, что вы хотите:

function notempty($var) {
    return ($var==="0"||$var);
}

Редактировать: я полагаю, таблицы работают только в предварительном просмотре, а не в реальных ответах. Поэтому, пожалуйста, обратитесь к таблицам сравнения типов PHP для получения дополнительной информации.

notempty("")       : false
notempty(null)     : false
notempty(undefined): false
notempty(array())  : false
notempty(false)    : false
notempty(true)     : true
notempty(1)        : true
notempty(0)        : false
notempty(-1)       : true
notempty("1")      : true
notempty("0")      : true
notempty("php")    : true

По сути, notempty () - это то же самое, что! Empty () для всех значений, кроме «0», для которых он возвращает ] правда .


Редактировать: Если вы используете error_reporting (E_ALL) , вы не сможете передавать неопределенную переменную в пользовательские функции по значению. И, как указывает mercator, вы должны всегда использовать E_ALL , чтобы соответствовать передовой практике. В этой ссылке (комментарий № 11), которую он предоставляет, обсуждается, почему вы не должны использовать какую-либо форму подавления ошибок в целях производительности и обслуживания / отладки.

Примерно так могли бы работать даже с этими проблемами:

public class SomeExample {

  public static void main(String[] args) throws Exception{
    Object myObj = new SomeDerivedClass(1234);
    Class myClass = myObj.getClass();
    Field myField = getField(myClass, "value");
    myField.setAccessible(true); //required if field is not normally accessible
    System.out.println("value: " + myField.get(myObj));
  }

  private static Field getField(Class clazz, String fieldName)
        throws NoSuchFieldException {
    try {
      return clazz.getDeclaredField(fieldName);
    } catch (NoSuchFieldException e) {
      Class superClass = clazz.getSuperclass();
      if (superClass == null) {
        throw e;
      } else {
        return getField(superClass, fieldName);
      }
    }
  }
}

class SomeBaseClass {
  private Integer value;

  SomeBaseClass(Integer value) {
    this.value = value;
  }
}

class SomeDerivedClass extends SomeBaseClass {
  SomeDerivedClass(Integer value) {
    super(value);
  }
}
54
ответ дан 27 November 2019 в 17:58
поделиться

Do you perhaps mean from a different object an untrusted context with a SecurityManager set? That would break the type system, so you can't. From a trusted context, you can call setAccessible to defeat the type system. Ideally, don't use reflection.

0
ответ дан 27 November 2019 в 17:58
поделиться
field = myclass.getDeclaredField("myname");
field.setAccessible(true);
field.set(myinstance, newvalue);
4
ответ дан 27 November 2019 в 17:58
поделиться

Вы можете сделать что-то вроде ...

Class clazz = Class.forName("SuperclassObject");

Field fields[] = clazz.getDeclaredFields();

for (Field field : fields) {
    if (field.getName().equals("fieldImLookingFor")) {
        field.set...() // ... should be the type, eg. setDouble(12.34);
    }
}

Вам также может понадобиться изменить доступность, как отмечено в ответе Мориса.

0
ответ дан 27 November 2019 в 17:58
поделиться

Используйте отражение для доступа к членам экземпляра класса, сделайте их доступными и установите соответствующие значения. Конечно, вам нужно знать имя каждого участника, которого вы хотите изменить, но я думаю, это не будет проблемой.

public class ReflectionUtil {
    public static Field getField(Class clazz, String fieldName) throws NoSuchFieldException {
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            Class superClass = clazz.getSuperclass();
            if (superClass == null) {
                throw e;
            } else {
                return getField(superClass, fieldName);
            }
        }
    }
    public static void makeAccessible(Field field) {
        if (!Modifier.isPublic(field.getModifiers()) ||
            !Modifier.isPublic(field.getDeclaringClass().getModifiers()))
        {
            field.setAccessible(true);
        }
    }
}

public class Application {
    public static void main(String[] args) throws Exception {
        KalaGameState obj = new KalaGameState();
        Field field = ReflectionUtil.getField(obj.getClass(), 'turn');
        ReflectionUtil.makeAccessible(field);
        field.setInt(obj, 666);
        System.out.println("turn is " + field.get(obj));
    }
}
6
ответ дан 27 November 2019 в 17:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: