2009-06-17 24 views
4

私はいくつかの言語のプログラムを入れ子になったJavaクラスに翻訳しています。Java内部クラスのファイル名が長すぎます

はTest.javaTest.java:5179をコンパイルする:いくつかの点で、ネストのレベルは私が得るほど深くなる書き込み中にエラー:テスト$ 2 ... $ 1.class(長すぎるファイル名)

ここで...は長い文字列です。

私はext3ファイルシステムを使用しているので、私は256文字の長いファイル名に制限されています。また、クロージャ変換を実行する際に問題を解決する言語をテストすることにもっと関心があるため、この翻訳方法(内部クラス)については、今すぐに続けたいと思います。これを回避するためのクイックな汚い方法はありますか? (別のファイルシステムを使用するかjavacに別のファイル名を生成するように指示してもかまいません)

+2

あなたは100レベル以上のネストされたクラスを持っていますか?うんざりする:) – Bombe

答えて

0

Comparison of File Systems、ResierFSは長いファイル名をサポートする唯一のものです。ほとんどのファイルシステムが255であるので、ツール(javac、java、ant、ls、rm、cpなど)のすべてがファイル名の長さを前提にするかもしれないので、この方法には注意が必要です。どうすればそれがなくなるのでしょうか?)これが純粋に学術的なものであれば、再フォーマット(または仮想化を使用)できます。

クラスを深く入れ子にするのを避けるためにアルゴリズムを再評価する必要があります。複数のファイルを使用できますか?私はあなたががそれを行うにはしたくないが、これはのみオプション

1

1の可能な解決策は、このようなyGuardとしてObfuscaterを使用し、その後、別のオペレーティングシステム上でコンパイルすることであるかもしれ知っています。 obfuscaterはデフォルトでクラス名を最小限の名前(例えばA、B、C ...)に変更し、クラス名(したがってファイル名)を大幅に短縮します。

あなたがテストしたいものによってはまったく役に立たないかもしれません。

1

java内からjavaをコンパイルして、自分で実装するファイルマネージャに出力を送信できます。

を使用し、コンパイル済みの出力を提供するJavaFileManagerを使用します。これはおそらく、jarファイルに直接書き込むことができますか?

3

ボトムラインは、はい、できます。内部クラスの名前を変更できるので、javacによって割り当てられた元の名前よりも短くなります。

$文字を使用して内部クラスを示すために、The Java Language SpecificationThe Java Virtual Machine Specificationを検索していましたが、参照できませんでした。理由は、それは本当に問題ではないということです。

ケースとポイント:ここでは

class A { 
    class B { 
     class C {} 
    } 

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

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

、我々は内部クラスを入れ子にしています。コンパイルされたとき、私たちは、次のファイルを入手:

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

は、ここでは簡単な実験です:

  1. A.classファイルを開き、A$B$Cへの参照を変更し、ABCDEに変更します。
  2. A$B$C.classの名前をABCDE.classに変更します。
  3. ABCDE.classを開き、参照をABCDEに変更します。
  4. 実行java A、実行されているかどうかを確認してください。

注:識別子の長さの変化がclassファイル形式をマングルているようだ、とエラーの原因となりますので、A$B$CABCDEに変更された理由があります。技術的な説明はこの記事の最後にあります。

結果?できます。

理由はclassファイルにあります。ここでは、元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 A$B$C of class A$B 

// ... snip ... // 

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

// ... snip ... // 

const #21 = Asciz A$B$C; 

// ... snip ...// 

が判明し、内部クラスの名前は、定数プールに名前だけです。 A.classの定数プールでA$B$Cクラスの名前がABCDEに変更され、classファイル内A$B$Cクラスのファイル名と名前が変更された場合は、Java仮想マシンが幸せに新たに実行されます

名前付き内部クラス。

これはどういう意味ですか?

クラス名にMyClass$1$1$1 ... $1を使用する必要はありませんが、スイートに必要なものはすべてより短いファイル名に複数の組み合わせを含めることができます。

どのように誰かがこれを行うでしょうか?私は読者に運動として残しておきます。この記事では、新しいクラス名としてABCDEの使用

注意、ネストされた内部クラスの名前、A$B$Cはで、同じクラス名の長さを保つためにABCDEに変更されましたClassFormatErrorがスローされないようにしてください。これは、定数プールのCONSTANT_Utf8_info structureに文字列の長さを示すlengthというプロパティがあるためです。テキストエディタでclassファイルを編集していたため、長さを変更できませんでした。

定数プールの文字列を短くするには、文字列自体の長さを反映するようにlengthフィールドの値を変更する必要があると思います。

更新

はい、それは内部クラスの名前を短くするclassファイルの定数プールを編集することが可能です。

ABCDEクラスをZクラスに変更できました。ここ

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

分かるように、内部クラスは現在なくA$B$Cより、Zによって参照されます。

変更は、文字列の長さが今であることを示す、A.classA$B$C.classファイル内の文字列A$B$Cを探している、とZに置き換えること、および値0x050x01への文字列の前の文字を変更して行われました5ではなく1です。

これらの変更を加えて、ファイル名をZ.classに変更すると同時に、プログラムは何も起こらなかったかのように動作しました。

したがって、はい、それは可能です同様に内部クラスの名前を短縮します。

+0

だから...新しい名前が古い名前と同じ長さである限り、これらのクラスの名前を変更することは可能でしょうか?それがどのようにOPに役立つか分かりません。 –

+0

下の注記を参照してください。定数プールの長さ情報が変更されている場合は、短縮することが可能です。 – coobird

関連する問題