やあ!今日は、入れ子になったクラスの継承という重要なメカニズムを見ていきます。ネストされたクラスに他のクラスを継承させる必要がある場合にどうするかを考えたことはありますか。そうでない場合は、信じてください。この状況には多くのニュアンスがあるため、混乱を招く可能性があります。
- ネストされたクラスに何らかのクラスを継承させているのでしょうか?それとも、一部のクラスにネストされたクラスを継承させているのでしょうか?
- 子/親クラスは通常のパブリック クラスですか、それともネストされたクラスでもありますか?
- 最後に、これらすべての状況でどのようなタイプのネストされたクラスを使用すればよいでしょうか?
静的入れ子クラス
それらの継承ルールは最も単純です。ここでは、あなたの心が望むことはほとんど何でもできます。静的ネストされたクラスは以下を継承できます。- 普通のクラス
- 外部クラスまたはその祖先で宣言された静的なネストされたクラス
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
コードを変更して、Drawing
静的に入れ子になったクラスとその子孫を作成してみましょうBoeing737Drawing
。
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
public static class Boeing737Drawing extends Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
ご覧のとおり、問題ありません。クラスを取り出してDrawing
、静的に入れ子になったクラスではなく、通常のパブリック クラスにすることもできます。何も変わりません。
public class Drawing {
}
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Boeing737Drawing extends Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
私たちはこれを理解しています。しかし、静的にネストされたクラスを継承できるのはどのクラスでしょうか? 実質的にどれでも!ネストされているかどうか、静的か非静的かは関係ありません。ここでは、Boeing737Drawing
内部クラスにDrawing
静的なネストされたクラスを継承させます。
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
public class Boeing737Drawing extends Drawing {
public int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
次のようなインスタンスを作成できますBoeing737Drawing
。
public class Main {
public static void main(String[] args) {
Boeing737 boeing737 = new Boeing737(1990);
Boeing737.Boeing737Drawing drawing = boeing737.new Boeing737Drawing();
System.out.println(drawing.getMaxPassengersCount());
}
}
このBoeing737Drawing
クラスは静的クラスを継承していますが、それ自体は静的ではありません。その結果、常に外部クラスのインスタンスが必要になります。Boeing737Drawing
クラスからクラスを削除してBoeing737
、単純なパブリック クラスにすることができます。何も変わりません。静的なネストされたクラスを継承することもできますDrawing
。
public class Boeing737 {
private int manufactureYear;
public static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
}
public class Boeing737Drawing extends Boeing737.Drawing {
public int getMaxPassengersCount() {
return Boeing737.maxPassengersCount;
}
唯一重要な点は、この場合、静的maxPassengersCount
変数をパブリックにする必要があるということです。プライベートのままの場合、通常のパブリック クラスはアクセスできません。静的クラスを理解しました。:) 次に、内部クラスに移りましょう。単純な内部クラス、ローカル クラス、匿名内部クラスの 3 種類があります。 もう一度、単純なものから複雑なものに移りましょう:)
匿名の内部クラス
匿名内部クラスは別のクラスを継承できません。他のクラスは匿名クラスを継承できません。これ以上簡単なことはありません。:)ローカルクラス
ローカル クラスは (忘れた場合に備えて) 別のクラスのコード ブロック内で宣言されます。ほとんどの場合、これは外部クラスのメソッド内で発生します。論理的には、同じメソッド (またはコード ブロック) 内の他のローカル クラスのみがローカル クラスを継承できます。以下に例を示します。
public class PhoneNumberValidator {
public void validatePhoneNumber(final String number) {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber() {
this.phoneNumber = number;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
class CellPhoneNumber extends PhoneNumber {
}
class LandlinePhoneNumber extends PhoneNumber {
}
// ...number validation code
}
}
これはローカル クラスのレッスンのコードです。数値バリデータ クラスにはPhoneNumber
ローカル クラスがあります。携帯電話番号と固定電話番号など、2 つの異なるエンティティを表す必要がある場合、これを同じメソッド内でのみ行うことができます。理由は簡単です。ローカル クラスのスコープは、それが宣言されているメソッド (コード ブロック) に限定されます。その結果、外部から (クラスの継承を含む) 使用することができなくなります。ただし、ローカル クラス自体内での継承の可能性はさらに広いです。ローカル クラスは以下を継承できます。
- 普通のクラス。
- ローカル クラスと同じクラス、またはその祖先の 1 つで宣言された内部クラス。
- 同じメソッド (コード ブロック) で宣言された別のローカル クラス。
public class PhoneNumberValidator {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
public void validatePhoneNumber(final String number) {
class CellPhoneNumber extends PhoneNumber {
public CellPhoneNumber(String phoneNumber) {
super(number);
}
}
class LandlinePhoneNumber extends PhoneNumber {
public LandlinePhoneNumber(String phoneNumber) {
super(number);
}
}
// ...number validation code
}
}
PhoneNumber
ここではメソッドからクラス を削除しvalidatePhoneNumber()
、ローカル クラスではなく内部クラスにしました。これは、2 つのローカル クラスにそれを継承させることを妨げるものではありません。例 2 — 「... またはこのクラスの先祖にあります。」さて、これはすでにさらに興味深いものです。PhoneNumber
継承チェーンのさらに上位に進むことができます。AbstractPhoneNumberValidator
私たちのクラスの祖先となる抽象クラスを宣言しましょうPhoneNumberValidator
。
public abstract class AbstractPhoneNumberValidator {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
}
ご覧のとおり、単に宣言しただけではなく、PhoneNumber
内部クラスもその中に移動しました。ただし、その子孫では、メソッドで宣言されたローカル クラスは問題なく PhoneNumberValidator
継承できます。PhoneNumber
public class PhoneNumberValidator extends AbstractPhoneNumberValidator {
public void validatePhoneNumber(final String number) {
class CellPhoneNumber extends PhoneNumber {
public CellPhoneNumber(String phoneNumber) {
super(number);
}
}
class LandlinePhoneNumber extends PhoneNumber {
public LandlinePhoneNumber(String phoneNumber) {
super(number);
}
}
// ...number validation code
}
}
継承関係により、子孫クラス内のローカル クラスは祖先内の内部クラスを「認識」します。そして最後に、最後のグループに進みましょう:)
内部クラス
同じ外部クラス (またはその子孫) で宣言された内部クラスは、別の内部クラスを継承できます。内部クラスのレッスンの自転車の例を使用して、これを検討してみましょう。
public class Bicycle {
private String model;
private int maxWeight;
public Bicycle(String model, int maxWeight) {
this.model = model;
this.maxWeight = maxWeight;
}
public void start() {
System.out.println("Let's go!");
}
class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
class SportSeat extends Seat {
// ...methods
}
}
Seat
ここではクラス内で内部クラス を宣言しましたBicycle
。専用タイプのレーシングシートはSportSeat
それを継承しています。ただし、別の「レーシングバイク」タイプを作成し、それを別のクラスに置くこともできます。
public class SportBicycle extends Bicycle {
public SportBicycle(String model, int maxWeight) {
super(model, maxWeight);
}
class SportSeat extends Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
}
これもオプションです。子孫の内部クラス ( SportBicycle.SportSeat
) は、祖先の内部クラスを「認識」し、それらを継承できます。内部クラスの継承には、非常に重要な機能が 1 つあります。前の 2 つの例では、SportSeat
クラスは内部クラスでした。しかし、内部クラスSportSeat
を同時に継承する通常のパブリック クラスを作成することにした場合はどうなるでしょうかSeat
?
// Error! No enclosing instance of type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {
public SportSeat() {
}
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
エラーが発生しました! その理由はわかりますか? :) それはすべて簡単です。内部クラスについて説明したときにBicycle.Seat
、外部クラスのインスタンスへの参照が暗黙的に内部クラスのコンストラクターに渡されると述べました。Seat
これは、オブジェクトを作成せずにオブジェクトを作成することはできないことを意味しますBicycle
。しかし、 の作成についてはどうでしょうかSportSeat
。とは異なりSeat
、コンストラクターに外部クラスのインスタンスへの参照を暗黙的に渡すための組み込みメカニズムがありません。オブジェクトがなければ、の場合と同様に、オブジェクトをBicycle
作成することはできません。したがって、私たちが行うべきことは 1 つだけ残っています。それは、オブジェクトへの参照をコンストラクターに明示的に渡すことです。その方法は次のとおりです。 SportSeat
Seat
SportSeat
Bicycle
class SportSeat extends Bicycle.Seat {
public SportSeat(Bicycle bicycle) {
bicycle.super();
}
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
super();
さて、オブジェクトを作成したい場合は、次のコマンド を使用してスーパークラス コンストラクターを呼び出しますSportSeat
。
public class Main {
public static void main(String[] args) {
Bicycle bicycle = new Bicycle("Peugeot", 120);
SportSeat peugeotSportSeat = new SportSeat(bicycle);
}
}
ふう!このレッスンはかなり長かったです :) でも、たくさんのことを学びました! 今度はいくつかのタスクを解決します。:)
GO TO FULL VERSION