JavaRush /Java Blog /Random-JA /クラス、ネストされたクラスの種類と例
Ярослав
レベル 40
Днепр

クラス、ネストされたクラスの種類と例

Random-JA グループに公開済み
こんにちは、みんな。このトピックでは、初心者がこのトピックを理解し、おそらく初心者ではない人が何か新しいことを学べるように、Java クラスとその型について詳しく説明したいと思います。可能な場合は、コード例を伴う実際の例を使用してすべてを示します。始めましょう。 クラス、ネストされたクラスの種類と例 - 1そして、重要なことは最初の 2 種類のクラスを理解することであり、ローカルと匿名は単に内部クラスのサブタイプであることに注意してください。

クラスとは何ですか?

クラスは何かの論理的な説明であり、それを使用して実際のインスタンスを作成できるテンプレートです。言い換えれば、それは作成されたエンティティがどのようなものであるべきか、つまりどのようなプロパティとメソッドを持つべきかを単に説明したものです。 プロパティはエンティティの特性であり、メソッドはエンティティが実行できるアクションです。クラスが何であるかを理解するための現実のクラスの良い例は、図面と考えることができます。図面は構造 (カタパルト、ドライバー) を説明するために使用されますが、図面は設計ではありません。エンジニアが設計図を使用して設計を作成するのと同じように、プログラミングではクラスを使用して、プロパティとメソッドが記述されたオブジェクトを作成します。
public class Student {
    private String name, group, specialty;

    public Student(String name, String group, String specialty) {
       this.name = name;
       this.group = group;
       this.specialty = specialty;
   }

   // getters/setters
}
この例では、「学生」エンティティを記述する Java クラスを作成しました。各学生には名前、グループ、専門分野があります。ここで、プログラムの他の場所で、このクラスの実際の例を作成できます。言い換えれば、クラスがStudent生徒のあるべき姿を描いたものである場合、作成されたインスタンスは実際の生徒そのものです。新しい生徒を作成する例:new Student("Ivan", "KI-17-2", "Computer Engineering");オペレーターはnewクラスを検索しStudent、このクラスの特別なメソッド (コンストラクター) を呼び出します。コンストラクターは既製のクラス オブジェクトを返しますStudent- 奨学金のないお腹を空かせた親愛なる学生 :))

Javaのクラスの種類

Java では、別のクラス内に 4 種類のクラスがあります。
  1. ネストされた内部クラスは、外部クラス内の非静的クラスです。

  2. ネストされた静的クラスは、外部クラス内の静的クラスです。

  3. Java ローカル クラスはメソッド内のクラスです。

  4. 匿名 Java クラスは、その場で作成されるクラスです。

それぞれについて個別に説明します。

外部クラス内の非静的クラス

まず、実際の例でこれが何であるかを理解してください。そうすることで非常に理解しやすくなります。それでは、実際に大きなものを小さなコンポーネントに分解し、飛行機を分解してみましょう。ただし、例として少しだけ示すだけで十分なので、完全に分解するわけではありません。このプロセスを視覚化するために、飛行機の図を使用します。 まず、航空機名、識別コード、フライトなどの簡単な説明を追加できる クラス、ネストされたクラスの種類と例 - 2 クラスを作成する必要があります。Airplane
public class Airplane {
    private String name, id, flight;

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    // getters/setters
}
次に翼を追加したいと思います。別のクラスを作成しますか? おそらくこれは、飛行機を設計するための複雑なプログラムがあり、膨大な数の派生クラス (親クラス、つまり継承元のクラスと同じロジックを持つクラスですが、親クラスと同じロジックを持つクラス) を作成する必要がある場合のロジックです。そのため、ロジックやより詳細な特性を追加することで親クラスを拡張します)。しかし、飛行機が 1 つだけあるゲームの場合はどうなるでしょうか? そうなると、全体の構造を 1 か所 (1 つのクラス) で完成させる方が合理的になります。ここで、非静的ネストされたクラスが活躍します。基本的に、これは外部クラスの詳細の一部をより詳細に説明したものです。この例では、飛行機の左右の翼を作成する必要があります。作ってみましょう!
public class Airplane {
    private String name, id, flight;
    private Wing leftWing = new Wing("Red", "X3"), rightWing = new Wing("Blue", "X3");

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    private class Wing {
        private String color, model;

        private Wing(String color, String model) {
            this.color = color;
            this.model = model;
        }

        // getters/setters
    }

    // getters/setters
}
Wingそこで、クラス (飛行機) 内に 非静的入れ子クラス (翼) を作成しAirplane、左翼と右翼という 2 つの変数を追加しました。そして、各翼には変更できる独自のプロパティ (色、モデル) があります。こうすることで、必要なだけ構造物に人員を配置できます。注: 先ほどの図では、航空機の部品が非常に多くありました。実際、すべての部品を内部クラスに分割できますが、そのようなプロセスは常に推奨されるわけではありません。タスクに応じて、そのような瞬間を追跡する必要があります。問題を解決するのに翼はまったく必要ないかもしれません。そうすれば、それらを行う必要はありません。これは、人を足、腕、胴体、頭に切断するようなものです。それは可能ですが、このクラスが人に関するデータを保存するためだけに使用されるのはなぜでしょうか? 非静的ネストされた Java クラスの特徴:
  1. これらはオブジェクト内にのみ存在するため、作成するにはオブジェクトが必要です。言い換えれば、私たちは翼を飛行機の一部として設計したので、翼を作成するには飛行機が必要ですが、そうでなければ飛行機は必要ありません。
  2. Java クラス内に静的変数を含めることはできません。定数やその他の静的なものが必要な場合は、それらを外部クラスに移動する必要があります。これは、非静的ネストされたクラスが外部クラスに密接に結合しているためです。
  3. このクラスは、外部クラスのすべてのプライベート フィールドに完全にアクセスできます。この機能は 2 つの方法で機能します。
  4. 外部クラスのインスタンスへの参照を取得できます。例: 飛行機。これは飛行機へのリンク、これは翼へのリンクです。

外部クラス内の静的クラス

このタイプのクラスは、通常の外部クラスと何ら変わりませんが、1 つだけ異なります。このようなクラスのインスタンスを作成するには、外部クラスから目的のクラスまでのパス全体をドットで区切ってリストする必要があります。例:Building.Plaftorm platform = new Building.Platform(); 静的クラスは、論理構造を扱いやすくするために、関連するクラスを並べて配置するために使用されます。たとえば、外部クラスを作成できますBuilding。そこには、特定の建物を表すクラスの特定のリストが含まれます。
public abstract class Building {
    private String name, address, type;

    Building(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public static class Platform extends Building {
        public Platform(String name, String address) {
            super(name, address);
            setType("Platform");
        }

        // some additional logic
    }

    public static class House extends Building {
        public House(String name, String address) {
            super(name, address);
            setType("House");
        }

        // some additional logic
    }

    public static class Shop extends Building {
        public Shop(String name, String address) {
            super(name, address);
            setType("Shop");
        }

        // some additional logic
    }

    // getters/setters
}
この例では、静的クラスを使用して論理構造をより便利な形式にパッケージ化する方法を示します。それらが存在しない場合は、4 つのまったく異なるクラスを作成する必要があります。 このアプローチの利点は次のとおりです。
  1. 授業数が減りました。
  2. すべてのクラスはその親クラス内にあります。各クラスを個別に開かなくても、階層全体をトレースできます。
  3. Building クラスを参照すると、IDE はすでにこのクラスのすべてのサブクラスのリスト全体を表示します。これにより、必要なクラスを見つけやすくなり、全体像をより総合的に表示できるようになります。
ネストされた静的クラスのインスタンスを作成する例:Building.Shop myShop = new Building.Shop(“Food & Fun!”, “Kalyaeva 8/53”); この戦略は、Line2D、Arc2D、Ellipse2D などの形状を記述するために AWT 2D クラスで使用されることにも注意してください。

ローカルクラス

これらのクラスは他のメソッド内で宣言されます。実際、それらは非静的ネストされたクラスのすべてのプロパティを持ち、それらのインスタンスのみがメソッド内でのみ作成でき、メソッドを静的にすることはできません (これらを作成するには、外部クラスのインスタンス、つまりクラスへの参照が必要です)。呼び出し元オブジェクトのインスタンスは暗黙的に非静的メソッドに渡され、静的メソッドにはこのリンクのメソッドはありません)。 しかし、それらには独自の特徴があります。
  1. ローカル クラスは、final メソッド変数でのみ動作します。問題は、メソッドの完了後にローカル クラスのインスタンスをヒープに保存でき、変数を消去できることです。変数がfinalと宣言されている場合、コンパイラは、後でオブジェクトで使用できるように変数のコピーを保存できます。そしてもう 1 つ: Java の 8 以降のバージョンでは、ローカル クラスで非 Final 変数を使用できますが、それは変更されないという条件に限ります。
  2. ローカル クラスはアクセス修飾子を使用して宣言できません。
  3. ローカル クラスはメソッド変数にアクセスできます。
ローカル クラスは、コードを読みにくくし、メソッド変数へのアクセスを除いて何の利点もないため、非常にまれに見つかります。ローカル クラスのどのような例が効果的な使用法を示すことができるかわからないので、私の例だけを示します。プロパティ(通り)、 (家) を持つクラスPerson(これは人であると仮定します) があるとします。その人の位置だけにアクセスするために、何らかのオブジェクトを返したいと考えています。これを行うために、人の位置に関するデータの保存を意味する AddressContainer インターフェイスを作成しました。 streethouse
public class Person {
    private String name, street, house;

    public Person(String name, String street, String house) {
        this.name = name;
        this.street = street;
        this.house = house;
    }

    private interface AddressContainer {
        String getStreet();
        String getHouse();
    }

    public AddressContainer getAddressContainer() {
        class PersonAddressContainer implements AddressContainer {
            final String street = Person.this.street, house = Person.this.house;

            @Override
            public String getStreet() {
                return this.street;
            }

            @Override
            public String getHouse() {
                return this.house;
            }
        }

        return new PersonAddressContainer();
    }

    public static void main(String[] args) {
        Person person = new Person("Nikita", "Sholohova", "17");

        AddressContainer address = person.getAddressContainer();

        System.out.println("Address: street - " + address.getStreet() + ", house - " + address.getHouse());
    }

    // getters/setters
}
ご覧のとおり、メソッド内で人の位置の保存を実装するクラスを作成し、そこに定数変数を作成し (メソッドを終了した後、変数がオブジェクトに保存されるように)、住所とデータを取得するためのメソッドを実装しました。家。これで、このオブジェクトをプログラム内の他の場所で使用して、人の位置を取得できるようになります。この例が理想的ではないことは理解しています。単に getter を class 内に残すだけで実行する方が正しいでしょう。Personただし、このクラスの作成とその使用方法は示されており、あとはあなた次第です。

匿名クラス

内部的には、匿名クラスは通常の非静的ネストされたクラスです。彼らの特徴はその使いやすさです。別のクラスのインスタンスを作成するときに、クラスを直接記述することができます。
public class Animal {
    public void meow() {
        System.out.println("Meow!");
    }

    public static void main(String[] args) {
        Animal anonTiger = new Animal() {
            @Override
            public void meow() {
                System.out.println("Raaar!");
            }
        };

        Animal notAnonTiger = new Animal().new Tiger();

        anonTiger.meow(); // будет выведено Raaar!
        notAnonTiger.meow(); // будет выведено Raaar!
    }

    private class Tiger extends Animal {
        @Override
        public void meow() {
            System.out.println("Raaar!");
        }
    }
}
Animal基本的に、1 つのクラスのインスタンスの作成 ( ) とその継承内部クラスのインスタンスの作成 ( ) という 2 つのことを 1 か所で組み合わせているだけですTiger。それ以外の場合は、クラスを個別に作成し、同じ結果を得るためにより長い構造を使用する必要があります。 多くの場合、特に次の場合に匿名クラスの使用が正当化されます。
  • クラス本体は非常に短いです。
  • 必要なクラスのインスタンスは 1 つだけです。
  • クラスは、作成された場所またはその直後に使用されます。
  • クラス名は重要ではなく、コードを理解しやすくするものでもありません。
匿名クラスは、GUI でイベント ハンドラーを作成するためによく使用されます。たとえば、ボタンを作成し、そのクリックに反応するには、次のようにします。
JButton b2 = new JButton("Click");
b2.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Кнопка нажата!");
    }
});
ただし、Java 8 以降ではラムダ式が使用されるようになりましたが、依然として多くのコードはバージョン 8 より前に記述されており、そのような記述に遭遇する可能性があります (JavaRush のトレーニング中に遭遇するでしょう)。\ ラムダ式との類似:
JButton b2 = new JButton("Click");
b2.addActionListener(e -> System.out.println("Кнопка нажата!"));
記事の終わり ご清聴ありがとうございました。何か新しいことを学んだり、以前は理解できなかったことを理解していただければ幸いです。また、この記事が「細部へのこだわり」カテゴリに属していることも明確にしておきたいと思います。初めての作品なので、誰かのお役に立てれば幸いです。近い将来、新しいアイデアが浮かんだら、別のことを書こうと思います。アイデアが 1 つだけあります... 皆さんの幸運とプログラミングの成功を祈ります :)
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION