Отражение Java/Scala: Получить методы класса в порядке и вызвать инициацию объекта
У меня есть class
с несколькими объектами в качестве внутренних методов.
Я также задал этот вопрос некоторое время назад и получил хороший ответ, но это приводит к фатальным ошибкам в контейнерах сервлетов. Scala не может последовательно генерировать TypeTag
когда URLClassLoader
просит класс.
Данный проект с открытым исходным кодом находится здесь.
Текущий подход находится здесь, но он не сохраняет порядок. Члены объекта правильно инициализируются, но в случайном порядке.
Вопрос: Как вы можете собирать учеников:
- в порядке их определения
- потокобезопасным способом
- фильтровать их по супер типу
- и жадный initliase объектов (ссылки
module.instance
)
Обновление:
- Не предлагайте ответы на основе ссылок здесь, они были проверены и, как известно, не дают результатов.
- Используя
val
вместоobject
это не вариант по стилистическим соображениям. getMethods
или жеgetDeclaredFields
как известно, не гарантирует порядок. Если это как-то возможно, то, скорее всего, с отражением Scala.
4 ответа
От http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html:
public Field [] getDeclaredFields () генерирует исключение SecurityException
Возвращает массив объектов Field, отражающих все поля, объявленные классом или интерфейсом, представленным этим объектом Class. Это включает в себя открытые, защищенные, доступ по умолчанию (пакет) и частные поля, но исключает унаследованные поля. Элементы в возвращаемом массиве не отсортированы и расположены не в определенном порядке. Этот метод возвращает массив длины 0, если класс или интерфейс не объявляет никаких полей или если этот объект Class представляет примитивный тип, класс массива или void. См. Спецификацию языка Java, разделы 8.2 и 8.3.
(мой акцент). Подобный язык явно указан в документации для getDeclaredMethods(), но не в том, что касается getDeclaredClasses() (но IMO там можно считать неявным).
Так что нет, вы не можете полагаться на упорядочение из Java в JVM; на практике я видел, как порядок меняется в зависимости от архитектуры работающей JVM (32- или 64-битная).
Если вам действительно нужно инициализировать объекты в определенном порядке (почему?), Вы можете использовать соглашение об именах и сортировать вручную; однако, вероятно, было бы лучше изменить код, чтобы он не зависел от порядка.
Обновить
Похоже, что вы можете получить что-то из API отражения Scala:
trait EarlyInit {
val mirror = runtimeMirror(this.getClass.getClassLoader)
val reflection = mirror.reflect(this)
mirror
.classSymbol(this.getClass)
.toType
.members
.sorted /// This method is documented to return members "in declaration order"
.filter(_.isModule)
.foreach(m => reflection.reflectModule(m.asModule).instance)
}
}
Смотрите документацию по API:
Сортирует символы, включенные в эту область, таким образом: 1) Символы появляются в порядке линеаризации их владельцев. 2) Символы с одним и тем же владельцем отображаются в том же порядке, что и их объявления. 3) Синтетические члены (например, методы получения / установки для значений / переменных) могут появляться в произвольном порядке.
Однако это не будет гарантированно работать в целом, особенно для смешанных проектов Java/Scala (поскольку на самом деле нет способа получить членов класса Java в порядке объявления). Также имейте в виду, что отражение среды выполнения Scala не является поточно-ориентированным и обычно не считается готовым к работе.
Я все еще чувствую, что вам будет лучше, если вы модифицируете свой дизайн так, чтобы он был независимым от порядка, возможно, по-другому кодируя зависимости.
AFAIK, это невозможно. Члены класса порядка определены в просто не сохраняется в .class
файлы (по крайней мере, с использованием отражения Java).
У вас есть класс с несколькими внутренними object
s. Как вы указываете, внутренние объекты лениво инициализируются, когда какой-то другой код ссылается на них / вызывает их (аналогично lazy val
).
Проблема: (a) вышеупомянутая ленивая инициализация PLUS (b) неявные взаимозависимости между определениями объектов. Это означает, что их нужно инициализировать в порядке их цепочки зависимостей, но они явно не ссылаются друг на друга, поэтому правильно упорядоченная отложенная инициализация не происходит автоматически.
Попытка решения: программно предварительно инициализировать эти объекты в правильном порядке, используя отражение во время фазы построения / инициализации. Хотя это сработало бы, если бы с вами работало отражение scala или java, оно "идет вразрез" - оно работает вразрез с самим определением внутренних объектов. Если вы не хотите, чтобы они инициализировались лениво, тогда зачем объявлять их внутренними объектами?
Мое предлагаемое решение: изменить объявления изнутри object
с val
s. Упорядочите эти объявления в соответствии с желаемой последовательностью инициализации. Нет отражения требуется.
(Помимо: в этом разделе "Вопросы и ответы" вы не упомянули об искусственных ограничениях или причинах, по которым object
s должны быть использованы. Однако, если есть какая-то странная причина, по которой вы должны использовать объект, вы все равно можете избежать рефлексии. Просто пусть каждый конструктор объекта вызывает метод forceInit
от каждого объекта это зависит от. каждый forceInit
метод может просто вернуть 1. Это приведет к отложенной инициализации в правильном порядке.)
:-)
Я столкнулся с подобной проблемой и использовал аннотации с некоторой ценностью, чтобы назначить заказ. В частности, моя объектная модель управляет таблицей SWT, поэтому я создал:
public @interface DefaultColumnPosition {
int value();
}
Затем аннотируйте поля @DefaultColumnPosition(0)
или что бы то ни было число. Сортировать по значениям. Есть немного накладных расходов, и было бы лучше, если бы существовал другой метод или, возможно, аннотация на уровне класса, которая навязывала порядок, но не выглядела так.
Я не пробовал решение Scala, но оно также выглядит интересно, я могу дать этому шанс.