2013-04-11 4 views
11

逆コンパイル時に文字列が等しい:Javaの私は他の日のいくつかのJavaコードを逆コンパイルして、この見つかっ

明らか
String s1 = "something"; 
String s2 = "something_else"; 

if (s1 == s2) { 
// Path 1 
} else { 
// Path 2 
} 

「==」を使用して文字列の等価性をテストするために

悪いですがしかし、私は疑問に思った - これをコードがコンパイルされ、逆コンパイルされています。 s1.equals(s2)が 's1 == s2'に最適化されている可能性はありますか?すべての文字列がコンパイル時に定義され、インターンされ、コードがコンパイルされているとしますか?

+0

あなたはそれを試しましたか? – durron597

+5

1つの方法は、まるでそのようなコードをコンパイルして、デコンパイラから戻って来るものを見ることです:) – dasblinkenlight

+0

コンパイルされたコードはどのようにデコンパイルされましたか? –

答えて

8

私はそれを非常に疑っています。原則として、Javaコンパイラはバイトコードの最適化をほとんど行わず、最適化をJIT段階に任せています。

私はこれで少し実験してきた、と私のコンパイラは、次のと面白い何もしない:

public class Clazz { 

    public static void main(String args[]) { 
     final String s1 = "something"; 
     final String s2 = "something_else"; 
     if (s1.equals(s2)) { 
      System.out.println("yes"); 
     } else { 
      System.out.println("no"); 
     } 
    } 

} 

これはおそらく、最適化するための最も簡単な場合です。しかし、バイトコードは以下のとおりです。

public static void main(java.lang.String[]); 
    Code: 
     0: ldc   #16     // String something 
     2: astore_1  
     3: ldc   #18     // String something_else 
     5: astore_2  
     6: ldc   #16     // String something 
     8: ldc   #18     // String something_else 
     10: invokevirtual #20     // Method java/lang/String.equals:(Ljava/lang/Object;)Z 
     13: ifeq   27 
     16: getstatic  #26     // Field java/lang/System.out:Ljava/io/PrintStream; 
     19: ldc   #32     // String yes 
     21: invokevirtual #34     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     24: goto   35 
     27: getstatic  #26     // Field java/lang/System.out:Ljava/io/PrintStream; 
     30: ldc   #40     // String no 
     32: invokevirtual #34     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     35: return   

私はそれゆえ強く==は、元のソースコードの一部であったと思います。

1

いいえ、Javaではこれを最適化する(デフォルトでは)ようには見えません。

私は両方のソリューションをベンチマークしました。最適化されていない場合は、s1.equals(s2)s1 == s2よりも遅くなることが予想されます。これはまさに私たちが見るものです。最適化されている場合、s1.equals(s2)s1==s2と同じ時間がかかります。しかしながら、それらは異なる時間量(50,000ナノ秒のオーダー)をとる。これはではなく、です。このコンパイルの直接測定ですが、合理的な推論です。

==に最適化されないのは、オブジェクトのequals演算子が、オブジェクト自体の内容ではなく、オブジェクトのメモリアドレスを比較するためです。したがって、s1を変更すると、コンパイラがこれを最適化すると、s2も変更されます。

しかし、これはコードを壊す危険があるので、コンパイラはそれをしません。メモリアドレスはs1s2のままになります。

+0

なぜこれをdownvotedですか?ただ疑問に思う。 – RaptorDotCpp

+0

@RaptorDotCpp私はそれが戦術だと思う。しかたがない。 – Zyerah

+0

私はJITがこれを最適化していないことに少し驚いています。ウォーミングアップ、独自のメソッドなどで合理的なベンチマークを書いていましたか? – Voo

0

コンパイラが単一のクラスにあるソースコードから正確な値を差し引くことができる場合、主な規則があります。すべての最適化は最小のコンパイル単位クラスのみを使用するためです。私は、コード

public class Test 
{ 
    private static final String i = "1"; 
    public static void main(String[] args) 
    { 
     if(i == "2") 
      System.out.println("hello"); 
     System.out.println("world"); 
    } 
} 

を書く場合 コンパイラはこのクラスの声明に関連するすべてのコードを見て、もし条件を最適化します。デコンパイラはコードが

public class Test 
{ 
    private static final String i = "1"; 

    public static void main(String[] paramArrayOfString) 
    { 
    System.out.println("world"); 
    } 
} 

(私はjd-guiを使用しました)

のように見えた後、あなたは.equals==を交換する場合は、コンパイラは、メソッド.equalsがどのように動作するかを想定することはできません。Testクラスをコンパイルした後で、JDKをハックしてjava.lang.Stringクラスの別のバージョンを配置するとにtrueを返します。

コンパイラができる最適化について考えると、後でクラスを再コンパイルすることができれば、コンパイラがどのように動作するかを考えてください。

もう1つの例として、how enum is implementedが表示され、なぜこのような「奇妙な」方法が必要なのでしょうか。

関連する問題