Comment puis-je donner à java.util.Random une graine spécifique dans des classes tierces?

StackOverflow https://stackoverflow.com/questions/106623

  •  01-07-2019
  •  | 
  •  

Question

J'ai un programme Java qui charge et exécute des fichiers de classe tiers (des classes que je n'ai pas écrites). Ces classes utilisent souvent java.util.Random , qui génère par défaut des valeurs de départ de départ aléatoires à chaque instanciation. Pour des raisons de reproductibilité, je souhaite donner à ces classes la même valeur de départ, en ne les changeant qu’à ma discrétion.

Voici certaines des solutions évidentes et la raison pour laquelle elles ne fonctionnent pas:

  1. Utilisez une classe aléatoire différente dans les fichiers de classe tiers. Le problème ici est que je ne charge que les fichiers de classe et que je ne peux pas modifier le source.

  2. Utilisez un chargeur de classes personnalisé pour charger notre propre classe aléatoire au lieu de la version de la machine virtuelle Java. Cette approche ne fonctionnera pas car Java n'autorise pas les chargeurs de classes à remplacer les classes du package java .

  3. Échangez l'implémentation java.util.Random de rt.jar, ou insérez des fichiers dans des emplacements approuvés pour la machine virtuelle. Ces approches nécessitent que l'utilisateur de l'application joue avec l'installation de la machine virtuelle Java sur leur ordinateur et ne servent à rien.

  4. Ajout d'une classe personnalisée java.util.Random au chemin d'amorçage. Bien que cela fonctionnerait techniquement, pour cette application particulière, cela n’est pas pratique car cette application est destinée aux utilisateurs finaux et s’exécute à partir d’un environnement de développement intégré. Je veux rendre l'application facile à utiliser pour les utilisateurs, ce qui signifie que les forcer à définir leur chemin d'accès au bootclasspath est une douleur. Je ne peux pas cacher cela dans un script, car il est destiné à être exécuté à partir d'un IDE tel qu'Eclipse (pour faciliter le débogage.)

Alors, comment puis-je faire cela?

Était-ce utile?

La solution

Envisagez de modifier les bibliothèques tierces pour qu'elles utilisent un visionné pour leurs instances aléatoires. Bien que vous n'ayez pas le code source, vous pouvez probablement éditer le bytecode pour le faire. ASM est un outil utile pour ce faire.

Autres conseils

Votre option 2 fonctionnera réellement avec les instructions suivantes:

Vous aurez besoin (comme l'a dit anjab) de changer le chemin d'accès à la classe d'amorçage.

Dans la ligne de commande du programme, vous devez ajouter les éléments suivants:

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

En supposant que vous soyez sur la machine Windown ou sur le chemin d'accès dans n'importe quel système d'exploitation.

Cette option ajoute les classes dans les fichiers jar avant que le fichier rt.jar ne soit chargé. Donc, votre Random sera chargé avant la classe rt.jar Random.

L’utilisation est affichée en tapant:

java -X

Il affiche toutes les fonctionnalités X (tra) de la machine virtuelle Java. Il peut être non disponible  sur d’autres implémentations de machine virtuelle, telles que JRockit ou autre, mais sur la JVM de Sun.

-Xbootclasspath / p: ajoute devant le chemin d'accès à la classe d'amorçage

J'ai utilisé cette approche dans une application où la classe ORB par défaut devrait être remplacée par une autre implémentation ORB. La classe ORB fait partie de Java Core et n’a jamais rencontré de problème.

Bonne chance.

Vous pouvez utiliser AOP pour intercepter les appels de Random et modifier l’argument comme vous le souhaitez.

Sam

Bien que vous ne puissiez pas modifier le chargeur de classes de manière triviale pour "java.x". et "sun.x" Il existe un moyen de calculer le chargement des classes (et d'installer un "après que la classe ait été codée et chargée" par l'auditeur) de ces classes, de sorte que vous puissiez définir quelque chose comme la graine après avoir chargé les classes à partir de ces packages. Astuce: utilisez la réflexion.

Quoi qu'il en soit, tant que je n'ai pas d'informations supplémentaires sur ce que vous voulez réaliser, il est difficile de vous aider ici.

P.S .: Sachez que & static; static {} " - Les blocs peuvent encore vous empêcher de jouer avec les graines.

"Utilisez un chargeur de classes personnalisé pour charger notre propre classe aléatoire au lieu de la version de la machine virtuelle Java. Cette approche ne fonctionnera pas car Java n'autorise pas les chargeurs de classe à remplacer les classes du package java. "

que diriez-vous de changer le bootclasspath pour utiliser votre classe aléatoire personnalisée?

BR, ~ A

Oui, l'option 2 fonctionne: créé deux classes à des fins de test nommées ThirdPartyClass.java et Random.java

jar créé à partir de ThirdPartyClass.class

jar -cvf tpc.jar ThirdPartyClass.class

jar créé à partir de Random.class

jar -cvf rt123.jar Random.class

après cela exécuter avec la commande suivante:

java  -Xbootclasspath/p:tcp.jar:rt123.jar -cp . -verbose ThirdPartyClass

Le résultat sera: valeur de départ pour ThirdPartyClass- > 1

code source 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());
    }
}

code source 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;
    }
}

Merci Mahaveer Prasad Mali

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top