こんにちは!今日は、重要なメカニズムである入れ子クラスの継承の動作を見ていきます。ネストされたクラスを他のクラスから継承する必要がある場合にどうするか考えたことがあるかどうかはわかりません。そうでない場合は、信じてください。ここには多くのニュアンスがあるため、この状況は混乱を招く可能性があります。
- ネストされたクラスをあるクラスから継承するのでしょうか、それともネストされたクラスから別のクラスを継承するのでしょうか?
- 後継者/継承されたクラスは通常のパブリック クラスですか、それとも入れ子のクラスでもありますか?
- 最後に、これらすべての状況で使用しているネストされたクラスの正確なタイプは何でしょうか?
静的入れ子クラス
継承のルールは最も単純です。ここでは、あなたの心が望むことはほとんど何でもできます。静的ネストされたクラスは以下から継承できます。- 通常クラス
- 外部クラスまたはその祖先で宣言された静的なネストされたクラス
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
、ただの公開クラスにすることもできます。何も変わりません。静的なネストされた .html から継承することもできます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 {
}
//...code валидации номера
}
}
これは、ローカル クラスに関する講義のコードです。番号バリデーター クラス内には、ローカル クラスPhoneNumber
、つまり電話番号があります。目的のために、そこから 2 つの別個のエンティティ (携帯電話番号と固定電話番号など) を抽出する必要がある場合、これは同じメソッド内でのみ行うことができます。理由は簡単です。ローカル クラスのスコープは、それが宣言されているメソッド (ブロック) 内にあるからです。したがって、何らかの形で外部(継承を含む)で使用することはできません。ただし、ローカル クラス自体には、より広い継承の可能性があります。ローカル クラスは以下のものを継承できます。
- レギュラークラス。
- ローカル クラスと同じクラス、またはその祖先で宣言された内部クラス。
- 同じメソッド (ブロック) で宣言された別のローカル クラスから。
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);
}
}
//...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);
}
}
//...code валидации номера
}
}
継承による接続のおかげで、子孫クラス内のローカル クラスは、祖先内の内部クラスを「参照」します。そして最後に、最後のグループに進みましょう:)
内部クラス
内部クラスは、同じ外部クラス (またはその子孫) で宣言された別の内部クラスによって継承できます。インナークラスに関する講義の自転車の例を使用してこれを見てみましょう。public class Bicycle {
private String model;
private int mawWeight;
public Bicycle(String model, int mawWeight) {
this.model = model;
this.mawWeight = mawWeight;
}
public void start() {
System.out.println("Go!");
}
class Seat {
public void up() {
System.out.println("Сидение поднято выше!");
}
public void down() {
System.out.println("Сидение опущено ниже!");
}
}
class SportSeat extends Seat {
//...methods
}
}
ここでは、クラス - Seat内でBicycle
内部クラスを宣言しましたSeat
。レーシングシートの特別なサブタイプは、そこから受け継がれていますSportSeat
。ただし、別のタイプの「レーシング バイク」を作成し、別のクラスに入れることもできます。
public class SportBicycle extends Bicycle {
public SportBicycle(String model, int mawWeight) {
super(model, mawWeight);
}
class SportSeat extends Seat {
public void up() {
System.out.println("Сидение поднято выше!");
}
public void down() {
System.out.println("Сидение опущено ниже!");
}
}
}
これも可能です。子の内部クラス ( SportBicycle.SportSeat
) は、祖先の内部クラスを「認識」し、それらを継承できます。内部クラスからの継承には、非常に重要な特徴が 1 つあります。前の 2 つの例では、SportSeat
internal がありました。しかし、SportSeat
これを内部クラスからも継承する通常のパブリック クラスにすることにした場合はどうなるでしょうかSeat
?
//ошибка! No inclosing instance of type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {
public SportSeat() {
}
public void up() {
System.out.println("Сидение поднято выше!");
}
public void down() {
System.out.println("Сидение опущено ниже!");
}
}
エラーが発生しました! それが何と関係しているかわかりますか?:) それは簡単です。内部クラスについて説明したときにBicycle.Seat
、内部クラスのコンストラクターが外部クラスのオブジェクトへの参照を暗黙的に渡すと述べました。したがって、オブジェクトを作成しない限り、Bicycle
オブジェクトを作成することはできませんSeat
。創造についてはどうですかSportSeat
?これには、コンストラクター内の外部クラス オブジェクトへの参照を暗黙的に渡すための、 のような組み込みメカニズムはありませんSeat
。ただし、オブジェクトがなければBicycle
、 の場合と同様にSeat
、オブジェクトを作成することはできませんSportSeat
。したがって、やるべきことは 1 つだけ残っています。それは、SportSeat
オブジェクトへの参照をコンストラクターにBicycle
明示的に渡すことです。その方法は次のとおりです。
class SportSeat extends Bicycle.Seat {
public SportSeat(Bicycle bicycle) {
bicycle.super();
}
public void up() {
System.out.println("Сидение поднято выше!");
}
public void down() {
System.out.println("Сидение опущено ниже!");
}
}
このために特別な単語を使用します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