Java – 演算子 – 文字列結合

文字列同士の結合

+演算子の左右のオペランドが文字列の時、演算子は文字列結合として機能する。

文字列以外との結合

数値との結合

左右のオペランドの何れか1つが文字列の時も文字列結合として機能し、他方のオペランドは文字列に変換された後に結合される。

以下は文字列と数値を+演算子で結んだ場合で、数値が文字列に変換されて結合される。左右とも数値の場合は、当然数値の加算演算子として機能する。

char型との結合

char型の場合も文字列として結合される。左右ともchar型の場合はchar同士の値の加算(以下の例では’a’ + ‘b’ = $61 + $62 = $C3 = 195)。

一般的のオブジェクトとの結合

+演算子のオペランドの1つが文字列で他方がそうでないとき、演算子は文字列でない方のオペランドの文字列表現を結合する。

たとえば配列同士の+演算子は定義されていないが、文字列と配列を+演算子で結ぶと配列の方が文字列表現(ハッシュ)になり、もう1法の文字列と結合される。

以下の例はtoString()が実装されたクラスのオブジェクトと文字列の結合例で、Listオブジェクトが文字列化された後に結合されている。

 

 

Java – 演算子 – 代入演算子

数値に対する代入演算子

a = b bの値をaに代入する
a += b a = a + bと等価
a -= b a = a ― bと等価
a *= b a = a * bと等価
a /= b a = a / bと等価
a %= b a = a % bと等価

+=など演算と代入を同時に行う演算子を複合代入演算子(compound assignment operator)と呼ぶ。複合代入演算子と対比する場合は、=を単純代入演算子(simple assignment operator)と呼ぶ。

代入演算子の左辺に置けるのは変数のみで、リテラルや式は置けない。

宣言文で使えるのは=のみで、+=などの複合代入演算子は使えない。

文字列に対する代入演算子

a = b aの内容をbに代入する
a += b aの文字列とbの文字列を結合した結果をaに代入する

左辺が変数でなければならない点、宣言文で+=が使えない点は数値に対する場合と同じ。

なお、左辺はString型の変数でなければならないが、右辺はString型のほかchar型でもよい。

 

Java – プリミティブ型 – 最大値・最小値

概要

数値表現可能なプリミティブ型の最大値・最小値は、それぞれのラッパークラスの定数として定義されている。

WrapperClass.MAX_VALUE
WrapperClass.MIN_VALUE

整数型、実数型、文字型で、それぞれの意味が異なる。

整数型の最大値・最小値

整数型の最大値・最小値は、それぞれのビット長で表現可能な符号付整数の最大値(正数)、最小値(負数)。

byte型

short型

int型

long型

整数型のオバーフロー/アンダーフロー

整数型の最大値を超える演算や最小値を下回る演算をすると、その方の範囲内のビットパターンで表現される値になる。

実数型の最大値・最小値

実数型の最大値・最小値は整数型と異なり、次の値。

最大値
正の数で表現できる最大の数
最小値
正の数で表現できる絶対値が最も小さい数

したがって、負の領域で表現可能な最小値は最大値のマイナス、負の領域で表現可能な絶対値が最小の数は最小値のマイナスになる。

float型

double型

実数型のオーバーフロー/アンダーフロー

実数型の最大値を超える演算をするとInfinityまたは-Infinityになる。

実数型の最小値の絶対値を下回る計算をすると、0.0または−0.0になる。

文字型の最大値・最小値

char型

char型の最小値は文字コード0の文字、最大値は文字コード65535の文字。

文字型のオーバーフロー/アンダーフロー

char型の最大値を超える演算や最小値を下回る演算をすると、それで表現可能な整数型に変換される。

 

Java – 演算子 – 算術演算子

概要

算術演算子はbyte型~long型などの整数や実数(float型double型)を対象とした演算子で、文字型のcharも演算対象になる。

<単項演算子>

+a 正符号、意味はない
-a 負符号、正負反転
++a 参照前インクリメント
a++ 参照後インクリメント
--a 参照前デクリメント
a-- 参照後デクリメント

<二項演算子>

a + b 加算
a - b 減算
a * b 乗算
a / b 除算
a % b 剰余

単項演算子

+:正符号

数値リテラルや数値型変数の前に置く。正数・負数とも符号は変わらず、実質意味を持たない。

-:負符号

数値リテラルや数値型変数の前に置き、符号を反転させる。

符号演算子の連続

単項演算子は交互に連続して書くことができて、その結果は負符号’-‘が偶数回なら’+‘と同じ、奇数回なら’-‘と同じ結果になる。

ただしその中に--++のように連続した符号があると、インクリメント/デクリメント演算子と解釈されてエラーになる。

++/–:インクリメント/デクリメント

  • ++を変数の直前に書くと「変数が評価される前に」変数の内容が1増加する
  • ++を変数の後に書くと「変数が評価された後に」変数の内容が1減少する
  • 演算子と変数の間に空白が入ってもよい。

整数の例

以下の例では、演算子が前置された場合は表示前にインクリメント/デクリメントされ、後置された場合は表示後にインクリメント/デクリメントされる。

また、以下の例では二項演算子の項にインクリメント/デクリメント演算子を使った例。

 

上記の例をnの変化で表すと以下の様になる。

3(→4) + →5 – 5(→4) = 3(4)

実数の例

実数の場合も++で1.0増加、--で1.0減少になるが、計算誤差が出る。

char型の例

char型にも適用可能で、インクリメントで1文字進み、デクリメントで1文字戻る。

二項演算子

四則演算

四則演算は多言語と同じ記号で、整数・実数の関係も同じ。整数同士の演算は整数で桁数が多い方に自動的にキャストされ、2項のうちいずれかでも実数なら結果も実数になる。

+:加算

-:減算

*:乗算

/:除算

%:剰余

abで割った時の剰余(余り)をa % bで与える。実数表現でも整数商に対する剰余が計算される。

除数・被除数が小数部を持つ場合、整数商に対する剰余が実数で計算される。

除数・被除数が負数の場合は、商と剰余の以下の式から考える。

(1)    \begin{equation*} a / b = q, \; a \% b = r \quad \Leftrightarrow \quad a = b q + r \end{equation*}

たとえば以下のように。

(2)    \begin{equation*} -7 \% (-2) = -1 \quad \Leftarrow \quad -7 = -2 \times 3  - 1 \end{equation*}

 

ゼロによる除算

整数除算でゼロで割ると実行時例外となる。剰余も除算を行っているので同じ。

浮動小数点演算の場合にゼロで割ると例外にならず、結果はInfinityとなる。剰余計算の場合は結果はNaN

べき乗

べき乗の演算子はなく、必要ならMathpow()メソッドを使う。

 

Java – 配列 – 同一性・等価性

概要

配列の同一性は変数が指しているインスタンスが同じかどうかのみによるが、等価性の場合は末端の要素一つ一つが等価かどうかを判定することになる。

Javaの配列で等価性を判定する場合、1次元配列はArrays.equals()で等価性を判定できるが、2次元以上の配列になるとArrays.deepEquals()で判定しなければならない。

配列のコピーでもディープコピーができるメソッドがなくループで回さないといけないなど、Javaの配列は使いにくい。というよりも、下手に使うと思わぬところでミスの要因になりそう。

1次元配列

同一性(==)

配列変数が指している対象が同じかどうか。内容が同じでも変数が指しているインスタンスが異なる場合は同一にならない。

以下の例ではarray1array2が同じ配列インスタンスを指している(ハッシュ値が等しい)ので、内容が変わっても同一。

一方で変更前のarray1array4、変更後のarray1array3は、内容が同じでも配列のインスタンスが異なるため、同一とは判定されない。

等価性(Array.equals)

配列の内容が同じかどうか。異なる配列インスタンスでも内容が同じなら等価。同値性とも。

配列の等価性をチェックするにはArrays.equals()メソッドを使う。

以下の例では、array1array2は同一であり等価。array1の変更前はarray3と等価だが、変更後にはarray4と等価になる。

equals()メソッドは要注意

配列もオブジェクトとしてequals()メソッドを備えているが、これは同一性の判定しかせず、等価性の判定には使えない。

以下の例で、結果が==のときと同じになっているのが確認できる。

多次元配列

Array.equals()も要注意

Arrays.equals()clone()の挙動と似ていて、

  • 1次元目の各要素が同一なら結果はtrue
  • 1次元目の各要素のいずれかが同一でないなら結果はfalse

多次元配列でArray.equals()を使うと、2次元目の要素配列が同一であればtrueとなり、同一でなければ内容が同じでもfalseとなる。

以下の例では、

  • array2d1array2d2は元のインスタンスが同一であり等価
  • array2d1からclone()で作られたarray2d3は、元のインスタンスは異なるが、それが指している要素が同じなので同一ではないが等価
  • array2d3array2d4も、元のインスタンスから要素に至るまでarray2d1と異なるため、変更前/変更後に内容が同じになっても等価と判定されない

Arrays.equals()の等価性判定は1次元配列にしか使えない

深層比較(deepEquals)

Arrays.deepEquals()は、引数の2つの配列の要素の等価性を再帰的に判定する。

 

 

Java – 配列 – コピー

概要

Javaにおける配列のコピーについて整理する。

  • 1次元配列はclone()メソッドかSystem.arraycopy()メソッド
  • 多次元配列は次元分forでネストしてclone()System.arraycopy()

Javaの配列は扱いづらく、deepToString()deepEquals()はあるのにdeepCopy()がないのが不思議。

代入(assignment)

配列変数を他の変数に代入した場合、代入先の変数が元の変数と同じ配列を参照する。一方での変更が他方の結果にも反映される。

下記コードで、2つの配列のハッシュ値が同じこと、片方の変更が他方にも反映されることが確認できる。

clone()

clone()メソッドは配列の要素の「内容」を順次コピーして新たな配列を返す。一方の配列への変更は他方に影響しない。プリミティブ型の配列でも使える。

以下のコードで、2つの変数のハッシュ値が異なること、一方の変更が他方に影響していないことが確認できる。

System.arraycopy()

System.arraycopy()メソッドは引数にコピー元・コピー先の配列とコピー位置、コピー長さを指定して、コピー先にはコピー元の要素が複製された新たな配列が与えられる。clone()と同じく、一方の配列への変更は他方に影響しない。

System.copy(元配列, 元開始位置, 先配列, 先開始位置, コピー長)

clone()はシャローコピー

多次元配列をclone()でコピーしてもディープコピーにはならない。一方の配列への変更が他方に影響する。

以下のコードで、1次元目は違うハッシュ値でコピーされているが、それぞれが持っている要素配列はそのままのハッシュ値でコピーされている。

これは、clone()で元の配列の要素(配列)が新たなインスタンスとして複製されるが、その要素は単に代入されるだけで再帰的に複製されないため。

多次元配列のディープコピー

多次元配列をディープコピーするには、最後の要素までclone()で複製する必要がある。

2つの配列を同時に扱うのにPythonのzipのような機能がないので、カウンターで回さないといけない。

 

Java – 配列 – Object配列

概要

Object配列は、任意のオブジェクトを要素とすることができ、異なる型の要素を持つことができる。

1次元のObject配列

イニシャライザー

配列の型をObject[]とすると、任意の型・クラスの値を要素に持つことができる。

newによる初期化

多次元のObject配列

多次元のObject配列をイニシャライザーで宣言することもできるが、ダイナミックに要素を追加していくこともできる。

以下の例では、まず1次元のObject配列を要素数を与えて生成し、1つ目の要素はString型の要素、2つ目と3つ目はObject配列を要素配列として生成してセットしている。

 

 

Java – 配列 – 多次元配列

初期化

多次元配列の型はtype[][]...で表し、1次元と同じくイニシャライザーやnewで初期化できる。

newとイニシャライザーを使うと、要素配列を個別に定義することが可能。

内容表示

多次元配列を表示するには、ループで回すかArrays.deepToString()を使う(Java – 配列 – 内容表示)。

 

Java – 配列 – 内容表示

そのままだとオブジェクトの表示

Javaの配列をそのまま表示しようとすると、参照値が表示される。

Arrays.toString()

配列の内容を文字列として表現するには、java.util.ArraystoString()メソッドを使う。

多次元配列の場合

多次元配列の親配列をtoString()で表示しても下位次元までは適切に表示してくれない。

ループによる表示

ループを回して表示させることは考えられる。

Arrays.deepToString()

Arrays.deepToString()メソッドを使うと、多次元配列の内容を手軽に表示できる。

 

Java – 配列 – 長さ(サイズ)

配列の長さ(サイズ)はlengthプロパティーで得られる。Stringの場合のlength()メソッドと異なるので注意。

多次元配列の場合、親の配列の長さは子配列の数になる。