У меня есть программа Java, которая загружает файлы сторонних классов (классы, которые я не писал) и выполняет их. Эти классы часто используют java.util.Random, который по умолчанию генерирует случайные начальные начальные значения при каждом создании экземпляра. Из соображений воспроизводимости я хочу каждый раз давать этим классам одно и то же начальное значение, меняя его только по своему усмотрению.
Вот некоторые из очевидных решений и почему они не работают:
Используйте другой класс Random в сторонних файлах классов. Проблема здесь в том, что я загружаю только файлы классов и не могу изменять исходный код.
Используйте собственный загрузчик классов, чтобы загрузить наш собственный класс Random вместо версии JVM. Этот подход не будет работать, потому что Java не позволяет загрузчикам классов переопределять классы в пакете java.
Замените реализацию java.util.Random в rt.jar на нашу собственную или поместите файлы в надежные места для JVM. Эти подходы требуют, чтобы пользователь приложения возился с установкой JVM на своем компьютере, и они бесполезны.
Добавление пользовательского класса java.util.Random в путь к загрузочному классу. Хотя это технически сработает, для данного конкретного приложения это непрактично, поскольку это приложение предназначено для запуска конечными пользователями из среды IDE. Я хочу сделать запуск приложения удобным для пользователей, а это значит, что заставлять их устанавливать путь к загрузочному классу - это боль. Я не могу скрыть это в сценарии, потому что он предназначен для запуска из среды IDE, такой как Eclipse (для упрощения отладки).
Так как я могу это сделать?




Вы можете использовать АОП, чтобы перехватывать вызовы Random и менять аргумент на то, что вы хотите.
Сэм
«Используйте собственный загрузчик классов, чтобы загрузить наш собственный класс Random вместо версии JVM. Этот подход не будет работать, потому что Java не позволяет загрузчикам классов переопределять классы в пакете java».
как насчет изменения пути к загрузочному классу для использования вашего собственного класса Random?
BR, ~ А
Хотя вы не можете тривиально изменить загрузчик классов для пакетов «java.x» и «sun.x», есть способ учесть загрузку класса (и установить прослушиватель «после того, как класс был закодирован и загружен») этих классов, так что вы может установить что-то вроде семени после загрузки классов из этих пакетов. Подсказка: используйте отражение.
В любом случае, пока у меня нет дополнительной информации, чего именно вы хотите достичь, мне довольно сложно помочь вам здесь.
P.S .: Имейте в виду, что "static {}" - блоки могут снова помешать вам возиться с семенами.
Ваш вариант 2 действительно будет работать со следующими указаниями.
Вам нужно будет (как сказал Анджаб) изменить путь к классу начальной загрузки.
В командной строке программы нужно добавить следующее:
java -Xbootclasspath / p: C: \ your \ random_impl.jar YourProgram
Предполагая, что вы находитесь на машине Windown или пути в любой ОС.
Эта опция добавляет классы в файлы jar до загрузки rt.jar. Таким образом, ваш Random будет загружен раньше, чем это сделает класс rt.jar Random.
Использование отображается путем ввода:
java -X
Он отображает все функции X (tra), которые есть в JVM. Это может быть недоступно на других реализациях виртуальных машин, таких как JRockit или другие, но есть на Sun JVM.
-Xbootclasspath / p: добавить перед путем к классу начальной загрузки
Я использовал этот подход в приложении, где класс ORB по умолчанию должен быть заменен другой реализацией ORB. Класс ORB является частью Java Core и никогда не имел никаких проблем.
Удачи.
Подумайте об изменении сторонних библиотек, чтобы они использовали видимое для своих экземпляров Random. Хотя у вас нет исходного кода, вы, вероятно, можете отредактировать байт-код, чтобы сделать это. Один из полезных инструментов для этого - КАК М.
Да вариант 2 работает:
созданы два класса для целей тестирования с именами ThirdPartyClass.java и Random.java
создал банку из ThirdPartyClass.class
jar -cvf tpc.jar ThirdPartyClass.class
создал банку из 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;
}
}
Спасибо Махавир Прасад Мали
Изменение пути к загрузочному классу эффективно, но требует изменения способа запуска программы Java. Это нормально, если вы можете контролировать способ запуска программы, например сценарий запуска, но в моем случае пользователи обычно запускаются из среды IDE и должны делать это вручную, что не очень хорошо.