初心者入門レベルの【Javaの勉強】数値計算に必要な変数や演算子
2020/04/02
まずは簡単な数値計算をするために、以下のプログラムを作成します。
public class JavaTest01 {
public static void main(String[] args) {
int a = 3 + 4; //変数aに計算結果を代入
System.out.println(a); //aの中身を表示
}
}
これは「3 + 7」の計算結果を表示するためのプログラムになりますが、早速コンパイルして実行してみると以下のようになりました。
>javac JavaTest01.java
>java JavaTest01
7
>
意図したとおり、「3 + 4 = 7」の計算結果が表示されることが確認できましたね。
変数の宣言
このプログラムでは、変数「a」に、「3+4」の計算結果の値を代入しています。
コンピュータはメモリ上に数値をビット列のデータとして記憶し、それをCPUが取り出して計算をします。
メモリには1バイト単位で「アドレス」が付いていて、このアドレスを使ってメモリ上の位置を指定しますが、一つのアドレスが示すメモリの領域が記憶できるデータの大きさには限りがあります。
そのため大きなデータをメモリに記憶するには複数のアドレスを使う必要がありますが、複数のアドレスに記憶されたデータを利用する場合、データの先頭アドレスだけでなく、その領域の大きさが分かっている必要があります。
と言ってもそれらをプログラム上で管理するのは大変なので、Javaのような一般的なプログラミング言語では、「変数」という形でメモリ上の領域を確保し管理するような仕組みになっています。
変数はプログラム内で使用する前に、「修飾子」+「データ型」+「変数名」という形で宣言をする必要があります。
「修飾子」は変数の性質を決めるもので、「public」「private」などがあります。
「データ型」は変数のデータの種類や大きさを指定するもので、「int」「float」などがありますが、これについては後述します。
「変数名」は前回の「クラス名」と同じく識別子になりますので、「変数名」を付ける場合は「クラス名」と同様に識別子としての決まりに従うことになります。
また決まりだけでなく“慣例”として「変数名」は小文字で始めて、単語の区切りとなる最初の文字を大文字にするということがあります。
例えば「my」+「name」という2つの単語を使った変数名の場合は、「myName」というように記述します。
基本データ型の宣言
Java言語で扱うデータ型は、大きく2つに分けて「基本データ型(基本型とプリミティブ型)」と「参照型」がありますが、ここでは「基本データ型」について勉強しましょう。
「基本データ型」には、以下のようなものがあります。
変数の型 | タイプ | サイズ | 値の範囲 |
---|---|---|---|
boolean | 論理型 | 1ビット | trueまたはfalse |
byte | 整数型 | 8ビット | -128から127 |
short | 整数型 | 16ビット | -32,768,から32,767 |
int | 整数型 | 32ビット | -2,147,483,648から2,147,483,647 |
long | 整数型 | 64ビット | -9,223,372,036,854,775,808から9,223,372,036,854,775,807 |
float | 実数型 | 32ビット | ±3.40282347E+38から±1.40239846E-45 |
double | 実数型 | 64ビット | ±1.79769313486231570E308から4.94065645841246544E-324 |
char | 文字列 | 16ビット | Unicode('\u0000'から'\uffff') |
どのデータ型も大きさ(サイズ)が決まっていて、それぞれ表現できるデータの種類や値の範囲も決まっています。
ですから表現できないデータの種類を設定したり、その値の範囲を超えたりした場合はエラーになったり、エラーにならなくても間違った動作をするといった問題が起きますので注意が必要です。
これらのデータ型を使って変数を宣言しますが、例えば「int型」の変数「a」を宣言する場合は以下のようになります。
int a;
また宣言すると同時に、その変数の中身を決まった値にすることができますが、これを「変数の初期化」と呼んで、以下のように記述します。
int a = 10;
もちろんこれは同時にしないで、以下のように別々に記述することもできます。
int a;
a = 10;
また複数の変数をカンマで区切って、一度に宣言したり初期化することもできます。
int a, b, c;
int a = 10, b = 20, c = 30;
定数とリテラル
プログラムでは値の変化する「変数」に対して値の変化しない「定数」や「リテラル」というものもあり、「変数」と同じく宣言と初期化をして使いますが、いったん初期化をしたら、後で値を変更できません。
「定数」の宣言には「final」を使って、以下のように記述します。
final int WEEK = 7;
final int WEEK;
WEEK = 7;
この「定数」も「識別子」の決まりに従って名前を着けることになりますが、「変数」のときと同様に“慣例”としてすべて大文字で書き、複数の単語を使うときは「_」(アンダーライン)でつなげます。
また「リテラル」というのはプログラム中に直接記述する値のことで、例えば「10」とか「24」とかの整数は「整数リテラル」と呼んだりします。
「リテラル」もメモリ上の領域を使って記憶されているので、「変数」に値を代入する場合はメモリ上で「リテラル」の領域から「変数」の領域にデータをコピーするというイメージになります。
でもこの「リテラル」はあらかじめ宣言されたものではありませんので、そのデータの種類や値の範囲は宣言された「変数」のようには決められていません。
前述のようにデータの種類や値の範囲が決められないことには、メモリ上にそのデータを保存することはできませんが、それでは「リテラル」の場合はどうなっているのでしょうか?
実は普通に「整数リテラル」を記述した場合、自動的に「int型」になるようになっていて、それを確認するために以下のプログラムをコンパイルしてみます。
public class JavaTest02 {
public static void main(String[] args) {
System.out.println(2147483648); //int型の最大値を超える値
}
}
>javac JavaTest02.java
JavaTest02.java:3: エラー: 整数2147483648が大きすぎます
System.out.println(2147483648); //int型の最大値を超える値
エラー1個
>
「整数2147483648が大きすぎます」というコンパイルエラーになることが分かりますが、これは「int型」の範囲を超えているという意味のエラーになります。
試しに「2147483648」を1減らして「int型」の範囲の最大値の「2147483647」に変えてやると、コンパイルも実行も問題無くできることが確認されます。
では「int型」の領域を超えるような値を使いたい場合はどうするかというと、「整数リテラル」の型を指定してやる方法があるんですね。
例えば上記のプログラムのエラーような場合は「long型」にしてやると領域内に収まりますが、そのときは「2147483648L」というように記述します。
このようにリテラルの型指定のために末尾につけるアルファベットを「サフィックス」と呼びますが、これは大文字でも小文字でも問題ありません。
また小数の値を持つ「リテラル」を「実数リテラル」とよびますが、これは自動的に「double型」として扱われます。
ですから例えば「3.14」を「float型」の変数に代入する場合、以下のように記述するとエラーになります。
float x = 3.14;
これは「float型」の変数に「double型」の値を代入しようとしていることになって、「float型」の領域をオーバーしてしまうためです。
ですから、このようなときは以下のように「サフィックス」を付けて「実数リテラル」を「double型」から「float型」にしてやる必要があります。
float x = 3.14F;
代入演算子と算術演算子
さて、それでは最後に演算子について勉強します。
これまで出てきた「変数」「定数」「リテラル」といったデータの値を使って計算を行うときは、「演算子」を使う必要があります。
演算子には、「算術演算子」「代入演算子」「比較演算子」「論理演算子」「ビット演算子」などがあります。
例えば冒頭のプログラムの「a = 3 + 4」で使った「=」は代入演算子で、「+」は「算術演算子」になります。
ここではその「代入演算子」と「算術演算子」について勉強しましょう。
まず「代入演算子」ですが、これは変数に値をコピーするために使います。
通常のコピーするだけの演算子を「単純代入演算子」と呼んで、これまでのプログラムにも何度も出てきていますが「=」と記述します。
使い方は簡単で、演算子の左にコピー先の変数を記述し、右にコピー元の値を記述するだけです。
またコピーの際に同時に演算を行うものもあって、これを「複合代入演算子」と呼びます。
例えば以下のような記述において、「+=」が複合代入演算子」にあたります。
a = 5;
a += 3;
このとき「a」に「3」を代入するのではなく、元の値の「5」に「3」を加算した値を代入するので、結果として「a」の値は「8」になります。
これら「代入演算子」をまとめると、次の表のようになります。
演算子 | 呼び名 | 使用例 | 意味 |
---|---|---|---|
= | 単純代入演算子 | x = 10 | xに右辺の値を代入する |
+= | 複合代入演算子 | x += 10 | xの値を右辺の値で演算して、その結果を代入する |
-= | |||
*= | |||
/= | |||
%= |
続いて「+」や「-」といった「算術演算子」ですが、こちらは通常の計算式とほとんど変わりないので説明するまでも無いでしょう。
算術演算子をまとめると、次の表のようになります。
演算子 | 呼び名 | 使用例 | 意味 |
---|---|---|---|
+ | 加算演算子 | x + y | xとyを加える |
- | 減算演算子 | x - y | xからyを引く |
* | 乗算演算子 | x * y | xとyを掛ける |
/ | 除算演算子 | x / y | xをyで割る |
% | 剰余演算子 | x % y | xをyで割った余り |
++ | インクリメント演算子 |
++x x++ |
++xはxを1増加させた後にxを評価する。 x++はxを評価した後に1増加させる。 |
-- | デクリメント演算子 |
--x x-- |
--xはxを1減少させた後にxを評価する。 x--はxを評価した後に1減少させる。 |
この中にも「複合代入演算子」のように二つの記号をつなげた「++」と「--」という演算子がありますが、それぞれ「インクリメント演算子」「デクリメント演算子」と呼びます。
これはどういう働きをするかというと、値を1ずつ増加や減少させるものです。
例えば「++3」のように書きますが、このときに「++3」と書くのと「3++」と書くのでは意味が変わってくるので要注意です。
「++3」のように演算子を前に書いた場合は、値を1だけ増やしてから処理を行います。
逆に「3++」のように演算子を後ろに書いた場合は、処理を行った後に1だけ値を増やします。
一般に前者を「演算してから評価する」と言い、後者を「評価してから演算する」と言いますが、これらの動作の確認のために以下のプログラムを書いて試してみましょう。
public class JavaTest03 {
public static void main(String[] args) {
int a = 3;
System.out.println(++a); //演算してから評価(値を表示)
a = 3;
System.out.println(a++); //評価(値を表示)してから演算
System.out.println(a); //aの値を表示
a = 3;
System.out.println(--a); //演算してから評価(値を表示)
a = 3;
System.out.println(a--); //評価(値を表示)してから演算
System.out.println(a); //aの値を表示
}
}
これをコンパイルして実行した結果、以下のようになります。
>javac JavaTest03.java
>java JavaTest03
4
3
4
2
3
2
>
これによって、「インクリメント演算子」と「デクリメント演算子」の働きが確認できました。
計算のときの型に注意する
これまでの「変数」や「演算子」などを使ってプログラムによる計算ができますが、そのときに注意しなければならないのは「型」についてです。
例えば以下のような計算をした場合、「0.4」という計算結果を期待するかも知れませんが、実際にやってみると「x」の値は「0.0」となってしまいます。
double x = 2 / 5;
これは「int型」の「整数リテラル」同士を計算した際に、その結果も「int型」に自動的に変換されてしまうためです。
小数の結果を表示させたい場合は、例えば「2.0 / 5.0」のように書く方法もありますが、「キャスト」を使うというやり方もあります。
「キャスト」というのは型を明示的に変換する方法ですが、上記の計算の場合は以下のように記述します。
double x = (double)2 / (double)5;
さらにJavaには計算に使われる値の型が異なるものが混じっている場合、自動的にキャストして型変換する機能を持っています。
この自動的なキャストにはルールがあって、「int型 < double型 < float型 < long型」の優先順位で変換されます。
例えば「int型」と「double型」の計算の場合は「double型」に、「double型」と「long型」場合は「long型」に合わせてキャストされるわけです。
ですから上記の計算の場合、「2」のほうだけを「(double)2」としてやっても、自動的に「5」も「double型」にキャストされるので、結果は同じになります。
ちなみに、「double」「float」「long」以外の型の「short」などは演算時に自動で「int」に変換されるので注意が必要です。
ですから例えば次のプログラムはコンパイル時にエラーになりますが、これは最終行の代入が「short型」に自動で型変換された「int型」を代入することになるためです。
short a = 10;
short b = 20;
short c = a + c;
まとめ
というわけで今回は数値計算に必要な「変数」や「演算子」について勉強してみました。
他のプログラミング言語を知ってる人ならば違和感無く理解できるものばかりでしょうが、一部Javaに特有のものもあるので、そこは混乱しないように注意が必要でしょうね。
それでは、今回はここまでです。
《 【Javaの勉強】一覧 》