2009-06-17 7 views
4

Je traduis des programmes d'une certaine langue à des classes Java imbriquées. À un certain moment, le niveau d'imbrication devient si profond que je reçois:java classes internes noms de fichiers trop longs

compilation Test.javaTest.java:5179: Erreur lors de l'écriture: Test 2 $ ... $ 1.class (nom de fichier trop long)

où ... est une longue chaîne. J'utilise un système de fichiers ext3, donc je suis limité à 256 noms de fichiers longs de caractères. Aussi, je voudrais continuer avec cette méthode de traduction (pour les classes internes) pour le moment parce que je suis plus intéressé par le test du langage que dans la conversion de fermeture, ce qui résoudrait le problème. Existe-t-il un moyen rapide et efficace de contourner ce problème? (utilisant un système de fichiers différent ou disant à javac de générer des noms de fichiers différents peut-être?)

+2

Vous avez des classes imbriquées sur 100 niveaux de profondeur ?! Merde sainte. :) – Bombe

Répondre

0

Comparison of File Systems, ressemble à ResierFS peut être l'un des seuls à supporter des noms de fichiers plus longs. Je me méfierais de cette méthode car tous les outils (javac, java, ant, ls, rm, cp, etc) pourraient faire des suppositions sur la longueur du nom de fichier car la plupart des systèmes de fichiers sont 255 et vous serez lié à un FS (Et si ça s'en va?) Si c'est purement académique, reformatez-vous (ou utilisez la virtualisation).

Vous devrez peut-être simplement réévaluer votre algorithme pour éviter d'imbriquer des classes si profondes. Pouvez-vous utiliser plusieurs fichiers? Je sais que vous ne voulez pour le faire, mais cela peut être le que l'option

1

1 solution possible est de compiler sur un autre système d'exploitation, puis utilisez un Obfuscater tel que yGuard. Un obfuscater par défaut changera les noms de classe en un nom minimal (par exemple A, B, C ...) raccourcissant ainsi considérablement le nom de la classe (et donc le nom du fichier). Cependant, cela ne vous servira probablement à rien en fonction de ce que vous voulez tester, par contre.

1

Vous pouvez compiler java à partir de java, en envoyant la sortie à un gestionnaire de fichiers que vous implémentez vous-même.

Utilisez javax.tools.JavaCompiler, avec un JavaFileManager qui vous fournit la sortie compilée, que vous pourriez écrire directement dans un pot?

3

La ligne de fond est, oui, c'est faisable. On peut changer le nom d'une classe interne, donc il est plus court que le nom original attribué par javac.

je cherchais à travers The Java Language Specification et The Java Virtual Machine Specification pour trouver où il parle de l'utilisation du caractère $ pour désigner une classe interne, et n'a pas été en mesure de trouver une référence. La raison en est que cela n'a pas vraiment d'importance.

Case et le point:

class A { 
    class B { 
     class C {} 
    } 

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

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

Ici, nous avons des classes internes imbriquées. Lors de la compilation, nous obtenons les fichiers suivants:

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

Voici une expérience rapide:

  1. Ouvrez le fichier A.class, et changer la référence à A$B$C et le changement à ABCDE.Renommez le A$B$C.class en ABCDE.class. Ouvrez le ABCDE.class et remplacez la référence par ABCDE.
  2. Exécutez java A, vérifiez s'il s'exécute.

Note: La raison pour laquelle la A$B$C a été changé à ABCDE est parce que le changement de la longueur de l'identifiant semble mutiler le format de fichier class et provoquera une erreur. L'explication technique sera à la fin de ce post.

Résultat? Ça marche. La raison est dans le fichier class. Voici un démontage du A.class, et seules les parties pertinentes d'origine:

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 ...// 

fin de compte, le nom des classes internes ne sont que des noms dans la piscine constante.

Si le nom de la classe A$B$C dans la piscine constante de A.class est changé en ABCDE, et si le nom du fichier de classe A$B$C et nom dans le fichier class est modifié, la machine virtuelle Java heureux exécuter avec le nouveau classe interne nommée.

Qu'est-ce que cela signifie?

Il n'est pas nécessaire d'utiliser le MyClass$1$1$1 ... $1 pour le nom de la classe, mais tout ce qui est nécessaire à la suite, il serait donc possible d'avoir plus de combinaisons dans un nom de fichier plus court.

Comment quelqu'un pourrait-il aller et faire cela? Que je vais laisser comme un exercice au lecteur.

Note sur l'utilisation de ABCDE comme le nouveau nom de la classe

Dans ce post, le nom de la classe imbriquée interne, A$B$C a été changé pour ABCDE de garder la longueur du nom de la classe même, dans afin d'empêcher un ClassFormatError d'être lancé. La raison en est que le CONSTANT_Utf8_info structure du pool constant a une propriété length qui indique la longueur de la chaîne. Je n'étais pas en mesure de modifier la longueur pendant que je modifiais le fichier class dans un éditeur de texte.

Afin de raccourcir la chaîne dans le pool constant, je suppose que l'on devrait modifier la valeur du champ length pour refléter la longueur de la chaîne elle-même.

Mise à jour

Oui, il est possible de modifier constant_pool du fichier class pour raccourcir le nom de la classe interne. J'ai pu changer la classe ABCDE en classe Z.

est ici une partie du démontage du 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 ...// 

Comme on le voit, la classe interne est maintenant désignée par Z, plutôt que A$B$C.

Le changement a été effectué par la recherche de la chaîne A$B$C dans les A.class et A$B$C.class fichiers, et le remplacer par Z et changer le caractère avant la chaîne de la valeur 0x05-0x01, indiquant que la longueur de la chaîne est maintenant 1 plutôt que 5.

Avec ces changements, avec renommer le fichier à Z.class, le programme a couru comme si rien ne s'est jamais produit. Donc, oui, c'est possible de raccourcir le nom de la classe interne aussi.

+0

Alors ... vous dites qu'il est possible de changer le nom de ces classes, tant que le nouveau nom a la même longueur que l'ancien nom? Je ne suis pas sûr de savoir comment cela va aider le PO. –

+0

Veuillez vous référer à la note en bas - il devrait être possible de la raccourcir, si les informations sur la longueur du pool constant sont modifiées. – coobird

Questions connexes