Как я могу дать java.util.Random конкретное семя в классах третьих лиц? - PullRequest
5 голосов
/ 20 сентября 2008

У меня есть программа на Java, которая загружает файлы классов третьих лиц (классы, которые я не писал) и выполняет их. Эти классы часто используют java.util.Random, который по умолчанию генерирует случайные начальные начальные значения каждый раз, когда создается его экземпляр. Из соображений воспроизводимости я хочу, чтобы эти классы каждый раз давали одинаковое начальное число, меняя его только по своему усмотрению.

Вот некоторые из очевидных решений и почему они не работают:

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

  2. Используйте пользовательский загрузчик классов для загрузки нашего собственного класса Random вместо версии JVM. Этот подход не будет работать, потому что Java не позволяет загрузчикам классов переопределять классы в пакете java.

  3. Поменяйте реализацию rt.jar java.util.Random на нашу собственную или поместите файлы в надежные места для JVM. Эти подходы требуют, чтобы пользователь приложения возился с установкой JVM на своем компьютере, и они бесполезны.

  4. Добавление пользовательского класса java.util.Random в путь начальной загрузки. Хотя это технически будет работать, для данного конкретного приложения это нецелесообразно, поскольку это приложение предназначено для запуска конечными пользователями из IDE. Я хочу сделать запуск приложения удобным для пользователей, а это значит, что заставлять их устанавливать путь к загрузочной логике - это боль. Я не могу скрыть это в скрипте, потому что он предназначен для запуска из IDE, такой как Eclipse (для легкой отладки.)

Так как я могу это сделать?

Ответы [ 6 ]

3 голосов
/ 20 сентября 2008

Ваш вариант 2 действительно будет работать, со следующими указаниями.

Вам потребуется (как сказал anjab) изменить путь к классу начальной загрузки.

В командной строке программы необходимо добавить следующее:

java -Xbootclasspath / p: C: \ your \ random_impl.jar YourProgram

Предполагается, что вы находитесь на Windown-машине или по пути к этому в любой ОС.

Эта опция добавляет классы в jar-файлы перед загрузкой rt.jar. Таким образом, ваш файл Random будет загружен раньше, чем класс Random rt.jar.

Использование отображается, набрав:

java -X

Отображает все функции X (tra), которые есть у JVM. Может быть недоступен в других реализациях виртуальных машин, таких как JRockit или другие, но они есть в Sun JVM.

-Xbootclasspath / p: предварять перед путем к классу начальной загрузки

Я использовал этот подход в приложении, в котором класс ORB по умолчанию должен быть заменен на реализацию других ORB. Класс ORB является частью Java Core и никогда не имел проблем.

Удачи.

2 голосов
/ 20 сентября 2008

Подумайте о том, чтобы изменить сторонние библиотеки, чтобы они использовали видимые для своих экземпляров Random. Хотя у вас нет исходного кода, вы, вероятно, можете отредактировать байт-код, чтобы сделать это. Одним из полезных инструментов для этого является ASM .

1 голос
/ 20 сентября 2008

Хотя вы не можете изменять загрузчик классов тривиально для пакетов "java.x" и "sun.x", есть способ рассчитать загрузку классов (и установить "после того, как класс был байт-кодирован и загружен" слушателем) этих классов , так что вы можете установить что-то вроде семени после загрузки классов из этих пакетов. Подсказка: используйте отражение.

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

P.S .: Помните, что "static {}" - блоки могут помешать вам снова возиться с семенами.

1 голос
/ 20 сентября 2008

Вы можете использовать AOP, чтобы перехватывать вызовы в Random и поворачивать arg к тому, что хотите.

Sam

0 голосов
/ 04 июня 2010

Да, вариант 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;
    }
}

Спасибо Махавир Прасад Мали

0 голосов
/ 20 сентября 2008

"Используйте собственный загрузчик классов для загрузки нашего собственного класса Random вместо версии JVM. Этот подход не будет работать, поскольку Java не позволяет загрузчикам классов переопределять классы в пакете java."

как насчет изменения пути к загрузочному классу для использования вашего пользовательского класса Random?

BR, ~ A

...