2009-06-17 10 views
4

Ich übersetze Programme einer Sprache in verschachtelte Java-Klassen. An einem gewissen Punkt wird das Niveau der Verschachtelung so tief, dass ich bekommen:Java innere Klassen Dateinamen zu lang

Kompilieren Test.javaTest.java:5179: Fehler beim Schreiben: Test $ 2 ... $ 1.class (Dateiname zu lang)

wo ... ist eine lange Saite.

Ich benutze ein ext3-Dateisystem, also bin ich auf 256 Zeichen lange Dateinamen beschränkt. Außerdem möchte ich im Moment mit dieser Übersetzungsmethode (zu inneren Klassen) fortfahren, weil ich mehr daran interessiert bin, die Sprache zu testen, die bei der Ausführung der Abschlusskonvertierung das Problem lösen würde. Gibt es einen schnellen und schmutzigen Weg, dies zu umgehen? (Verwenden eines anderen Dateisystems oder sagen javac, um verschiedene Dateinamen zu erzeugen?)

+2

Sie haben Klassen über 100 Ebenen tief verschachtelt ?! Heiliger Strohsack. :) – Bombe

Antwort

0

Comparison of File Systems, sieht aus wie ResierFS einer der nur, um längere Dateinamen zu unterstützen. Ich würde vor dieser Methode skeptisch sein, da alle Werkzeuge (javac, java, ant, ls, rm, cp, usw.) Annahmen über die Länge des Dateinamens machen können, da die meisten Dateisysteme 255 sind und Sie an einen FS gebunden sind (Was wenn es weggeht?) Wenn das rein akademisch ist, das neuformatieren (oder Virtualisierung nutzen).

Sie müssen Ihren Algorithmus möglicherweise nur reevalutieren, um zu vermeiden, dass Klassen so tief verschachtelt werden. Können Sie mehrere Dateien verwenden? Ich weiß, dass Sie nicht wollen, es zu tun, aber dies kann die nur Option

1

1 mögliche Lösung ist auf ein anderes Betriebssystem zu kompilieren, dann eine Obfuscater verwenden wie yGuard. Ein Obfuscater ändert standardmäßig die Klassennamen in einen minimalen Namen (zB A, B, C ...) und verkürzt dadurch den Klassennamen (und damit den Dateinamen) erheblich.

Könnte Ihnen nichts nützen, je nachdem, was genau Sie testen möchten.

1

Sie können Java innerhalb von Java kompilieren und die Ausgabe an einen Dateimanager senden, den Sie selbst implementieren.

Verwenden Sie javax.tools.JavaCompiler, mit einer JavaFileManager, die Sie mit der kompilierten Ausgabe versorgt, die Sie vielleicht direkt in ein Glas schreiben könnten?

3

Fazit ist, ja, es ist machbar. Man kann den Namen einer inneren Klasse ändern, also ist sie kürzer als der ursprüngliche Name, der von javac zugewiesen wurde.

Ich war auf der Suche durch The Java Language Specification und The Java Virtual Machine Specification zu finden, wo es über die Verwendung des $ Charakters spricht eine innere Klasse zu bezeichnen, und war nicht in der Lage einen Verweis darauf zu finden. Der Grund ist, es ist nicht wirklich wichtig.

Fall und Punkt:

class A { 
    class B { 
     class C {} 
    } 

    A() { 
     new B().new C(); 
    } 

    public static void main(String[] s){ 
     new A(); 
    } 
} 

Hier haben wir innere Klassen verschachtelt. Wenn kompiliert, so erhalten wir die folgenden Dateien:

A.class 
A$B.class 
A$B$C.class 

Hier ist ein schnelles Experiment ist:

  1. öffnen Sie die A.class-Datei, und ändern Sie sich auf ABCDE den Verweis auf A$B$C und ändern.
  2. Benennen Sie die A$B$C.class in ABCDE.class um.
  3. Öffnen Sie die ABCDE.class, und ändern Sie den Verweis auf ABCDE.
  4. Run java A, sehen, ob es läuft.

Hinweis: Der Grund für die A$B$C-ABCDE geändert wurde, ist, weil die Änderung in der Länge der Kennung des class Dateiformat zu mangle scheint, und wird einen Fehler verursachen. Technische Erklärung wird am Ende dieses Beitrags sein.

Ergebnis? Es klappt.

Der Grund ist in der class Datei. Hier ist eine Demontage der ursprünglichen A.class, und nur die relevanten Teile:

Compiled from "A.java" 
class A extends java.lang.Object 
    SourceFile: "A.java" 
    InnerClass: 
    #10= #3 of #7; //B=class A$B of class A 
    #22= #2 of #3; //C=class A$B$C of class A$B 

// ... snip ... // 

const #2 = class #21; // A$B$C 

// ... snip ... // 

const #21 = Asciz A$B$C; 

// ... snip ...// 

Es stellt sich heraus, der Name der inneren Klassen sind nur Namen in dem Konstanten-Pool.

Wenn der Name für die A$B$C Klasse im konstanten Pool von A.class zu ABCDE geändert wird, und wenn der A$B$C Klasse Dateiname und Name in der class Datei geändert wird, dann wird die Java Virtual Machine wird mit der neu glücklich ausführen benannte innere Klasse.

Was bedeutet das?

Man muss nicht die MyClass$1$1$1 ... $1 für den Klassennamen verwenden, aber alles andere, was die eigenen Bedürfnisse erfüllen würde, daher wäre es möglich, mehr Kombinationen in einem kürzeren Dateinamen zu haben.

Wie würde jemand gehen und dies tun? Das werde ich dem Leser als Übung überlassen.

Hinweis auf die Verwendung von ABCDE als neuen Klassennamen

In diesem Beitrag wird der Name der verschachtelten inneren Klasse wurde A$B$C-ABCDE geändert, um die Länge der Klasse zu halten, den gleichen Namen, in Um zu verhindern, dass ein ClassFormatError geworfen wird. Der Grund dafür ist, dass die CONSTANT_Utf8_info structure des Konstantenpools eine length -Eigenschaft hat, die die Länge der Zeichenfolge angibt. Ich konnte die Länge nicht ändern, da ich die Datei class in einem Texteditor bearbeitet habe.

Um die Zeichenfolge im konstanten Pool zu verkürzen, würde ich davon ausgehen, dass man den Wert des length Feld verändern müsste sich die Länge der Zeichenfolge zu reflektieren.

aktualisieren

Ja, es ist möglich, die class Datei Konstante Pool bearbeiten Sie den Namen der inneren Klasse zu verkürzen.

Ich war in der Lage, die ABCDE Klasse in Z Klasse zu ändern.

Hier ist ein Teil der Demontage des A.class:

Compiled from "A.java" 
class A extends java.lang.Object 
    SourceFile: "A.java" 
    InnerClass: 
    #10= #3 of #7; //B=class A$B of class A 
    #22= #2 of #3; //C=class Z of class A$B 

// ... snip ...// 

const #2 = class #21; // Z 

// ... snip ...// 

const #21 = Asciz Z; 

// ... snip ...// 

Wie jetzt genannt zu sehen ist, wird die innere Klasse von Z, anstatt A$B$C.

wurde die Änderung durch die Suche nach der Zeichenfolge A$B$C in den A.class und A$B$C.class Dateien und ersetzt sie durch Z, und das Ändern der Zeichen vor der Zeichenfolge aus dem Wert 0x05-0x01 durchgeführt wird, bezeichnet, dass die Länge der Saite ist jetzt 1 statt 5.

Mit diesen Änderungen, zusammen mit dem Umbenennen der Datei zu Z.class, lief das Programm als ob nichts jemals passiert wäre.

Also ja, es ist möglich den Namen der inneren Klasse auch zu verkürzen.

+0

Also ... Sie sagen, dass es möglich ist, den Namen dieser Klassen zu ändern, solange der neue Name die gleiche Länge wie der alte Name hat? Ich bin mir nicht sicher, wie das dem OP helfen wird. –

+0

Bitte beachten Sie den Hinweis am unteren Rand - es sollte möglich sein, es zu kürzen, wenn die Längeninformation des konstanten Pools geändert wird. – coobird