Java入門:クラスとオブジェクトのよくある間違い

レッスンの本文で注意している点を、つまずきの側から27件ぶん並べ直しました。書いた覚えのある形が見つかったら、 そのままレッスンに戻って前後を読めます。

クラスを定義する

レッスンを読む

クラス名を小文字で始める

public class book { ... } のように小文字で書くとコンパイル自体は通ってしまうことがあるものの、Java の世界ではクラス名を小文字で始めるのは強い アンチパターン です。チームのコードレビューでも一発で指摘されます。必ず Book のように大文字始まりで書きましょう

クラスを定義するで詳しく読む

ファイル名とクラス名が食い違う

Book.java の中に public class Library { ... } と書くと、class Library is public, should be declared in a file named Library.java というエラーで止まります

クラスを定義するで詳しく読む

クラスにフィールドを持たせる

レッスンを読む

クラスにメソッドを定義する

レッスンを読む

static を付けたり外したりを間違える

クラス内のフィールドを使うインスタンスメソッドに static を付けると、non-static field cannot be referenced from a static context というエラーが出ます。逆にユーティリティ的な計算なのに static を外すと、毎回 new してから呼ばないといけなくなり不便です。「フィールドに触るかどうか」で判断しましょう

クラスにメソッドを定義するで詳しく読む

this を使わずに引数とフィールドを混同する

メソッドの引数とフィールドが同じ名前のとき、title = title; と書いても何も起きません (引数が引数に代入されているだけ)。this.title = title; のように、フィールド側だけ this. を付けて区別する必要があります

クラスにメソッドを定義するで詳しく読む

戻り値の型と return の値がずれる

メソッドの宣言が public String getDescription() なのに return 123; と書くとコンパイルエラーです。戻り値の型と return で返す値の型は必ず一致させてください。何も返さないなら戻り値型を void に変える、というルールも忘れずに

クラスにメソッドを定義するで詳しく読む

インスタンスを作る

レッスンを読む

new を書き忘れる

Book b = Book(); のように new を抜いてしまうと、「Book という名前のメソッドを呼ぼうとした」と解釈されてコンパイルエラーになります。インスタンスを作るときは必ず new を先頭に付けてください

インスタンスを作るで詳しく読む

変数宣言と new を混同する

Book b; だけで終わってしまうと、変数 b は宣言されていますが中身は null のままです。この状態で b.read() を呼ぶと実行時に NullPointerException が飛んできます。必ず = new Book(); まで書ききりましょう

インスタンスを作るで詳しく読む

static メソッドをインスタンスから呼ぼうとする

Solution.helloWorld() のような static メソッドは、本来クラス名から呼ぶものです。インスタンスを作って s.helloWorld() と書いてもエラーにはなりませんが、警告が出るうえに意味も薄れます。static はクラス、それ以外はインスタンス、と使い分けましょう

インスタンスを作るで詳しく読む

コンストラクタ

レッスンを読む

コンストラクタに戻り値型を書いてしまう

public void Book(...) public String Book(...) のように voidString を入れてしまうと、Java のコンパイラはそれを 同じ名前のただのメソッド として扱います。引数付きで new Book("x", "y") のように呼ぼうとするとコンパイルエラーになります(コンストラクタとして認識されるものが引数なしのデフォルトコンストラクタしかないため)。一方、引数なしで new Book() と呼んだ場合はデフォルトコンストラクタが動くものの、フィールドは初期化されないままになります。public ClassName(...) { の形を厳守してください

コンストラクタで詳しく読む

複数コンストラクタの解決ミス

public Book(String title)public Book(String title, String author) の両方を用意した状態で new Book("Java入門") と呼ぶと、引数 1 個の方が選ばれます。new Book("Java入門", null) を呼ぶと 2 引数の方が選ばれ、authornull のまま fullTitle() を実行すると null が出力に混ざります。引数の数と意味は、コンストラクタを増やすたびに丁寧に確認しましょう

コンストラクタで詳しく読む

デフォルトコンストラクタが消えていることに気づかない

─ 自分で public Book(String title, String author) を 1 つ追加した瞬間、new Book() は使えなくなります。テストコードや別ファイルでまだ new Book() を呼んでいると、constructor Book in class Book cannot be applied to given types というエラーが出ます。引数なしも使いたいなら、public Book() {} を明示的に書き足してください

コンストラクタで詳しく読む

this キーワード

レッスンを読む

static メソッドの中で this を使ってしまう

public static String describe() の中で this.title と書くと「non-static variable this cannot be referenced from a static context」と怒られます。static メソッドはクラス全体に属するので、「自分自身のインスタンス」が存在しません。インスタンスメソッド (static が付かないメソッド) でだけ this が使えます

this キーワードで詳しく読む

this を省略したつもりが、ローカル変数を上書きしてしまう

Book(String title) { title = title; } のように書くと、引数 title を引数自身に代入するだけでフィールドは空のまま。フィールドへ書き込みたいときは必ず this.title = title; と書くか、引数名を変える (_title newTitle など) ようにします

this キーワードで詳しく読む

コンストラクタで this(...) を 2 行目以降に書く

this(...) はコンストラクタの 先頭行 でなければなりません。何か別の処理を挟むと「call to this must be first statement in constructor」というエラーになります。共通処理は this(...) で呼ばれる側のコンストラクタにまとめるのが鉄則です

this キーワードで詳しく読む

カプセル化 (private と getter)

レッスンを読む

フィールドをついつい public にしてしまう

書き始めのうちは、public int balance; のほうがコード量が少なくて楽に感じます。けれどそれは「これから先、誰かが変な値を入れても止められない」という時限爆弾を埋めている状態です。フィールドは原則 private、必要に応じて getter / setter を足す という順番を体に染み込ませてください。Java の世界では「private が当たり前、public フィールドは要相談」が共通認識です

カプセル化 (private と getter)で詳しく読む

getter / setter を機械的に全フィールドに作る

IDE の自動生成でフィールドの数だけ getter / setter が並ぶと、見た目はリッチですが、実質的には public フィールドと同じ「中身を素通しできるクラス」になりがちです。setter は「外から自由に書き換えてほしい場合だけ」用意する、それ以外は読み取り専用にする (getter だけ作る)、という判断をするとカプセル化が一段強くなります。balance のように外から直接いじらせたくない値には、deposit(int) withdraw(int) のような 意図のあるメソッド を用意するのが理想です

カプセル化 (private と getter)で詳しく読む

ボイラープレートだらけのクラスになって本質が埋もれる

private フィールドと getter / setter を律儀に書いていくと、Java のコードはどうしても縦に長くなります。意味のあるロジックが 1 行なのに、その周りに 50 行のボイラープレートがついている、ということもよくあります。これを Lombok@Getter @SetterJava 16 以降の record で短く書く、というテクニックもありますが、まずは「カプセル化は手間に見合った価値がある」と感じてもらえる程度の手書きに慣れることが大事です

カプセル化 (private と getter)で詳しく読む

Person クラスを作る

レッスンを読む

フィールドの初期化漏れ

フィールドだけ宣言して、コンストラクタの中で this.name = name; を書き忘れるパターン。コンパイルは通ってしまうのに、introduce() を呼ぶと namenull のままで "null (0)" のような結果が返ってきます。Java では String のフィールドは初期値 nullint のフィールドは初期値 0 になる仕様なので、入れ忘れに気づきにくいのが厄介です

Person クラスを作るで詳しく読む

コンストラクタなしで放置する

コンストラクタを 1 つも書かないと、Java が自動で 引数なしのデフォルトコンストラクタ を作ってしまいます。すると new Person("太郎", 25) という書き方ができず、コンパイラから constructor Person in class Person cannot be applied to given types と怒られます。引数付きで初期化したいなら、その引数を取るコンストラクタを必ず自分で書く のが鉄則です

Person クラスを作るで詳しく読む

equals を実装していないのに == で比較する

2 人の Person を比べたくて taro == hanako のように == で書くと、Java は メモリ上の同じ場所を指しているか だけを見ます。中身が同じでも new で別々に作っていれば結果は false です。中身を比べたいときは equals メソッドを自分で実装する必要があります

Person クラスを作るで詳しく読む

toString のオーバーライド

レッスンを読む

@Override アノテーションを忘れる

付け忘れてもコンパイル自体は通ってしまうので、気づかずにメソッド名を tostring と書き間違えても、コンパイラは何も言ってくれません。すると toString() は親の実装が呼ばれ続け、いつまで経っても Point@1540e19d のままで「あれ、書いたはずなのに反映されない」とハマります。@Override を付けておけば、コンパイル時に即エラーで教えてくれます

toString のオーバーライドで詳しく読む

引数を勝手に増やしてしまう

Object.toString()引数なし のメソッドです。これを public String toString(int n) のように引数付きにしてしまうと、それは別のメソッドの オーバーロード (overload) になり、オーバーライド にはなりません。@Override を付けていればコンパイラが「親クラスに引数 inttoString はない」と教えてくれます

toString のオーバーライドで詳しく読む

戻り値の型を間違える

Object.toString() の戻り値は String です。これを void にしたり、Object にしたりすると、String 以外の戻り値を持つメソッドはオーバーライドとして認められません。やはり @Override を付けておけばコンパイラが守ってくれます

toString のオーバーライドで詳しく読む