アクセス修飾子と継承

JavaJavaBeginner
オンラインで実践に進む

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

この実験では、アクセス修飾子と継承について学びます。異なる修飾子を使用すると、アクセスレベルが異なります。Java における継承は、生物学的な継承と同じように、子孫が親の特徴を引き継ぎ、ある意味で異なる振る舞いをすることができます。

これは Guided Lab です。学習と実践を支援するためのステップバイステップの指示を提供します。各ステップを完了し、実践的な経験を積むために、指示に注意深く従ってください。過去のデータによると、この 初級 レベルの実験の完了率は 93%です。学習者から 100% の好評価を得ています。

アクセス修飾子

今のところ、私たちは既にいくつかのコードを書いてきました。前の実験では、クラスを書きました。publicprivateのようないくつかの修飾子があります。では、これらの言葉は何を意味するのでしょうか?

Java は、クラス、変数、メソッド、コンストラクタのアクセスレベルを設定するための多くのアクセス修飾子を提供しています。4 つのアクセスレベルは以下の通りです。

  • デフォルト: パッケージ内で可視。デフォルトのもので、修飾子は必要ありません。
  • private: 定義するクラス内のみ可視。
  • public: Java のユニバース(すべての)に可視。どこからでもアクセスできます。
  • protected: パッケージとすべてのサブクラス(他のパッケージにあるものでも)に可視。
Java アクセス修飾子の図

Java は、さまざまな方法で動作を微調整するための多くの非アクセス修飾子を提供しています。

  • static: この修飾子は、クラスのインスタンスとは独立して存在する変数やメソッドを作成するために使用されます。クラスには、作成されたインスタンスの数に関係なく、static変数のコピーが 1 つだけ存在します。
  • final: final変数は明示的に 1 回だけ初期化できます。finalメソッドは、サブクラスによってオーバーライドできません。クラスはfinalとして宣言されることで、サブクラス化されることを防ぎます。
  • abstract: abstractクラスは決してインスタンス化できません。abstractメソッドは、実装が宣言されていないメソッドです。
  • synchronized/volatile: synchronizedvolatile修飾子は、スレッドと関連付けて使用されます。

例:

/home/labex/project/modifierTest.javaファイルに以下のコードを書きます。

public class modifierTest {
    // static 変数はクラスが読み込まれるときに初期化されます。
    public static int i = 10;
    public static final int NUM = 5;
    // 非 static 変数はオブジェクトが作成されるときに初期化されます。
    public int j = 1;

    /*
     * ここに static コードブロックがあります。これはクラスが読み込まれるときに実行されます。
     * 新しいオブジェクトを作成しても、このブロックは再度実行されません。1 回だけ実行されます。
    */
    static{
        System.out.println("this is a class static block.");
    }
    public static void main(String[] args)
    {
        System.out.println("this is in main method");

        // 変数 i にアクセスして変更することができます。
        modifierTest.i = 20;  //obj.i = 20 と同じ
        System.out.println("Class variable i = " + modifierTest.i);
        // 変数 NUM にアクセスすることはできますが、変更することはできません。
        // HelloWorld.NUM = 10;     これはエラーになります。NUM は final で、変更できません。
        System.out.println("Class variable NUM = " + modifierTest.NUM);

        // 新しいオブジェクトを作成します。
        modifierTest obj = new modifierTest();
        // クラスとオブジェクトの両方を使って static メソッドと static プロパティにアクセスできます。
        obj.staticMethod();  //modifierTest.staticMethod() と同じ
        // 変数 j にはこのようにアクセスできません。modifierTest.j
        System.out.println("Object variable j = " + obj.j);
    }
    // コンストラクタ。新しいオブジェクトが作成されるときにのみこれが呼び出されます。
    public modifierTest(){
        System.out.println("this is in object's constructor.");
    }
    public static void staticMethod(){
        System.out.println("this is a static method");
    }
}

出力:

以下のコマンドを使ってmodifierTest.javaファイルを実行します。

javac /home/labex/project/modifierTest.java
java modifierTest

出力を見てください。

this is a class static block.
this is in main method
Class variable i = 20
Class variable NUM = 5
this is in object's constructor.
this is a static method
Object variable j = 1

継承

多くの場合、私たちはクラスを書いてきました。そして、そのクラスのコードを少しだけ修正するだけで新しいクラスを書く必要があり、それらは論理的にいくつかの関係があります。ここでは継承を使うことができます。継承を実現するには、キーワードextendsを使います。サブクラスはスーパークラスのすべてのアクセス可能なプロパティとメソッドを継承し、サブクラスには独自の特殊なものも持てます。サブクラスでは、publicまたはprotectedとしてスーパークラスで宣言されたものにアクセスできますが、privateのものには直接アクセスできません。例を見てみましょう。継承構造は図のように表示されます。マルチレベル継承(水平方向)または階層型継承(垂直方向)を実装できます。

継承構造の図

例:

/home/labex/project/inheritanceTest.javaファイルに以下のコードを書きます。

class Animal{
    // 私はどんな種類の動物か。
    private String species;
    private int age = 8;

    public Animal(){
        System.out.println("Animal's constructor");
    }
    public void grow(){
        // このクラスでは、private プロパティに直接アクセスできます。
        System.out.println("I'm "+ this.age + " years old, " +"I grow up.");
    }
}
class Dog extends Animal{
    private String color;
    // このクラスでは、スーパークラスの private 属性にアクセスできませんが、grow() は問題ありません。
    public Dog(){
        System.out.println("Dog's constructor");
    }
    public void run(){
        this.grow();
        System.out.println("I'm dog, I can run.");
    }
}
class Bird extends Animal{
    private double weight;

    public Bird(){
        // 明示的にスーパークラスのコンストラクタを呼び出す場合、ここでは最初の行にしなければなりません。
        // super();
        System.out.println("Bird's constructor");
    }
    public void fly(){
        this.grow();
        System.out.println("I'm bird, I can fly.");
    }
}
public class inheritanceTest{
    public static void main(String[] args){
        Dog dog = new Dog();
        dog.run();

        Bird bird = new Bird();
        bird.fly();
    }
}

出力:

以下のコマンドを使ってinheritanceTest.javaファイルを実行します。

javac /home/labex/project/inheritanceTest.java
java inheritanceTest

出力を見てください。

Animal's constructor
Dog's constructor
I'm 8 years old, I grow up.
I'm dog, I can run.
Animal's constructor
Bird's constructor
I'm 8 years old, I grow up.
I'm bird, I can fly.

この出力を見ると、混乱するかもしれません。心配しないでください。なぜか説明します。newを使ってサブクラスのオブジェクトを作成すると、デフォルトで最初に継承木構造の「上から下」にスーパークラスのデフォルトコンストラクタを呼び出し、最後に自分自身のコンストラクタを実行します。スーパークラスのコンストラクタは、superキーワードを使って明示的に呼び出すことができますが、それがあるコンストラクタの最初の文でなければなりません。superキーワードは、階層構造において呼び出し元のクラスの直上のスーパークラスを指します。

まとめ

アクセス修飾子を使うことで、安全なコードを書き、詳細を隠し、アクセス制御を実現できます。他のユーザーは、メソッドの詳細な実装方法を知る必要はありません。私たちは他の呼び出し元にインターフェイスを提供します。アクセス修飾子については、Java のソースコードライブラリを読んで、どのような違いがあるかを理解してください。継承については、階層構造を覚えておいてください。これはクラス間の関係です。