[セットトップ]JavaのStringの詳細(繰り返し研究)
JAVAにおけるequalsと==の違い
==2つのオブジェクトのアドレスを比較し,equalsは2つのオブジェクトの内容を比較する.equalsがtrueの場合,==がtrueとは限らないことは明らかである.
しばらく振り回されてまた本を調べて、ついにStringという特殊な相手に少し悟った.
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
}
}
何か問題がありますか.
1.Stringからの懸念
上のプログラムには、いったい何人のオブジェクトがありますか?
多くの人が口にしたかもしれません:2つ、s 1とs 2
どうして?
Stringはfinalクラスで、その値は可変ではありません.
理にかなっているように見えるので、チェックしてみましょう.少しプログラムを変更してください.
結果が表示されます.
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
}
}
プログラムをコンパイルして実行し、出力:s 1==s 2
どうしてs 1==s 2なの?
==明らかに、s 1とs 2は同じStringオブジェクト--「Monday」を参照している!
2.千変万化のString
もう少しプログラムを変更すると、もっと奇妙な発見があります.
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
s 2をnewオペレータで作成します
プログラム出力:
s1 != s2
s1 equals s2
うん、明らかに?
s 1 s 2はそれぞれ2つの「Monday」Stringオブジェクトを参照している
しかし、なぜ2つのプログラムが違うのでしょうか.
3.Stringのプールで泳ぐ
ははは、本をめくってやっと答えを見つけた.
元は、プログラムが実行されると文字列バッファが作成されます.
s 2="Monday"のような表現を使って文字列を作成する場合、JAVAはまず
このStringバッファで同じ値のオブジェクトを探し、最初のプログラムではs 1が先に
プールに入れたので、s 2が作成されると、プログラムは同じ値のs 1を見つけました.
s 2をs 1が参照するオブジェクト「Monday」を参照
2段目のプログラムでは、newオペレータを使用して、彼はプログラムに理解しています.
「新しいものが欲しい!古いものは要らない!」と新しい「Monday」Stingオブジェクトが作成されました
メモリに建てられています.彼らの値は同じですが、位置が異なり、プールで泳いでいます.
一人は岸辺で休んでいます.あら、資源の浪費ですね.同じなのに何を分けなければなりませんか.
4.ダイビングを続ける
プログラムの再変更:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
s2 = s2.intern();
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
今回加入:s 2=s 2.intern();
わあ!プログラム出力:
s1 == s2
s1 equals s2
もとは、プログラムはs 2を新しく作った後に、またintern()で彼を池の中でひっくり返しました
ははは、今回s 2とs 1は同じ対象を引用しました
メモリの消費量を削減
5.==equals()との争い
Stringはオブジェクトです.2つの異なるStringオブジェクトの値が同じかどうかを比較します.
明らかにequals()という方法を用いる
しかし、プログラムにそんなに多くのStringオブジェクトがあれば、equalsを何度も使います.
より良い方法:
すべてのStringをintern()バッファに行きましょう
newを使うときにこの操作をしたほうがいいです.
String s2 = new String("Monday").intern();
Stringオブジェクトの値を=で比較できるようになりました
爽やかですね.速くて便利です.
テストコード:
public class StringAddress {
public static void main(String[] args) { String a = "hehe"; String b = "hehe"; String c = new String("hehe"); String d = a; String e = c.intern(); if (a == b) System.out.println(「a==b---a='hehehe'を使用して文字列を作成する場合、JAVAはまずStringバッファで同じ値を探しますが、見つかったら新しいオブジェクトを作成しません」). if (a == c) System.out.println(「a==c---newオペレータを使用してメモリを再申請」); if (a.equals(c)) System.out.println(「a.equals(c)---値が同じで、メモリアドレスが異なる」); if (a == d) System.out.println("a==d---a==d ==> a.equals(d)"); if (a.equals(d)) System.out.println("a.equals(d)"); if (a == e) System.out.println(「a==e---intern()後はStringプール」); System.out.println(System.getProperty("user.dir")); }}
--------------------------------------------------------------------------------------------
StringとStringBufferの違い
特定の場合、Stringオブジェクトの文字列結合は、JVMによってStringBufferオブジェクトの結合として解釈されるため、Stringオブジェクトの速度はStringBufferオブジェクトよりも遅くはありません.特に、以下の文字列オブジェクト生成では、String効率はStringBufferよりもはるかに速いです.String S 1=「This is only a」+「simple」+"test";StringBuffer Sb=new StringBuilder("This only a").append("simple").append("test");String S 1オブジェクトを生成する速度が速すぎて、この時StringBufferは意外にも速度的に全然優勢ではありません.実はこれはJVMのトリックで、JVMの目には、このString S 1="This is only a"+"simple"+"test";実はString S 1="This is only a simple test";だからもちろんあまり時間はかかりません.しかし、ここで注意しなければならないのは、文字列が別のStringオブジェクトから来ている場合、速度はそれほど速くありません.例えば、String S 2="This is is only a";String S 3="simple";String S 4="test";String S 1=S 2+S 3+S 4;このときJVMはきちんとしたやり方で
//String+String String tempstr = "abcdefghijklmnopqrstuvwxyz"; int times = 3500; long lstart1 = System.currentTimeMillis(); String str = ""; for (int i = 0; i < times; i++) { str += tempstr; } long lend1 = System.currentTimeMillis(); long time1 = (lend1 - lstart1)/1000; System.out.println(「String+String時間:」+time 1+「ミリ秒」); //"abcdefghijklmnopqrstuvwxyz"+"abcdefghijklmnopqrstuvwxyz" long lstart2 = System.currentTimeMillis(); for (int i = 0; i < times; i++) { str = "abcdefghijklmnopqrstuvwxyz"+"abcdefghijklmnopqrstuvwxyz"; } long lend2 = System.currentTimeMillis(); long time2 = (lend2 - lstart2)/1000; System.out.println("a b cdefghijklmnopqrstuvwxyz+a b cdefghijklmnopqrstuvwxyz時間:"+time 2+"ミリ秒");
//StringBuffer.append() long lstart3 = System.currentTimeMillis(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < times; i++) { sb.append(tempstr); } long lend3 = System.currentTimeMillis(); long time3 = (lend3 - lstart3)/1000; System.out.println(「StringBuffer.append()時間:」+time 3+「ミリ秒」);
---------------------------------------------------------------------------------------------
いくつかのオブジェクトが作成されました
String s = new String(「xyz」).この文はいくつのオブジェクトを作成しますか?1つかもしれません.定数プールにはすでに「xyz」というオブジェクトが存在する可能性があるため、この文は定数プールに作成されず、スタックに1つのオブジェクトのみが作成されます.定数プールに「xyz」が存在しない場合、2つが作成されます.
String s="a"+"b";いくつかのオブジェクトを作成
次に、私の推測を簡単に証明し、まずこのクラスをコンパイルします.
classファイルの代替をコピーし、次のように変更します.
再コンパイルし、ueなどのテキストエディタで開き、バイナリの内容を見ると、2つのclassファイルが完全に一致し、1バイトも悪くないことがわかります.
OK,真相が明らかになった.実行期間の処理String b=「a」+「b」はまったく存在しない.このようなコードの問題は,コンパイル時に直接最適化された.
Stringプールには、「」および+を使用して作成されたStringオブジェクトのみが追加され、newまたはString変数+「」を使用する他の状況は、オブジェクトを格納するスタックにあります.
スタック(Stack):レジスタに次ぐ速度で基本タイプ(byte,int,char)とオブジェクト参照を保存します.
ヒープ(heap):複雑なオブジェクトを格納します.Stringにはchar[]型配列で格納されたValue属性があります.
==2つのオブジェクトのアドレスを比較し,equalsは2つのオブジェクトの内容を比較する.equalsがtrueの場合,==がtrueとは限らないことは明らかである.
しばらく振り回されてまた本を調べて、ついにStringという特殊な相手に少し悟った.
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
}
}
何か問題がありますか.
1.Stringからの懸念
上のプログラムには、いったい何人のオブジェクトがありますか?
多くの人が口にしたかもしれません:2つ、s 1とs 2
どうして?
Stringはfinalクラスで、その値は可変ではありません.
理にかなっているように見えるので、チェックしてみましょう.少しプログラムを変更してください.
結果が表示されます.
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
}
}
プログラムをコンパイルして実行し、出力:s 1==s 2
どうしてs 1==s 2なの?
==明らかに、s 1とs 2は同じStringオブジェクト--「Monday」を参照している!
2.千変万化のString
もう少しプログラムを変更すると、もっと奇妙な発見があります.
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
s 2をnewオペレータで作成します
プログラム出力:
s1 != s2
s1 equals s2
うん、明らかに?
s 1 s 2はそれぞれ2つの「Monday」Stringオブジェクトを参照している
しかし、なぜ2つのプログラムが違うのでしょうか.
3.Stringのプールで泳ぐ
ははは、本をめくってやっと答えを見つけた.
元は、プログラムが実行されると文字列バッファが作成されます.
s 2="Monday"のような表現を使って文字列を作成する場合、JAVAはまず
このStringバッファで同じ値のオブジェクトを探し、最初のプログラムではs 1が先に
プールに入れたので、s 2が作成されると、プログラムは同じ値のs 1を見つけました.
s 2をs 1が参照するオブジェクト「Monday」を参照
2段目のプログラムでは、newオペレータを使用して、彼はプログラムに理解しています.
「新しいものが欲しい!古いものは要らない!」と新しい「Monday」Stingオブジェクトが作成されました
メモリに建てられています.彼らの値は同じですが、位置が異なり、プールで泳いでいます.
一人は岸辺で休んでいます.あら、資源の浪費ですね.同じなのに何を分けなければなりませんか.
4.ダイビングを続ける
プログラムの再変更:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
s2 = s2.intern();
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
今回加入:s 2=s 2.intern();
わあ!プログラム出力:
s1 == s2
s1 equals s2
もとは、プログラムはs 2を新しく作った後に、またintern()で彼を池の中でひっくり返しました
ははは、今回s 2とs 1は同じ対象を引用しました
メモリの消費量を削減
5.==equals()との争い
Stringはオブジェクトです.2つの異なるStringオブジェクトの値が同じかどうかを比較します.
明らかにequals()という方法を用いる
しかし、プログラムにそんなに多くのStringオブジェクトがあれば、equalsを何度も使います.
より良い方法:
すべてのStringをintern()バッファに行きましょう
newを使うときにこの操作をしたほうがいいです.
String s2 = new String("Monday").intern();
Stringオブジェクトの値を=で比較できるようになりました
爽やかですね.速くて便利です.
テストコード:
public class StringAddress {
public static void main(String[] args) { String a = "hehe"; String b = "hehe"; String c = new String("hehe"); String d = a; String e = c.intern(); if (a == b) System.out.println(「a==b---a='hehehe'を使用して文字列を作成する場合、JAVAはまずStringバッファで同じ値を探しますが、見つかったら新しいオブジェクトを作成しません」). if (a == c) System.out.println(「a==c---newオペレータを使用してメモリを再申請」); if (a.equals(c)) System.out.println(「a.equals(c)---値が同じで、メモリアドレスが異なる」); if (a == d) System.out.println("a==d---a==d ==> a.equals(d)"); if (a.equals(d)) System.out.println("a.equals(d)"); if (a == e) System.out.println(「a==e---intern()後はStringプール」); System.out.println(System.getProperty("user.dir")); }}
--------------------------------------------------------------------------------------------
StringとStringBufferの違い
特定の場合、Stringオブジェクトの文字列結合は、JVMによってStringBufferオブジェクトの結合として解釈されるため、Stringオブジェクトの速度はStringBufferオブジェクトよりも遅くはありません.特に、以下の文字列オブジェクト生成では、String効率はStringBufferよりもはるかに速いです.String S 1=「This is only a」+「simple」+"test";StringBuffer Sb=new StringBuilder("This only a").append("simple").append("test");String S 1オブジェクトを生成する速度が速すぎて、この時StringBufferは意外にも速度的に全然優勢ではありません.実はこれはJVMのトリックで、JVMの目には、このString S 1="This is only a"+"simple"+"test";実はString S 1="This is only a simple test";だからもちろんあまり時間はかかりません.しかし、ここで注意しなければならないのは、文字列が別のStringオブジェクトから来ている場合、速度はそれほど速くありません.例えば、String S 2="This is is only a";String S 3="simple";String S 4="test";String S 1=S 2+S 3+S 4;このときJVMはきちんとしたやり方で
//String+String String tempstr = "abcdefghijklmnopqrstuvwxyz"; int times = 3500; long lstart1 = System.currentTimeMillis(); String str = ""; for (int i = 0; i < times; i++) { str += tempstr; } long lend1 = System.currentTimeMillis(); long time1 = (lend1 - lstart1)/1000; System.out.println(「String+String時間:」+time 1+「ミリ秒」); //"abcdefghijklmnopqrstuvwxyz"+"abcdefghijklmnopqrstuvwxyz" long lstart2 = System.currentTimeMillis(); for (int i = 0; i < times; i++) { str = "abcdefghijklmnopqrstuvwxyz"+"abcdefghijklmnopqrstuvwxyz"; } long lend2 = System.currentTimeMillis(); long time2 = (lend2 - lstart2)/1000; System.out.println("a b cdefghijklmnopqrstuvwxyz+a b cdefghijklmnopqrstuvwxyz時間:"+time 2+"ミリ秒");
//StringBuffer.append() long lstart3 = System.currentTimeMillis(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < times; i++) { sb.append(tempstr); } long lend3 = System.currentTimeMillis(); long time3 = (lend3 - lstart3)/1000; System.out.println(「StringBuffer.append()時間:」+time 3+「ミリ秒」);
---------------------------------------------------------------------------------------------
いくつかのオブジェクトが作成されました
String s = new String(「xyz」).この文はいくつのオブジェクトを作成しますか?1つかもしれません.定数プールにはすでに「xyz」というオブジェクトが存在する可能性があるため、この文は定数プールに作成されず、スタックに1つのオブジェクトのみが作成されます.定数プールに「xyz」が存在しない場合、2つが作成されます.
String s="a"+"b";いくつかのオブジェクトを作成
次に、私の推測を簡単に証明し、まずこのクラスをコンパイルします.
public class Test {
private String s = "ab";
}
classファイルの代替をコピーし、次のように変更します.
public class Test {
private String s = "a" + "b";
}
再コンパイルし、ueなどのテキストエディタで開き、バイナリの内容を見ると、2つのclassファイルが完全に一致し、1バイトも悪くないことがわかります.
OK,真相が明らかになった.実行期間の処理String b=「a」+「b」はまったく存在しない.このようなコードの問題は,コンパイル時に直接最適化された.
Stringプールには、「」および+を使用して作成されたStringオブジェクトのみが追加され、newまたはString変数+「」を使用する他の状況は、オブジェクトを格納するスタックにあります.
スタック(Stack):レジスタに次ぐ速度で基本タイプ(byte,int,char)とオブジェクト参照を保存します.
ヒープ(heap):複雑なオブジェクトを格納します.Stringにはchar[]型配列で格納されたValue属性があります.