Pythonでオブジェクトの比較の時に気をつけることと、 同じような事でJavaのString型の比較の時に気をつけることについて。
Pythonで2つの物が同値かどうか確認するには ==
を使う方法とis
を使う方法がありますが、 これらは少し違うものです。
Immutable 1 なintやstring等の場合には基本的に結果は同じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
一方、Mutableなリストとかだと
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
の様に、is
の方だと同値とみなしません。
これは、==
の方は値を比較しているのに対して、 is
の方は同じオブジェクト(同じID、メモリ上のアドレスに対応するもの)かどうかを比較してるからです。
実際IDを見てみると、
1 2 3 4 5 6 7 8 9 |
|
な感じでint型の方は1
なものは全て同じIDですが、 listの方では値が同じでもIDはそれぞれ違っています。
Javaの型にはプリミティブ型と呼ばれる基本的な方が有り、 byte
, short
, int
, long
, float
, double
, char
, boolean
の基本的な型で小文字で始める型です。
これらに関しては==
で同値かどうか判断します。
一方、String等はオブジェクトで、 オブジェクトは全てequals
というメソッドを持っています。
このequals
はデフォルトで
1 2 3 |
|
という風に定義されていて、==
と同じです。
で、この==
は、オブジェクトの参照先が同じものかどうか、でtrue or falseを返します。
なので、String型とかでも、同じ文字列を持つものでも ==
で判断すると違うオブジェクトであれば違うものと判断されます。
同じ内容かどうか、を判断するために、 String型ではequals
メソッドをオーバーライドして 文字列の内容が同じかどうか、を返す様にしてあります。
1 2 3 4 5 6 7 8 |
|
とすると
s1.equals(s2)
だけ表示されます。
ただ、次の様にnew
を使わずに直接文字列を入れるようにすると
1 2 3 4 5 6 7 8 |
|
とすると
s1 == s2
s1.equals(s2)
と両方表示されます。
この場合はインスタンス化されてない文字列が擬似プリミティブ型と呼ばれ、 "abc"
がs1, s2両方で同じオブジェクトを指す様な形になるので s1 == s2
でもtrueになります。
ですが、普通に文字列の比較をしたい場合には 必ずequals
で比較するべきです。
これと同じように、数字でもInteger型を使う時には ==
で比較するとおかしくなることがあります。
1 2 3 4 5 6 7 8 |
|
とすると
i1.equals(i2)
なのでIntegerを比較する際にもequals
を使います。
Integerに直接数字を入れて
1 2 3 4 5 6 7 8 |
|
比較すると
i1 == i2
i1.equals(i2)
となります。 ただ、これは数値が-128
から127
までの間の場合だけで、 この間ではこれらの数字がおあんじオブジェクトとして扱われますが、 それ以上になるとIntegerに入れる時はインスタンス化されるので
1 2 3 4 5 6 7 8 |
|
比較すると
i1.equals(i2)
の様にequals
だけがtrueを返します。
Pythonの場合もJavaの場合も最初の頃良くわからないまま 適当にやってしまうところですが、 両方見てみると==
の意味合いが 逆な感じになってるのでちょっと混乱の元です。
というかちょっと混乱したのでまとめておきました。
is
ではなく==
。==
ではなくequals
。