2008-09-20 14 views
5

Ich habe ein Java-Programm, das Third Party Class-Dateien (Klassen, die ich nicht geschrieben habe) lädt und führt sie aus. Diese Klassen verwenden häufig java.util.Random, die bei jeder Instanziierung standardmäßig zufällige Anfangswertwerte generiert. Aus Gründen der Reproduzierbarkeit möchte ich diesen Klassen jedes Mal den gleichen Anfangskorn geben und sie nur nach meinem Ermessen ändern.Wie kann ich java.util.Random einen bestimmten Startwert in Drittklassen geben?

Hier sind einige der offensichtlichen Lösungen, und warum sie nicht funktionieren:

  1. Verwenden Sie eine andere Zufallsklasse in den Klassendateien von Drittanbietern. Das Problem hier ist, ich lade nur die Klassendateien und kann die Quelle nicht ändern.

  2. Verwenden Sie einen benutzerdefinierten Classloader zum Laden unserer eigenen Random-Klasse anstelle der JVM-Version. Dieser Ansatz wird nicht funktionieren, da Java es ClassLadern nicht erlaubt, Klassen im java-Paket zu überschreiben.

  3. Tauschen Sie die Implementierung java.util.Random von rt.jar aus, oder legen Sie Dateien in vertrauenswürdige Speicherorte für die JVM. Diese Herangehensweisen erfordern, dass der Benutzer der Anwendung mit der JVM-Installation auf seinem Computer herumhängt und nicht gut ist.

  4. Hinzufügen einer benutzerdefinierten Klasse java.util.Random zum bootclasspath. Während dies für diese spezielle Anwendung technisch funktionieren würde, ist es unpraktisch, da diese Anwendung für Endbenutzer von einer IDE ausgeführt werden soll. Ich möchte die App für Benutzer bequemer machen, was bedeutet, dass sie gezwungen sind, ihren Bootclasspath einzustellen. Ich kann dies in einem Skript nicht verstecken, denn es bestimmt ist von einem IDE wie Eclipse ausgeführt werden (für eine einfache Fehlersuche.)

So wie kann ich das tun?

Antwort

2

Sie können die Bibliotheken von Drittanbietern so ändern, dass sie für ihre zufälligen Instanzen gesehen werden. Obwohl Sie den Quellcode nicht haben, können Sie den Bytecode wahrscheinlich bearbeiten, um es zu tun. Ein hilfreiches Toolkit dafür ist ASM.

1

Sie könnten AOP verwenden, um die Aufrufe von Random abzufangen und den Arg zu drehen, was Sie wollen.

Sam

0

„eine benutzerdefinierte Classloader verwenden unsere eigene Klasse Random statt der JVM-Version zu laden. Dieser Ansatz wird nicht funktionieren, weil Java Classloader nicht zulässt, dass Klassen in der Java-Paket außer Kraft zu setzen.“

Wie wäre es, wenn Sie den bootclasspath so ändern, dass er Ihre benutzerdefinierte Random-Klasse verwendet?

BR, ~ A

+0

Cha Der bootclasspath ist zwar effektiv, erfordert jedoch eine Änderung der Ausführung des Java-Programms. Dies ist in Ordnung, wenn Sie steuern können, wie jemand das Programm startet, z. ein Startskript, aber in meinem Fall laufen Benutzer normalerweise innerhalb einer IDE und würden es manuell tun müssen, was nicht gut ist. – adum

1

Obwohl Sie nicht den Klassenlader triviale für „java.x“ ändern und „sun.x“ Pakete, gibt es eine Möglichkeit, das Laden von Klassen zu rechnen (und eine „nach Klasse installieren wurde bytecoded und geladen "listener" dieser Klassen, so dass Sie so etwas wie den Startwert nach dem Laden der Klassen aus diesen Paketen setzen können. Tipp: Benutze Reflektion.

Wie auch immer, solange ich keine weiteren Informationen habe, was genau Sie erreichen wollen, ist es ziemlich schwierig, Ihnen hier zu helfen.

P.S .: Beachten Sie, dass "statische {}" - Blöcke Sie daran hindern können, wieder mit Samen herumzuspielen.

3

Ihre Option 2 wird tatsächlich funktionieren, mit den folgenden Anweisungen.

Sie müssen (wie anjab gesagt wurde) den Bootstrap-Klassenpfad ändern.

in der Befehlszeile des Programms Sie Folgendes hinzufügen müssen:

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

Angenommen, Sie sind auf Windown Maschine oder die Pfad für diese Angelegenheit in jedem Betriebssystem.

Diese Option fügt die Klassen in JAR-Dateien, bevor die rt.jar geladen werden. Dein Random wird also vor der rt.jar Random-Klasse geladen.

Die Nutzung wird durch die Eingabe angezeigt:

java -X 

Es zeigt alle X (tra) verfügt de JVM hat. Es ist möglicherweise nicht verfügbar auf anderen VM-Implementierungen wie JRockit oder andere, aber es ist dort auf Sun JVM.

-Xbootclasspath/p: prepend vor Bootstrap-Classpath

ich diesen Ansatz in einer Anwendung verwenden haben, wo die Standard-ORB-Klasse sollte mit anderen ersetzt werden ORB-Implementierung. ORB-Klasse ist Teil des Java-Core und hatte nie ein Problem.

Viel Glück.

0

Ja Option 2 arbeiten: erstellt zwei Klassen zu Testzwecken genannt ThirdPartyClass.java und Random.java

erstellt jar von ThirdPartyClass.class

jar -cvf tpc.jar ThirdPartyClass.class 

erstellt jar von Random.class

jar -cvf rt123.jar Random.class 

danach ausführen mit folgendem Befehl:

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

wird der Ausgang sein: seed value for ThirdPartyClass-> 1

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

Quellcode 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; 
    } 
} 

Dank Mahaveer Prasad Mali