Как я могу предоставить java.util.Random определенное начальное значение в сторонних классах?
-
01-07-2019 - |
Вопрос
У меня есть Java-программа, которая загружает файлы сторонних классов (классы, которые я не писал) и выполняет их.Эти классы часто используют java.util.Random
, который по умолчанию генерирует случайные начальные начальные значения каждый раз при создании экземпляра.По соображениям воспроизводимости я хочу каждый раз присваивать этим классам одно и то же начальное значение, изменяя его только по своему усмотрению.
Вот некоторые из очевидных решений и почему они не работают:
Используйте другой Случайный класс в файлах сторонних классов.Проблема здесь в том, что я загружаю только файлы классов и не могу изменить исходный код.
Используйте пользовательский загрузчик классов, чтобы загрузить наш собственный Случайный класс вместо версии JVM.Этот подход не будет работать, потому что Java не позволяет загрузчикам классов переопределять классы в
java
посылка.Замените rt.jar'ы
java.util.Random
реализация для наших собственных или размещение файлов в надежных расположениях для JVM.Эти подходы требуют, чтобы пользователь приложения возился с установкой JVM на своем компьютере, и никуда не годятся.Добавление пользовательского
java.util.Random
класс к bootclasspath.Хотя технически это работало бы, для данного конкретного приложения это непрактично, поскольку это приложение предназначено для запуска конечными пользователями из IDE.Я хочу сделать запуск приложения удобным для пользователей, а это значит, что заставлять их задавать путь к bootclasspath - сплошная боль.Я не могу скрыть это в скрипте, потому что он предназначен для запуска из IDE, такой как Eclipse (для упрощения отладки).)
Итак, как я могу это сделать?
Решение
Рассмотрите возможность модификации сторонних библиотек, чтобы они использовали seen для своих случайных экземпляров.Хотя у вас нет исходного кода, вы, вероятно, можете отредактировать байт-код, чтобы сделать это.Одним из полезных инструментов для этого является ASM.
Другие советы
Ваш вариант 2 действительно будет работать, со следующими указаниями.
Вам нужно будет ( как сказал анджаб ) изменить путь к классу bootstrap .
В командной строке программы вам необходимо добавить следующее:
java -Xbootclasspath/p:C:\your andom_impl.jar Ваша программа
Предполагая, что вы находитесь на оконном компьютере или на пути, если уж на то пошло, в любой операционной системе.
Эта опция добавляет классы в файлы jar перед загрузкой rt.jar.Таким образом, ваш Random будет загружен раньше, чем это сделает класс rt.jar Random.
Использование отображается путем ввода :
java -X
Он отображает все функции X (tra), которыми обладает JVM.Он может быть недоступен в других реализациях виртуальных машин, таких как JRockit или других, но он есть в Sun JVM.
-Путь к Xbootclasspath/p:добавляйте перед путем к классу bootstrap
Я использовал этот подход в приложении, где класс ORB по умолчанию должен быть заменен другой реализацией ORB.Класс ORB является частью ядра Java, и у него никогда не было никаких проблем.
Удачи.
Вы могли бы использовать AOP для перехвата вызовов Random и настройки аргумента на то, что вы хотите.
Сэм
Хотя вы не можете тривиально изменить classloader для пакетов "java.x" и "sun.x", есть способ учесть загрузку классов (и установить прослушиватель "после того, как класс был байткодирован и загружен") этих классов, так что вы могли бы установить что-то вроде начального значения после загрузки классов из этих пакетов.Подсказка:Используйте рефлексию.
В любом случае, пока у меня нет дополнительной информации о том, чего именно вы хотите достичь, мне довольно сложно помочь вам здесь.
P.S.:Имейте в виду, что блоки "static {}" могут снова помешать вам возиться с семенами.
"Используйте пользовательский загрузчик классов для загрузки нашего собственного случайного класса вместо версии JVM.Этот подход не будет работать, потому что Java не позволяет загрузчикам классов переопределять классы в пакете Java ".
как насчет изменения bootclasspath для использования вашего пользовательского случайного класса?
BR, ~A
Да, вариант 2 работает:создал два класса для целей тестирования с именем ThirdPartyClass.java
и Random.java
созданный jar из ThirdPartyClass.class
jar -cvf tpc.jar ThirdPartyClass.class
созданный jar из Random.class
jar -cvf rt123.jar Random.class
после этого выполните следующую команду:
java -Xbootclasspath/p:tcp.jar:rt123.jar -cp . -verbose ThirdPartyClass
Результатом будет: seed value for ThirdPartyClass-> 1
исходный код ThirdPartyClass.java ----->
import java.util.Random;
public class ThirdPartyClass {
ThirdPartyClass(long seed ) {
System.out.println("seed value for ThirdPartyClass-> "+seed);
}
public static void main(String [] args) {
ThirdPartyClass tpc=new ThirdPartyClass(new Random().nextLong());
}
}
исходный код Random.java ------->
package java.util;
import java.io.Serializable;
public class Random extends Object implements Serializable
{
public Random() {
}
public Random(long seed) {
}
public long nextLong() {
return 1;
}
}
Спасибо Махавир Прасад Мали