手を動かして学ぶ Java入門 (定数の定義)
環境構築不要! ブラウザから直接コードを実行できます。
本記事では、静的フィールド (staticフィールド) を使った定数の定義について学びます。
15分くらいで、さくっと終わる記事をめざしています。
(今回はいつもより少し長めです)
シリーズ一覧
- シリーズ
- 手を動かして学ぶ Java入門 (Hello world 編)
- 手を動かして学ぶ Java入門 (数値と演算)
- 手を動かして学ぶ Java入門 (数値と変数)
- 手を動かして学ぶ Java入門 (コメントの書き方)
- 手を動かして学ぶ Java入門 (文と式の違い)
- 手を動かして学ぶ Java入門 (if文)
- 手を動かして学ぶ Java入門 (if-else文、if-elseif文)
- 手を動かして学ぶ Java入門 (文字列の連結)
- 手を動かして学ぶ Java入門 (while文)
- 手を動かして学ぶ Java入門 (break文)
- 手を動かして学ぶ Java入門 (continue文)
- 手を動かして学ぶ Java入門 (for文)
- 手を動かして学ぶ Java入門 (クラスの超基本)
- 手を動かして学ぶ Java入門 (クラス・メソッド)
- 手を動かして学ぶ Java入門 (クラス・フィールド)
- 手を動かして学ぶ Java入門 (クラス・コンストラクタ)
- 手を動かして学ぶ Java入門 (文字列クラス)
- 手を動かして学ぶ Java入門 (静的メソッド)
- 手を動かして学ぶ Java入門 (静的フィールド)
- 手を動かして学ぶ Java入門 (定数の定義)
- 手を動かして学ぶ Java入門 (クラス継承の超基本)
- 手を動かして学ぶ Java入門 (メソッドのオーバーライド)
- 手を動かして学ぶ Java入門 (メソッドのオーバーロード)
続きは近日公開予定!
はじめに
この記事は paiza.IO の「Online Java compiler」を利用しています。
2024/12/17 現在、上記環境の Java バージョンは 18 です。(paiza.IO利用ガイド)
実行したコードは paiza.IO で保存および公開されることがあります。
そのため、個人情報などの機密性の高い情報は、コードとして入力しないようにご注意ください。
詳細は paiza.IO の利用規約およびプライバシーポリシーをご確認ください。
静的フィールドのおさらい
静的フィールドとは、インスタンスではなく クラスが持つ 変数です。
つまり インスタンス は必要ありません。
また、インスタンスを必要としないので 静的メソッド からもアクセスできます。
以前の記事 でも学習しましたね。
次の Sample クラスを例に見てみましょう。
静的フィールドは value ですね。
public class Sample {
private static int value;
public static void set(int v) {
value = v;
}
public static void print() {
System.out.println("value = " + value);
}
}
静的メソッドの呼び出しはこんな感じです。
Sample.set(123);
Sample.print();
それでは実際に動かして確認してみましょう。
結果がどうなるか予想してから「実行(Ctrl-Enter)」ボタンを押してください。
注意:コードは2ファイルあります。上部のタブで切り替え可能です。
(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)
いかがでしたでしょうか? 「出力」のところに
value = 123
と表示されたら成功です。
Sample クラスの インスタンス を生成しなくても、静的フィールドにアクセスできたことが分かります。
定数
定数とは、簡単にいうと…
- 内容 (値) の変わらない変数
です。
厳密にいうと、静的フィールドでなくても定数は定義できます。
しかし、普通のフィールドだとインスタンス毎に定数が作られます。
定数は 内容 が変わりません。
同じ内容の定数をインスタンス毎に持つのは、ちょっとメモリを無駄にしちゃってますよね…
そのため、一般的に定数には静的フィールドが使われます。
静的フィールドはクラス自身が持つフィールドです。
インスタンスは関係しません。
これなら、いくらインスタンスが増えてもメモリの無駄にならないですね。
ただし、static キーワードだけでは 変数の書き換え ができてしまいます。
内容 (値) が変わったら、それは定数ではありません。
そこで、変数の書き換えができないように final キーワードを使います。
コード例
例として、Circle クラスに円周率を定数として定義してみましょう。
円周率は π(パイ) ということで、定数の名前は PI にします。
まずは final を使わない例です。
静的フィールドの Circle.PI は 円周率(3.14) を定義しています。
public class Circle {
public static double PI = 3.14;
}
double は小数を表すデータ型です。小数点付きの値も扱えます。
また、Circle クラスの外からもアクセスできるようにアクセス修飾子は public にしています。
さて、これだけでは PI は変更可能です。
実際に確認してみましょう。
結果がどうなるか予想してから「実行(Ctrl-Enter)」ボタンを押してください。
注意:コードは2ファイルあります。上部のタブで切り替え可能です。
(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)
いかがでしたでしょうか? 「出力」のところに
円周率 : 3.14
円周率? : 1.23
と表示されたら成功です。
PI の値が変わってしまっていて、これでは定数ではありませんね。
次は final キーワードを使ってみましょう。
先ほどの Circle クラスを…
public class Circle {
public static double PI = 3.14;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ← この部分!
}
次のように書き換えてください。
public class Circle {
public static final double PI = 3.14;
^^^^^ ← これを追加
}
final キーワードをつけることで、フィールドの書き換えができなくなります。
(1回目となる最初の代入だけは OK)
それは、final キーワードを書き加えてから「実行(Ctrl-Enter)」ボタンを押してください。
注意:コードは2ファイルあります。上部のタブで切り替え可能です。
(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)
いかがでしたでしょうか?
Main.java:7: error: cannot assign a value to final variable PI
Circle.PI = 1.23;
^
とエラーになれば成功です。
"cannot assign a value to final variable PI" は意訳すると…
- final のついた変数(フィールド) は、1度 値を代入したら、再度 値を代入することはできません。
という感じですね。
これで Circle.PI という静的フィールドは、決して変更されることのない 定数 となりました。
なぜ定数が必要のなのか?
定数を使わないで、直接書く値のことを マジックナンバー といいます。
これは、プログラミングの慣習的に 良くない とされています。
例えば、次のようなコードです。
ちなみに、Product は商品、Price は値段、という意味です。
public class Product {
private int price;
public void setPrice(int p) {
price = p;
}
public double getPrice() {
return price + (price * 0.1);
}
}
getPrice メソッドの "0.1" の部分がマジックナンバーですね。
さて、この "0.1" は何を表しているのでしょうか…?
正解は 消費税(10%) でした。
getPrice メソッドは、消費税込みの値段を返します。
"0.1" は消費税 … となんとなく推測はできても確信するにはコードをしっかりと読む必要があります。
それは手間と労力がかかるでしょう。
次に、消費税が 5% に変わった場合について考えてみましょう。
今回のように、"0.1" と書いてあるのが1か所ならまだよいです。
そこを "0.05" に変えるだけです。
しかし、10か所に "0.1" と書いてあったら … さあ大変です。
全部を "0.05" に変えればよいのでしょうか?
いやいや、10か所のうち8か所は消費税としての "0.1" だけど、他の2か所は別の意味の "0.1" かもしれません。
それをいちいち確認しながら、注意深く "0.05" に書き換えるのは大変ですよね…
そこで定数の出番です。
次のように定数 TAX を定義すると、より分かりやすいコードになります。
TAX は税という意味ですね。
public class Product {
private static final double TAX = 0.1;
... 省略 ...
public double getPrice() {
return price + (price * TAX);
}
}
TAX という 名前 の定数になったので、消費税であることがより明確になりました。
また、消費税率が変わっても、TAX = 0.1 の1か所を変えるだけで OK です。
private static final double TAX = 0.05; // <--- ここを変更するだけ!
これが定数を使うメリットですね。
補足
実は、final だけでは定数にならない場合もあります。
それは内容の変更が可能なインスタンスの場合です。
例えば、次のような Sample1 クラスがあります。
public class Sample1 {
private int value;
public void set(int v) {
value = v;
}
public void print() {
System.out.println("value = " + value);
}
}
そして、この Sample1 クラスを定数として持つ Sample2 クラスです。
定数の名前は SAMPLE1 です。
public class Sample2 {
public static final Sample1 SAMPLE1 = new Sample1();
}
さて、SAMPLE1 ですが、final がついているので、もちろん再代入はできません。
public class Main {
public static void main(String[] args) {
Sample2.SAMPLE1 = new Sample1(); // コンパイルエラー!
}
}
しかし、set メソッドでいくらでも 内容の変更 ができます。
public class Main {
public static void main(String[] args) {
Sample2.SAMPLE1.set(123); // エラーにはならない
}
}
これでは、厳密には定数とはいえませんね…
よって、このように 内容の変更 ができるインスタンスを定数とするべきではありません。
実際に確認してみましょう。
結果がどうなるか予想してから「実行(Ctrl-Enter)」ボタンを押してください。
注意:コードは3ファイルあります。上部のタブで切り替え可能です。
(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)
いかがでしたでしょうか? 「出力」のところに
value = 0
value = 123
と表示されたら成功です。
定数のつもりの SAMPLE1 の 内容 が変わってしまっていますね。
よって、SAMPLE1 は 定数ではありません。
ちなみに、Java の文字列(Stringクラス) は内容の変更ができないインスタンスとなります。
(このような インスタンスを「不変オブジェクト」ともいいます)
よって、慣れないうちは、定数にするのは…
- int や double といった数値
- 文字列
くらいにしておいたほうがよいかもしれません。
応用問題
【問題】
まずは、下記のプログラムをそのまま「実行(Ctrl-Enter)」してみましょう。
結果はコンパイルエラーになったはずです。
Circle.java:5: error: cannot find symbol
return PI * r * r;
^
これは、Circle クラスに PI 定数がないためです。
そこで問題です。
Circle クラスに、PI 定数を追加してください。
また、PI の値は 3.14 としてください。
public class Circle {
// ここに 定数 PI を定義してください。
public static double getArea(double r) {
return PI * r * r;
}
}
ちなみに getArea は円の面積を求めるメソッドです。
円の面積 = πr2 ですね。r は半径です。
Main クラスでは半径 5 の面積を求めています。
double area = Circle.getArea(5);
System.out.println("面積 = " + area);
3.14 × 5 × 5 なので…
面積 = 78.5
と「出力」に表示されるはずです。
(Java のバージョンによっては、多少の誤差がでるかもしれません)
それでは、Circle クラスに PI 定数を書き加えてから「実行(Ctrl-Enter)」してみましょう。
注意:コードは2ファイルあります。上部のタブで切り替え可能です。
(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)
無事に、
面積 = 78.5
と出力されましたでしょうか?
もし解けなかった場合は、下記の回答例をご参照ください。
回答例
【コード】
public class Circle {
// ここに 定数 PI を定義してください。
private static final double PI = 3.14;
public static double getArea(double r) {
return PI * r * r;
}
}
※ Main.java は書き換えません。
【出力】
面積 = 78.5
まとめ
本記事では、静的メソッドを使った定数の定義について解説しました。
定数とは、簡単にいうと…
- 内容 (値) の変わらない変数
です。
マジックナンバーだらけのコードは品質が低くなりがちです。
ぜひ、定数を有効に活用してコードの品質を高めましょう。
次回は「手を動かして学ぶ Java入門 (クラス継承の超基本)」になります。
関連記事
- シリーズ
- 手を動かして学ぶ Java入門 (Hello world 編)
- 手を動かして学ぶ Java入門 (数値と演算)
- 手を動かして学ぶ Java入門 (数値と変数)
- 手を動かして学ぶ Java入門 (コメントの書き方)
- 手を動かして学ぶ Java入門 (文と式の違い)
- 手を動かして学ぶ Java入門 (if文)
- 手を動かして学ぶ Java入門 (if-else文、if-elseif文)
- 手を動かして学ぶ Java入門 (文字列の連結)
- 手を動かして学ぶ Java入門 (while文)
- 手を動かして学ぶ Java入門 (break文)
- 手を動かして学ぶ Java入門 (continue文)
- 手を動かして学ぶ Java入門 (for文)
- 手を動かして学ぶ Java入門 (クラスの超基本)
- 手を動かして学ぶ Java入門 (クラス・メソッド)
- 手を動かして学ぶ Java入門 (クラス・フィールド)
- 手を動かして学ぶ Java入門 (クラス・コンストラクタ)
- 手を動かして学ぶ Java入門 (文字列クラス)
- 手を動かして学ぶ Java入門 (静的メソッド)
- 手を動かして学ぶ Java入門 (静的フィールド)
- 手を動かして学ぶ Java入門 (定数の定義)
- 手を動かして学ぶ Java入門 (クラス継承の超基本)
- 手を動かして学ぶ Java入門 (メソッドのオーバーライド)
- 手を動かして学ぶ Java入門 (メソッドのオーバーロード)