カテゴリ: JavaSilver試験対策 更新日: 2026/01/18

Javaの型推論(var)と継承に関する注意点を徹底解説!初心者でも理解できる基本知識

017
Javaの型推論(var)と継承に関する注意点

先生と生徒の会話形式で理解しよう

生徒

「Javaでvarを使ったらエラーが出ました。どうしてですか?」

先生

varは型推論を行う便利な機能ですが、いくつか制約があります。特に継承を扱うときには注意が必要です。一緒に見ていきましょう!」

生徒

「なるほど、継承のときにどう注意すればいいのか知りたいです!」

先生

「それでは、具体例を使って説明していきますね。」

1. var型と型推論の仕組み

1. var型と型推論の仕組み
1. var型と型推論の仕組み

varはJava 10で導入されたローカル変数の型推論機能です。varを使うと、右辺の値から型を推論して変数を宣言できます。


public class VarExample {
    public static void main(String[] args) {
        var number = 10; // 推論される型はint
        System.out.println(number); // 出力: 10
    }
}

このように便利な機能ですが、型推論はコンパイル時に行われるため、変数の型が固定されます。これが後述する継承に関する問題の原因になります。

2. 継承と型推論の注意点

2. 継承と型推論の注意点
2. 継承と型推論の注意点

次に、継承を含むコードでvarを使った場合の注意点を説明します。以下のコードを考えてみましょう。


class Parent {
    public void display() {
        System.out.println("Parent");
    }
}

class Child extends Parent {
    @Override
    public void display() {
        System.out.println("Child");
    }
}

public class VarInheritanceExample {
    public static void main(String[] args) {
        var obj = new Parent();
        obj = new Child(); // エラー: 型が固定されている
        obj.display();
    }
}

このコードでは、varによって推論された型がParentに固定されるため、Childのインスタンスを代入しようとするとコンパイルエラーが発生します。

正しい解決方法

継承を扱う場合は、明示的に親クラスやインターフェースの型を指定する必要があります。


public class CorrectInheritanceExample {
    public static void main(String[] args) {
        Parent obj = new Parent();
        obj = new Child(); // OK
        obj.display(); // 出力: Child
    }
}

このように型を明示的に指定することで、継承を活用した柔軟なコードを書くことができます。

3. 試験対策: var型推論の基本ルール

3. 試験対策: var型推論の基本ルール
3. 試験対策: var型推論の基本ルール

試験や実務で役立つvarの基本ルールをまとめました。

  • 型推論はコンパイル時に行われ、右辺の値から型を推論します。
  • 推論された型は変数の宣言時に固定されます。
  • 継承を使用する場合、varではなく親クラスやインターフェースの型を明示的に指定するのが一般的です。
  • varはローカル変数専用であり、フィールドやメソッド引数には使用できません。

これらのポイントを押さえておけば、varを安全かつ効果的に利用できます。

Javaをこれから始める人や、 オブジェクト指向の考え方を基礎から理解したい人には、 定番の入門書がこちらです。

スッキリわかるJava入門 第4版をAmazonで見る

※ Amazon広告リンク

4. varが使えないケースとよくあるエラー

4. varが使えないケースとよくあるエラー
4. varが使えないケースとよくあるエラー

varは便利ですが、どこでも使えるわけではありません。特に初心者がつまずきやすい「使えないケース」を知っておくと、エラーの原因がすぐに分かるようになります。

  • varローカル変数にしか使えません(フィールドや引数には使えない)。
  • 右辺がない宣言(初期化なし)はできません。
  • nullだけを代入して型推論することはできません。
  • 配列の要素型を省略した書き方では推論できないケースがあります。

たとえば、次のような書き方はコンパイルエラーになります。


public class VarErrorExample {
    // var field = 10; // エラー: フィールドには使用できない

    public static void main(String[] args) {
        // var x; // エラー: 初期化が必要
        // var y = null; // エラー: nullだけでは型推論できない

        var number = 10; // OK: intに推論される
        System.out.println(number);
    }
}

このように、varは「右辺の情報から型を決める」仕組みなので、右辺が曖昧だと推論できずエラーになります。

5. varとポリモーフィズムの関係

5. varとポリモーフィズムの関係
5. varとポリモーフィズムの関係

継承のメリットのひとつに「ポリモーフィズム(多態性)」があります。親クラス型で受け取り、実体は子クラスとして動作させることで、柔軟な設計ができます。

ただし、varを使うと「宣言時の右辺」で型が決まるため、ポリモーフィズムを意識したコードでは注意が必要です。


class Parent {
    public void display() {
        System.out.println("Parent");
    }
}

class Child extends Parent {
    @Override
    public void display() {
        System.out.println("Child");
    }

    public void childOnly() {
        System.out.println("Child Only");
    }
}

public class VarPolymorphismExample {
    public static void main(String[] args) {
        Parent p = new Child(); // 親型で受け取る(ポリモーフィズム)
        p.display(); // 出力: Child
        // p.childOnly(); // エラー: Parent型には存在しない

        var v = new Child(); // 推論される型はChild
        v.display(); // 出力: Child
        v.childOnly(); // OK: Child型なので呼び出せる
    }
}

このように、varは宣言時点で具体クラス(例: Child)に推論されるため、結果として「子クラス固有のメソッドが呼べてしまう」ケースもあります。

設計として親型で扱いたい場合は、varを使わずに親クラスやインターフェース型で宣言するのが安全です。

6. インターフェースとvarを組み合わせるときの注意点

6. インターフェースとvarを組み合わせるときの注意点
6. インターフェースとvarを組み合わせるときの注意点

継承だけでなく、実務ではインターフェースを使った設計もよく登場します。ここでもvarは「右辺の具体クラス」で型が固定されるため、意図とズレないように注意しましょう。


interface Service {
    void execute();
}

class ServiceImpl implements Service {
    @Override
    public void execute() {
        System.out.println("ServiceImpl");
    }

    public void implOnly() {
        System.out.println("Impl Only");
    }
}

public class VarInterfaceExample {
    public static void main(String[] args) {
        Service s = new ServiceImpl(); // インターフェース型で受け取る
        s.execute(); // 出力: ServiceImpl
        // s.implOnly(); // エラー: Service型には存在しない

        var v = new ServiceImpl(); // 推論される型はServiceImpl
        v.execute(); // 出力: ServiceImpl
        v.implOnly(); // OK: 実装クラス型なので呼べる
    }
}

インターフェース型で受け取る設計にしている場合、varを使うと実装クラス型になり、実装依存のメソッドを呼べてしまいます。

「インターフェースとして扱う」ことが目的なら、varではなくインターフェース型を明示して宣言するのが基本です。

まとめ

まとめ
まとめ

この記事では、Javaの型推論機能varを継承と組み合わせた際に注意すべき点について詳しく解説しました。varは非常に便利な機能ですが、継承のような複雑な場面では型推論の仕組みを正しく理解することが重要です。 特に、varで宣言された変数はコンパイル時に型が固定されるため、親クラスと子クラス間で代入を行う場合には注意が必要です。以下は今回学んだ主なポイントです。

  • 型推論はコンパイル時に決定する: 変数の型は右辺の値から決定され、その後変更できません。
  • 継承を活用する場合: 明示的に親クラスやインターフェースの型を指定することで、柔軟な代入が可能になります。
  • varの適用範囲: ローカル変数専用であり、フィールドやメソッド引数では使用できません。

以下はまとめとして、正しい型の扱い方を示すサンプルコードです。


class Animal {
    public void sound() {
        System.out.println("Animal sound");
    }
}

class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("Bark");
    }
}

class Cat extends Animal {
    @Override
    public void sound() {
        System.out.println("Meow");
    }
}

public class InheritanceExample {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.sound(); // 出力: Bark
        animal = new Cat();
        animal.sound(); // 出力: Meow
    }
}

このコードでは、親クラスAnimalを明示的に型として指定することで、子クラスDogCatのインスタンスを柔軟に扱うことができています。

先生と生徒の振り返り会話

生徒

varが便利だけど、継承と一緒に使うときには注意が必要なんですね!」

先生

「その通りです。特に型が固定される性質を理解していないと、思わぬエラーが発生することがあります。」

生徒

「親クラスを型として指定する方法を知って、より柔軟にコードが書けるようになりました!」

先生

「それは良かったですね。今回の知識を活用して、さらに複雑なコードにも挑戦してみてください。」

生徒

「はい、次回も楽しみにしています!」

この記事を読んだ人からの質問

この記事を読んだ人からの質問
この記事を読んだ人からの質問

プログラミング初心者からのよくある疑問/質問を解決します

Javaのvar型とは何ですか?型推論とはどういう意味ですか?

Javaのvar型とは、ローカル変数の型推論を自動で行う機能です。右辺の値からコンパイル時に型を判断し、型を省略して記述できます。型推論とは、変数の型をコンパイラが自動的に決定する仕組みのことです。

varを使うとき、右辺の値から型が固定されるというのはどういうことですか?

varは右辺の値によってコンパイル時に型が決定され、その後変更できません。例えばvar number = 10 と書くと、number の型はintに固定され、別の型の値を代入しようとするとコンパイルエラーになります。
JavaSilver試験対策の一覧へ
新着記事
FlutterのMVP・MVVMアーキテクチャの違いと使い分け
FlutterのMVP・MVVMアーキテクチャの違いと使い分けを初心者向けに解説!
オニオンアーキテクチャの基本とFlutterでの適用例
オニオンアーキテクチャの基本とFlutterでの適用例を初心者向けに解説
クリーンアーキテクチャとは?Flutterでの導入メリット
クリーンアーキテクチャとは?Flutterでの導入メリットをやさしく解説
【AWS】RDS for Oracleの特徴・できないこと・バージョン・料金まとめ
【AWS】RDS for Oracleの特徴・できないこと・バージョン・料金を初心者向けに徹底解説
人気記事
インスタンスタイプの料金比較と最適な選び方(最新2025年版)
AWSのインスタンスタイプの料金比較と最適な選び方【2025年最新版】
【AWS】VPCの料金体系まとめ!無料枠・通信費・各種サービスごとの料金を徹底解説
【AWS】VPCの料金体系まとめ!無料枠・通信費・各種サービスごとの料金を徹底解説
【AWS】VPCエンドポイントとは?種類・使い方・S3連携まで完全解説
【AWS】VPCエンドポイントとは?種類・使い方・S3連携まで完全解説
【AWS】s3 cpコマンド完全ガイド!基本・recursive・exclude/includeも解説
【AWS】s3 cpコマンド完全ガイド!基本・recursive・exclude/includeも解説

🔌 USBポート不足を解消

Type-C 1本で拡張。
開発・作業環境を一気に快適に

UGREEN USB-Cハブを見る

※ Amazon広告リンク