Stringクラスの解析

4006 ワード

JavaのStringは特殊なパッケージクラスデータであり、2つの作成形式があります.
String s = "abc";
String s = new String("abc");    
    1つ目は、スタックにStringクラスのオブジェクト参照変数sを作成してから、「abc」が文字列定数プールに保存されているかどうかを検索し、そうでない場合はスタックに3つのchar型の値「a」、「b」、「c」を作成し、スタックにStringオブジェクトobjectを作成します.その値は、スタックに作成した3つのchar型の値からなる配列{'a'、'b'、'c'}です.次に、このStringオブジェクトobjectは文字列定数プールに格納され、最後にsはこのオブジェクトのアドレスを指し、「abc」が文字列定数プールに保存されている場合、文字列定数プールで値が「abc」のオブジェクトobjectが見つかり、sはこのオブジェクトのアドレスを指す.
    1つ目の特徴:JVMは、スタック内のデータの実際の状況に基づいて、新しいオブジェクトを作成する必要があるかどうかを自動的に決定します.
    2つ目は、2ステップ1、String object=「abc」に分解することができる.2、String s = new String(object); 第1のステップは第1の作成方法を参照し、第2のステップはabcが文字列定数プールに作成され保存されているため、jvmはスタックにStringオブジェクトを新規に作成し、その値はスタックに既存の3つのchar型値を共有するだけです.
    2つ目の特徴:文字列の値が等しいかどうかにかかわらず、スタックに新しいオブジェクトを作成する必要があるかどうかにかかわらず、すべてスタックに新しいオブジェクトを作成します.
    文字列の比較を話す前に、==とequalsの違いを理解する必要があります.
JavaはすべてのクラスがObjectベースクラスに継承され、Objectではequalsが==で実現されるため、equalsと==は同じであり、比較対象アドレスであり、java apiのクラスの大部分はequalsメソッドを書き換え、基本データ型のパッケージクラス、Stringクラスなどを含む.Stringクラス==2つのStringオブジェクトを比較するためのアドレスで、equalsは2つのStringオブジェクトの内容(値)を比較するために使用されます.
 
例1.文字列定数プールの使用
String s0="abc";
String s1="abc";
System.out.println(s0==s1);//true   s0,s1      

 
 
String s0=new String ("abc");
String s1 = new String ("abc");
System.out.println(s0==s1); //false,new           
System.out.println(s0.equals(s1));  //true, equals      String     

 
String s0="helloworld"; 
String s1="helloworld"; 
String s2="hello" + "word"; 
System.out.println( s0==s1 ); //true     s0 s1       
System.out.println( s0==s2 ); //true     s0 s2      

    解析:例のs 0とs 1の「helloworld」は文字列定数であり、コンパイル期間中に決定されるため、s 0=s 1はtrueであり、「hello」と「world」も文字列定数であり、1つの文字列が複数の文字列定数で接続されている場合、それ自体も文字列定数であるに違いないので、s 2も同様にコンパイル期間中に1つの文字列定数として解析されるので、s 2も定数プールの「helloworld」の参照である.
 
String s0="helloworld"; 
String s1=new String("helloworld"); 
String s2="hello" + new String("world"); 
System.out.println( s0==s1 ); //false  
System.out.println( s0==s2 ); //false 
System.out.println( s1==s2 ); //false

 解析:new String()で作成された文字列は定数ではなく、コンパイル期間中に決定できないため、new String()で作成された文字列は定数プールに入れられず、独自のアドレス空間があります.
s 0は定数プールの「helloworld」の参照であり、s 1はコンパイル期間で確定できないため、実行時に作成された新しいオブジェクト「helloworld」の参照であり、s 2は後半のnew String("world")があるためコンパイル期間でも確定できないため、新しい作成オブジェクト「helloworld」の参照でもある.
String s0 = "a1"; 
String s1 = "a" + 1; 
System.out.println((s0 == s1)); //result = true  
String s2 = "atrue"; 
String s3= "a" + "true"; 
System.out.println((s2 == s3)); //result = true  
String s4 = "a3.4"; 
String s5 = "a" + 3.4; 
System.out.println((a == b)); //result = true

   解析:プログラムコンパイル期間中、JVMは定数文字列の「+」接続を接続後の値に最適化し、「a」+1で言えば、コンパイラによって最適化されたclassではすでにa 1である.コンパイル期間中に文字列定数の値が決定されるので、上記のプログラムの最終的な結果はtrueです.
String s0 = "ab"; 
final String s1 = "b"; 
String s2 = "a" + s1;  
System.out.println((s0 == s2)); //result = true

 
解析:および[6]で唯一異なるのは、s 1文字列にfinal修飾が付加されていることであり、final修飾の変数については、コンパイル時に定数値として解析されたローカルコピーが自分の定数プールに格納されたり、バイトコードストリームに埋め込まれたりする.したがって、この場合の「a」+s 1と「a」+「b」の効果は同じである.従って、上記のプログラムの結果はtrueである.
 
String s0 = "ab"; 
final String s1 = getS1(); 
String s2 = "a" + s1; 
System.out.println((s0 == s2)); //result = false 
private static String getS1() {  return "b";   }

 
解析:JVMは文字列参照s 1に対して、その値はコンパイル中に確定できず、プログラム実行中にメソッドを呼び出した後、メソッドの戻り値と「a」を動的に接続し、アドレスをs 2に割り当てるため、上記のプログラムの結果はfalseである.