エンジニアのはしがき

プログラミングの日々の知見を書き連ねているブログです

Java勉強中/C#と比較しながらハマりそうなところピックアップ

どうも、ご無沙汰してました。

この度、転職先でJavaをメインに書くことになり勉強しています。 ぱっと見の文法はC#と似ているものの、実態は結構違う部分も多かったので個人的に気になる部分をピックアップしました。

個人的な要注意ポイント

String型の同値判定は==ではなくequals()を使う

Javaで文字列の同値比較する手段は大きく2タイプあります。

  • ==: 同一性(同じメモリのアドレスをもつインスタンスであること)の判定
  • equals(): 同値性(同じ値であること)の判定

JavaのString型は参照型である為、==による判定をした際に人間が見て同じ値のように見えたとしても、結果が異なる場合があります。

String foo = "java";
String bar = new String("java");

// 結果はfalseになる
if (foo == bar) {
    ...
}
// 結果はtrueになる
if (foo.equals(bar)) {
    ...
}

ただし、文字列リテラルで同じ文字列を代入した場合は同じインスタンスになります。

String foo = "java";
String bar = "java";

// 結果はtrueになる
if (foo == bar) {
    ...
}

この仕様は知らないとうっかりバグの原因になりそうな感じがしますね…。 Javaの文字列の同値判定ではequals()を使うことが推奨されているようです。

一方、C#では==Javaequals()と同じ結果を得られるので、間違わないように注意したいところです。

Calendar.MONTHの数値範囲は0~11

Calendarクラスで扱う月(MONTH)の数値範囲は現実世界の1~12ではなく、0~11として扱います。 JavaScriptのDateオブジェクトと同じですね。 一方でC#は1~12です。

ふと、過去にJavaScriptC#の月の仕様を混同してしまったせいでバグを起こした記憶が蘇りました。気をつけたいと思います。

メソッドのオーバーライド時にはアノテーションをつける

基底クラスのメソッドを派生クラスでオーバーライドする際は、派生クラスで同名・同引数を持つメソッドを定義するだけでオーバーライドされます。 ただ、開発者が見たときにオーバーライドされたものなのかどうか判別が非常に付きにくくなる為、アノテーションとして@Overrideをメソッドの真上に書く方が良さそうです。

アノテーションを付けておけばjavacでのコンパイル時に文法ミスの検知もしてくれる模様。ちゃんと書くよう癖づけていきたいですね。

public class SuperClass extends BaseClass {
    ...
    // BaseClassのfoo()をオーバーライドしていることを明示する
    @Override
    public void foo() {
        ...
    }
}

finalは書く場所によって効果が異なる

finalを書く場所 効果
クラス 継承を禁止する
メソッド 派生クラスでのメソッドのオーバーライドを禁止する
変数 再代入を禁止する

C#だとsealed, const, readonly辺りが近い修飾子ですね。 finalという単語は「この定義は最初で最後。別の箇所での定義変更は禁止!」といったニュアンスの単語であると意識して覚えることにしました。

勉強に使っている書籍

  • スッキリわかるJava入門 第3版 (スッキリわかる入門シリーズ)

www.amazon.co.jp

プログラミング初心者からでも理解できるような丁寧な解説・イラストと、具体例を踏まえたソースコードが記載されています。

個人的には解説はくどく感じたので、ポイントとなる説明文だけピックアップしてどんどん読み進めています。 たまに言語仕様に深めに突っ込んだトピックがあったりするので結構良い勉強になります。 プログラミング初心者向けに書いていながら、オブジェクト指向の要である継承、カプセル化ポリモーフィズムなども取り上げていて良い頭の整理ができました。

なおリファレンス的に読み返そうとすると要点が探し辛いと思いますので、そういう用途には向いていないと思います。