VScodeでJavaの継承を学んでいます(Javaの継承の特徴、superキーワード、superとthisの比較、メソッドの書き換え、サブクラスのコンストラクタ)Ⅱ

クラス メンバーには、メンバー変数、メンバー メソッド、構築メソッドが含まれます。

構築方法:どの修飾子でも継承可能
メンバ変数:全て継承可能だが一点注意(継承!=呼び出し、プライベートなものは呼び出せない)
メンバメソッド:プライベート以外も可能。プライベートではありません。

私の個人的なブログのホームページ: If '' が本当に脱出できる場合 1️⃣ Say 1️⃣
Java の基本文法学習に関するブログのホームページ ----> 私のブログを参照してください: 「VScode で Java を学ぶ」
について —> 私のブログを参照してください記事「VScodeでJava継承を学ぶ(Java継承とは何か、特徴、サブクラス継承とは何か)1」

記事ディレクトリ

継承におけるメンバ変数アクセスの特徴: 近接性の原理

これは、サブクラス内に親クラスと同名のメンバ変数が存在する場合、サブクラスは親クラスから継承した同名のメンバ変数ではなく、自身のメンバ変数に優先的にアクセスすることを意味します。

具体的には、サブクラス内でメンバ変数を使用する場合、まずサブクラス自体にそのメンバ変数があるかどうかを確認し、存在する場合はサブクラスのメンバ変数を直接使用します。サブクラスにそのようなメンバー変数がない場合、システムは上向きの検索を続けて、親クラスに同じ名前のメンバー変数があるかどうかを見つけます。親クラスに同じ名前のメンバ変数が見つかった場合は、親クラスのメンバ変数が使用されます。

この機能により、継承関係において、サブクラスは、親クラスと同じ名前のメンバー変数を定義することで、親クラスのメンバー変数を非表示にしたりオーバーライドしたりできるようになります。このようにして、サブクラスは、親クラスから継承したメンバー変数を独自のニーズに応じてカスタマイズできます。

なお、サブクラスは親クラスのメンバ変数を隠すことができますが、これは親クラス自体のメンバ変数には影響せず、親クラスのメンバ変数は親クラスに存在したままになります。サブクラス内の親クラスのメンバー変数にアクセスする必要がある場合は、 super キーワードを使用して親クラスのメンバー変数を参照できます。
ここに画像の説明を挿入

スーパーキーワード

Java では、super親またはスーパークラス (基本クラス) への参照を示すために使用されるキーワードです。これをサブクラスで使用して、親クラスのメンバー変数、メンバー メソッド、またはコンストラクターにアクセスできます。主に以下のような用途があります。

  1. 親クラスのメンバー変数にアクセスする:superサブクラス内に同じ名前のメンバー変数がある場合でも、キーワードを使用してサブクラス内の親クラスのメンバー変数にアクセスします。

  2. 親クラスのメンバー メソッドを呼び出す: サブクラスでは、superキーワードを使用して、サブクラスによってオーバーライドされる親クラスのメソッドを呼び出すか、サブクラスによってカバーされない親クラスのメソッドを呼び出します。

  3. 親クラスのコンストラクターを呼び出す: サブクラスのコンストラクターでは、superキーワードを使用して親クラスのコンストラクターを明示的に呼び出し、親クラスの初期化ロジックが確実に実行されるようにすることができます。

キーワードを使用すると、superサブクラスが相互作用して親クラスから継承することができるため、コードを効果的に拡張および再利用できます。

スーパーとこの比較

Java では、thisキーワードとsuperキーワードはどちらもクラスのメンバーにアクセスしたり、コンストラクターを呼び出したりするために使用されますが、機能と使用法が異なります。

关键字:
- `this`:用于引用当前类的实例,用于访问当前类的成员变量、方法和构造方法。
- `super`:用于引用当前类的父类,用于访问父类的成员变量、方法和构造方法。

1.thisキーワード:

`this` 关键字用于引用当前类的实例。可以理解为一个变量。
		表示当前对象的地址,并且用于访问或调用当前类的成员变量和方法。
实际上是通过这个方法的隐式参数来传递当前对象的引用。
		这个隐式参数就是 this,它指向当前调用该方法的对象。
  • 現在のオブジェクト、つまりメソッドまたはコンストラクターが現在呼び出されているオブジェクトのインスタンスを参照するために使用されます。
  • メンバー変数とローカル変数が同じ名前である場合、それらを区別するために使用できます。
  • クラスの他のコンストラクターを呼び出して、1 つのコンストラクター内のコードを再利用するために使用できます (コンストラクターのオーバーロード)。

2.superキーワード:

`super` 关键字用于引用当前类的父类(超类)。
	它表示父类的存储空间,并且用于访问或调用父类的成员变量、方法或构造方法。
  • 親クラス (スーパークラス) のメンバーを参照するか、親クラスのコンストラクターを呼び出すために使用されます。
  • superスーパークラスのメソッドとメンバーには、特にスーパークラスのメソッドがサブクラスでオーバーライドされる場合、キーワードを介してアクセスできます。
  • サブクラスの構築メソッドでは、superキーワードを使用して親クラスの構築メソッドを呼び出し、親クラスの初期化作業を確実に実行できます。

3. 例:

class Parent {
    
    
    int value = 10;

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

class Child extends Parent {
    
    
    int value = 20;

    void display() {
    
    
        System.out.println("Child class method");
    }

    void printValues() {
    
    
        int value = 30;
        System.out.println(value); // Prints local variable value (30)
        System.out.println(this.value); // Prints Child class variable value (20)
        System.out.println(super.value); // Prints Parent class variable value (10)

        this.display(); // Calls Child class method
        super.display(); // Calls Parent class method
    }
}
要約:
  • thisキーワードは、現在のオブジェクト参照とコンストラクター呼び出しに使用されます。
  • superキーワードは、スーパークラスのメンバーにアクセスし、スーパークラスのコンストラクターを呼び出すために使用されます。
使用法:
  • メンバー変数へのアクセス:this.成员变量名現在のクラスのメンバー変数とsuper.成员变量名親クラスのメンバー変数を示します。
  • アクセス メンバー メソッド:this.方法名(...)現在のクラスのメンバー メソッドを意味し、super.方法名(...)親クラスのメンバー メソッドを意味します。
  • アクセスコンストラクター:this(...)現在のクラスの構築メソッドとsuper(...)親クラスの構築メソッドを示します。
1.> ローカル変数とメンバ変数の名前が異なる場合、thisキーワードは省略可能です。

Java では、メソッド内のローカル変数がクラスのメンバー変数と同じ名前を持たない場合、コンパイラーは自動的にそれらを区別し、ローカル変数を最初に使用します。したがって、名前の競合がない場合は、thisキーワードを省略してクラスのメンバー変数を参照できます。

ただし、ローカル変数とメンバ変数が同じ名前の場合、クラスのメンバ変数を使用していることを明示するために、キーワードを使用して区別する必要があります this

public class Student {
    
    
    private String name; // 成员变量

    public Student(String name) {
    
    
        // 参数name和成员变量name同名,需要使用this关键字来区分
        this.name = name;
    }

    public void displayInfo(String name) {
    
    
        // 参数name和成员变量name不同名,可以省略this关键字
        System.out.println("传入的参数name:" + name);
        System.out.println("成员变量name:" + this.name);
    }
}

上の例では、コンストラクター内のパラメーターはnameクラスのメンバー変数と同じ名前を持っているため、メンバー変数を参照するためにname 使用します。this.name
displayInfo メソッドでは、パラメーターnameとメンバー変数のname 名前が異なるため、this キーワードを省略してローカル変数を直接使用できますname

2.>this(...) コンストラクター内で同じクラスの他のコンストラクターを呼び出すために使用されます。これはコンストラクター内でのみ使用でき、コンストラクターの最初のステートメントである必要があります。
 // Constructor with three parameters___具有三个参数的构造函数
    public Student(String name, int age, String school) {
    
    
        this.name = name;
        this.age = age;
        this.school = school;
    }

    // Constructor with no parameters, calling the three-parameter constructor using this(...)
    //没有参数的构造函数,使用以下(...)调用三参数构造函数
    public Student() {
    
    
        this(null, 0, "Magic_School");
    }

Javaでは、同じ名前のメンバ変数が存在する場合、特定のキーワードを使用することで区別できます。通常、次の 3 つの方法があります。

就近原则

1. ローカル位置から開始して以下を調べます。

同じ名前のローカル変数が現在のスコープ (メソッドまたはコード ブロック) で定義されている場合、同じ名前のメンバー変数がオーバーライドされます。この場合、メンバー変数にアクセスするには、thisキーワードを使用して、現在のクラスのメンバー変数にアクセスすることを明確に示すことができます。

public class MyClass {
    
    
    private String name = "Class member variable";

    public void printName(String name) {
    
    
        System.out.println(name);       // 局部变量name
        System.out.println(this.name);  // 类的成员变量name
    }
}

2. このクラスのメンバー位置から上方向に検索します。

現在のクラスの別のメソッドに同じ名前のメンバー変数が存在する場合、メンバー変数の名前を直接使用してアクセスでき、コンパイラーは自動的に正しいメンバー変数を選択します。

public class MyClass {
    
    
    private String name = "Class member variable";

    public void method1() {
    
    
        System.out.println(name);  // 类的成员变量name
    }

    public void method2() {
    
    
        System.out.println(name);  // 类的成员变量name
    }
}

3. 親クラスのメンバーの位置から上を見上げます。

現在のクラスが他のクラスから継承しており、親クラスと子クラスに同じ名前のメンバー変数がある場合、superキーワードを使用して親クラスのメンバー変数にアクセスできます。

public class ParentClass {
    
    
    protected String name = "Parent class member variable";
}

public class ChildClass extends ParentClass {
    
    
    private String name = "Child class member variable";

    public void printNames() {
    
    
        System.out.println(name);          // 子类的成员变量name
        System.out.println(this.name);     // 子类的成员变量name
        System.out.println(super.name);    // 父类的成员变量name
    }
}

概要: Java では、thisキーワードを使用することにより、現在のクラスのメンバー変数を指すことができ、superキーワードは親クラスのメンバー変数を指すことができます。さまざまなキーワードを使用すると、正しいメンバー変数にアクセスできます。

このキーワード + スーパーキーワード

在Java中,如果在不同的作用域(例如实例变量和局部变量)中出现了同名的变量,
	可以使用`this`关键字来引用实例变量并访问正确的变量。`
this`关键字是对当前类实例的引用。

例えば:

public class MyClass {
    
    
    private String name; // 这是实例变量

    public MyClass(String name) {
    
    
        this.name = name; // 使用"this"关键字来给实例变量赋值
    }

    public void printName() {
    
    
        String name = "局部变量"; // 这是局部变量
        System.out.println(name); // 这里引用的是局部变量
        System.out.println(this.name); // 这里引用的是实例变量
    }
}
类似地,如果一个类继承自另一个父类,并且两个类中有同名的变量,
	可以使用`super`关键字来引用父类的变量。

例えば:

public class ParentClass {
    
    
    protected String name = "父类成员变量";
}

public class ChildClass extends ParentClass {
    
    
    private String name = "子类成员变量";

    public void printNames() {
    
    
        System.out.println(name); // 这里引用的是子类的变量
        System.out.println(this.name); // 这里也引用的是子类的变量
        System.out.println(super.name); // 这里引用的是父类的变量
    }
}

概要: Java では、thisキーワードは現在のクラス インスタンスを参照するために使用され、superキーワードは親クラスを参照するために使用されます。これらのキーワードは、同じ名前を持つが異なるスコープまたはクラスに属する変数にアクセスする必要がある場合に便利です。

継承におけるメンバーメソッドアクセスの特徴:近接原理+スーパーコール:

Java 継承では、メンバー メソッド アクセスには、近接性の原理とキーワード呼び出しの使用という 2 つの重要な機能がありますsuper

1. 近接原理:

Java中的就近原则是指在方法调用或变量访问时,会优先选择离当前位置最近的方法或变量。
	这意味着如果在当前类中存在与父类相同名称的方法或变量,Java会优先使用当前类中的方法或变量。	

近接原則とは、継承チェーンにおいて、サブクラスと親クラスに同じ名前のメンバー メソッドがある場合、サブクラスは親クラスのメソッドではなく、最初に独自のメソッドを呼び出すことを意味します。言い換えれば、サブクラスのメソッドはスーパークラスのメソッドを「カバー」(上書き)します。この機能により、サブクラスは継承されたメソッドを必要に応じてカスタマイズまたは変更できます。

class Parent {
    
    
    void print() {
    
    
        System.out.println("This is the parent's print method.");
    }
}

class Child extends Parent {
    
    
    void print() {
    
    
        System.out.println("This is the child's print method.");
    }
}

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Child child = new Child();
        child.print(); // Output: This is the child's print method.
    }
}

上記の例では、子クラスChildのメソッドが親クラスprintのメソッドをオーバーライドしますParentprint

2.superキーワード call を使用します。

通过super关键字,可以直接访问父类中的方法或变量。

場合によっては、サブクラスのメソッドが親クラスのカバーされたメソッドを呼び出す必要がある場合があります。これはsuperキーワードを使用することで実現できます。superこのキーワードを使用すると、メソッドがサブクラスによってオーバーライドされた場合でも、スーパークラスのメソッドをサブクラスで呼び出すことができます。

class Parent {
    
    
    void print() {
    
    
        System.out.println("This is the parent's print method.");
    }
}

class Child extends Parent {
    
    
    void print() {
    
    
        super.print(); // Call the parent's print method
        System.out.println("This is the child's print method.");
    }
}

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Child child = new Child();
        child.print();
        /* Output:
           This is the parent's print method.
           This is the child's print method.
        */
    }
}

上記の例では、サブクラスChild内のメソッドは、print最初にsuper.print()親クラスを呼び出すメソッドを使用しParentprint次にサブクラス自体の出力を実行します。

概要:
Java 継承では、メンバー メソッドは近接性の原則に従い、サブクラスのメソッドは、親クラスのメソッドではなく、最初に独自のメソッドを呼び出します。ただし、親クラスのメソッドを呼び出す必要がある場合は、superキーワードを使用してそれを実現できます。

コード例:

class Person {
    
    
    public void eat() {
    
    
        System.out.println("Person eats rice and vegetables");
    }

    public void drink() {
    
    
        System.out.println("Person drinks water");
    }
}

class Student extends Person {
    
    
    public void lunch() {
    
    
        // 首先,检查在本类中是否有"eat"和"drink"方法,如果有,则调用本类中的方法。
        this.eat();
        this.drink();
        // 然后,直接调用父类(Person)中的"eat"和"drink"方法。
        super.eat();
        super.drink();
    }
}

// OverseasStudent类,继承自Person类
class OverseasStudent extends Person {
    
    
    public void lunch() {
    
    
        // 首先,检查在本类(OverseasStudent)中是否有"eat"和"drink"方法, 如果有,则调用本类中的方法。

        this.eat();
        this.drink();
        // 然后,直接调用父类(Person)中的"eat"和"drink"方法。

        super.eat();
        super.drink();
    }
    // 重写Person类中的"eat"方法
    @Override
    public void eat() {
    
    
        System.out.println("OverseasStudent eats spaghetti");
    }
    
    // 重写Person类中的"drink"方法
    @Override
    public void drink() {
    
    
        System.out.println("OverseasStudent drinks cold water");
    }
}

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Student localStudent = new Student();
        localStudent.lunch();

        System.out.println("--------------------");

        OverseasStudent overseasStudent = new OverseasStudent();
        overseasStudent.lunch();
    }
}

出力:

Person eats rice and vegetables
Person drinks water
Person eats rice and vegetables
Person drinks water
--------------------
OverseasStudent eats spaghetti
OverseasStudent drinks cold water
Person eats rice and vegetables
Person drinks water

コードの説明:

Java では、キーワード this は現在のクラスのメソッドを呼び出すか、現在のクラスのメンバー変数にアクセスするために使用され、キーワード super は親クラスのメソッドを呼び出すか、親クラスのメンバー変数にアクセスするために使用されます。

Lunch メソッドでは、this.eat() と this. Drink() が、現在のクラス (OutsideStudent または Student) で書き換えられた Eat メソッドと Drink メソッドを呼び出します。そして、 super.eat() と super. Drink() は、親クラス (person) の Eat メソッドと Drink メソッドを呼び出します。

したがって、OutsideStudent または Student が Lunch メソッドを呼び出すと、まず現在のクラスでオーバーライドされたメソッドが呼び出され、次に親クラスのメソッドが呼び出されます。

コードでは、OutsideStudent クラスが Person クラスの Eat メソッドと Drink メソッドをオーバーライドします。OutsideStudent オブジェクトが Lunch メソッドを呼び出すとき、まず IPv6 クラスに Eat メソッドと Drink メソッドがあるかどうかを確認し、存在する場合は IPv6 クラスのメソッドを呼び出します。したがって、OutsideStudent オブジェクトが Lunch メソッドを呼び出すと、「OutsideStudent はスパゲッティを食べます」と「OutsideStudent は冷たい水を飲みます」が出力されます。

次に、IPv6 クラスの Lunch メソッドは、スーパー キーワードを使用して、親クラス PERSON の Eat メソッドと Drink メソッドを直接呼び出します。これにより、親クラスの Eat メソッドと Drink メソッドが呼び出されます。したがって、OutsideStudent オブジェクトは、 Lunch メソッドを呼び出した後、「人は米と野菜を食べる」と「人は水を飲む」を出力します。

対照的に、localStudent オブジェクトは、person クラスの Eat メソッドと Drink メソッドをオーバーライドしない Student クラスのインスタンスです。したがって、localStudent オブジェクトが Lunch メソッドを呼び出すと、まず Student クラスに Eat メソッドと Drink メソッドがあるかどうかを確認し、存在しないことが判明した後、親クラス Person の Eat メソッドと Drink メソッドを直接呼び出します。これは、localStudent オブジェクトの Lunch メソッドを呼び出したときの出力結果が、OutsideStudent オブジェクトの出力結果とは異なるものの、親クラス Person の出力結果と同じである理由を説明しています。

メソッドのオーバーライド (メソッド オーバーライド) は、オブジェクト指向プログラミングにおける重要な概念です。これにより、サブクラスは、親クラスと同じ名前、パラメーター リスト、戻り値の型を持つメソッドを再定義して、独自の実装を実現できます。メソッドのオーバーライドは、実行時のポリモーフィズムを実現する鍵となります。

重写方法的核心目的是允许子类提供自己特定的实现,以便更好地适应子类的行为和需求。
	在运行时,当子类对象调用被重写的方法时,会优先执行子类中的实现,而不是父类中的实现,
这实现了运行时多态性。这意味着父类引用指向子类对象时,根据对象的实际类型来决定调用哪个方法。

1. 書き換えメソッド名と仮パラメータリストは一貫している必要があります。

サブクラスが親クラスのメソッドを書き換える必要がある場合、書き換えられたメソッド名と仮パラメータ リストが親クラスのメソッドとまったく同じであることを確認する必要があります。これは、サブクラス内のメソッド名とパラメーターの型、パラメーターの数、およびパラメーターの順序が親クラスのメソッドと同じである必要があることを意味します。これは、サブクラスが親クラスのメソッドを正しくオーバーライド (オーバーライド) できるようにして、実行時にオブジェクトの実際の型に基づいて正しいメソッドが呼び出されるようにするためです。

class Animal {
    
    
    public void makeSound() {
    
    
        System.out.println("Animal is making a sound");
    }
}

class Dog extends Animal {
    
    
    public void makeSound() {
    
    
        System.out.println("Dog is barking");
    }
}

この例では、Dog クラスは Animal クラスを拡張し、makeSound メソッドをオーバーライドします。サブクラスのメソッド名と仮パラメータのリストは、親クラスのものとまったく同じです。

例証します:

ここに画像の説明を挿入

次の問題に注意してください。

为什么Animal可以new一个Dog,而Dog不可以new一个Animal()
Animal ccc = new Dog();
ccc.makeSound();
Dog eee = new Animal();
eee.makeSound();

Java では、作成されるクラスが作成されるクラスのサブクラスである限り、クラスは別のクラスのインスタンスを作成できます。これは、サブクラスが親クラスのプロパティとメソッドを継承するため、親クラスの参照を通じてサブクラスのオブジェクトを参照できるためです。

在你的代码中,Dog是Animal的子类,所以可以使用Animal类的引用来创建一个Dog对象。
	这是因为Dog继承了Animal的属性和方法。
然而,Animal不是Dog的子类,所以不能使用Dog类的引用来创建一个Animal对象。
	这是因为Animal类可能没有Dog类特有的属性和方法。
所以,你可以使用Animal类的引用来创建一个Dog对象,
	但不能使用Dog类的引用来创建一个Animal对象。

スーパークラス参照をサブクラスに割り当てることはできません。

ここに画像の説明を挿入
Dog クラスの fetch() メソッドを呼び出す場合は、Animal 型オブジェクトを Dog 型に変換してから、fetch() メソッドを呼び出す必要があります。これはキャストを使用することで実現できます((Dog)ddd).fetch();

他のコード例:
class Animal {
    
    
    public void eat() {
    
    
        System.out.println("Animal is eating.");
    }
}

class Dog extends Animal {
    
    
    @Override
    public void eat() {
    
    
        System.out.println("Dog is eating.");
    }

    public void bark() {
    
    
        System.out.println("Dog is barking.");
    }
}

public class Mains {
    
    
    public static void main(String[] args) {
    
    
        Animal animal = new Animal();
        animal.eat(); // 输出: Animal is eating.

        Dog dog = new Dog();
        dog.eat(); // 输出: Dog is eating.
        dog.bark(); // 输出: Dog is barking.

        Animal animalDog = new Dog(); // 使用父类引用指向子类对象
        animalDog.eat(); // 输出: Dog is eating.
        // animalDog.bark(); // 错误,Animal类型的引用不能访问子类特有的方法

        ((Dog) animalDog).bark(); // 使用强制类型转换调用子类特有的方法
    }
}

Java では、スーパークラス (親クラス) 参照のサブクラス変数への直接代入がサポートされていない理由には、継承とポリモーフィズムの概念が関係しています。

Java の継承は一方向であり、サブクラスは親クラスのプロパティとメソッドを継承できますが、その逆は当てはまりません。これは、サブクラスが親クラスにはない新しいプロパティやメソッドを導入する可能性があるためです。スーパークラス参照がサブクラス変数に直接割り当てられると、サブクラス固有のプロパティやメソッドにアクセスできなくなり、タイプ セーフに違反する可能性があります。

Java におけるポリモーフィズムは、親クラス参照を通じてサブクラス オブジェクトを指すことによって実現されます。これは、実行時にさまざまなサブクラス インスタンスを動的に選択できるようにすることで、より柔軟なプログラミングを可能にするために行われます。ただし、型の互換性を考慮して、Java ではスーパークラス参照をサブクラス変数に直接割り当てることはできません。

スーパークラス参照をサブクラス型に変換する場合は、型キャストを使用できます。ただし、型変換を実行するときは、実行時の型変換例外 (ClassCastException) を回避するために、オブジェクトの実際の型に注意する必要があります。

例えば:

Superclass superClassInstance = new Subclass();
Subclass subclassInstance = (Subclass) superClassInstance; // Type Casting

superClassInstanceこれを行うには、が実際に のSubclassインスタンスであることを確認する必要があります。そうでない場合は、ClassCastException例外がスローされます。したがって、型変換を行うときは注意してください。

AnimalJava でスーパークラス (親クラス) への参照をサブクラス変数に割り当てることが許可されない理由を例を使って説明するとき、 というスーパークラスと、という名前Animalから継承するサブクラスがあると仮定しますDogどちらのクラスにもmakeSound()と呼ばれるメソッドがあります。

class Animal {
    
    
    public void makeSound() {
    
    
        System.out.println("一些通用的动物声音。");
    }
}

class Dog extends Animal {
    
    
    @Override
    public void makeSound() {
    
    
        System.out.println("汪汪!汪汪!");
    }

    public void fetch() {
    
    
        System.out.println("在找球玩耍。");
    }
}

Dogここで、オブジェクトを参照に割り当てようとしてもAnimalDogそれも .xml であるため問題ありませんAnimal

Animal animal = new Dog(); // 这是有效的,因为Dog是Animal的子类

animalただし、参照を使用してメソッドにアクセスしようとするとfetch()、コンパイル エラーが発生します。これは、animal参照はAnimal型ではありますfetch()Dogクラスに固有のメソッドであるためです。

animal.fetch(); // 错误:无法为Animal类型找到fetch()方法

このタイプの割り当てを許可しないことにより、Java では、実際のオブジェクト タイプに実際に存在するメソッドとプロパティのみにアクセスできるようになります。これは型の安全性を維持し、実行時エラーを回避するのに役立ちます。

メソッドまたは他のサブクラス固有の機能にアクセスする必要がある場合はfetch()、サブクラス型にキャストできます。ただし、実行時例外を回避するには、参照されるオブジェクトが実際に正しいサブクラス型であることを確認する必要があります。

サブクラスに固有のメソッドまたはその他の機能にアクセスするには、型キャストを使用してスーパークラス参照をサブクラス型に変換します。これにより、コンパイル時にスーパークラス参照をサブクラス参照として扱うことができ、サブクラス固有のメソッドを呼び出すことができるようになります。

Java では、スーパークラスの参照をサブクラスの型にキャストすることで型変換を実現できます。このようにして、サブクラス固有のメソッドにアクセスできます。

class Animal {
    
    
    public void makeSound() {
    
    
        System.out.println("一些通用的动物声音。");
    }
}

class Dog extends Animal {
    
    
    @Override
    public void makeSound() {
    
    
        System.out.println("汪汪!汪汪!");
    }

    public void fetch() {
    
    
        System.out.println("在找球玩耍。");
    }
}

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Animal animal = new Dog(); // 创建一个Dog对象,并用Animal引用引用它

        animal.makeSound(); // 调用的是Dog类的makeSound()方法,因为它是动态绑定的

        // 使用类型转换将Animal引用转换为Dog类型
        if (animal instanceof Dog) {
    
    
            Dog dog = (Dog) animal;
            dog.fetch(); // 现在我们可以访问Dog类特有的fetch()方法
        }
    }
}

この例では、まず、AnimalReferenceを使用してオブジェクトanimalを参照しますDog次に、 を呼び出しました。これにより、クラス内のメソッドanimal.makeSound()が呼び出されます。これは、Java が動的バインディング (動的バインディング) をサポートしており、対応するメソッドが実行時に実際のオブジェクトの型に応じて呼び出されるからです。DogmakeSound()

次に、instanceof演算子を使用して、animal参照が のDogオブジェクト型であるかどうかを確認します。そうであれば、animal参照をDog型に型キャストし、それをdog参照に割り当てます。これで、このメソッドはクラス固有のメソッドであるため、dog参照によって呼び出すことができます。fetch()Dog

型変換を実行するときは、参照が指すオブジェクトが実際にターゲットのサブクラス型であることを確認する必要があることに注意してください。そうしないと、実行時に例外がスローされますClassCastExceptioninstanceofしたがって、型変換を実行する前にチェックを使用して、型変換が安全に実行されることを確認することが最善です。

2. アクセス権は親クラス以上である必要があります。

親クラスのメソッドがサブクラスでオーバーライドされる場合、サブクラスでオーバーライドされたメソッドのアクセス修飾子は、親クラスのメソッドよりも大きくする (より寛容な) ことはできますが、親クラスのメソッドより小さく (より厳密に) することはできません。親クラス 。アクセス修飾子の順序は、プライベート < デフォルト (パッケージプライベート) < 保護 < パブリックです。たとえば、親クラスのメソッドが の場合protected、子クラスでオーバーライドされるメソッドは、デフォルトまたはプライベートである場合もprotectedあれば、そうでない場合もあります。public,これは、サブクラスが親クラスのメソッドへのアクセスを制限しないようにし、継承関係の正確さを保証するためです。

 class Animal {
    
    
    protected void eat() {
    
    
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {
    
    
    public void eat() {
    
    
        System.out.println("Dog is eating");
    }
}

この例では、Dog クラスが Animal クラスを継承し、親クラスの protected メソッドを public メソッドに変更します。サブクラス内のオーバーライドされたメソッドのアクセス権は、親クラスのメソッドのアクセス権以上です。

3. 戻り値の型は親クラス以下である必要があります。

サブクラスが親クラスのメソッドをオーバーライドする場合、サブクラスのオーバーライドされたメソッドの戻り値の型は、親クラス メソッドの戻り値の型のサブタイプ (共変) であるか、親クラス メソッドの戻り値の型とまったく同じである必要があります。これは、サブクラスのメソッドと親クラスのメソッドの型の互換性を確保し、サブクラスのオブジェクトを親クラスのオブジェクトとして使用できるようにするためです。サブクラスのオーバーライドされたメソッドの戻り値の型が親クラスのメソッドと互換性がない場合、コンパイルエラーが発生します。

class Animal {
    
    
    public Animal giveBirth() {
    
    
        return new Animal();
    }
}

class Dog extends Animal {
    
    
    public Dog giveBirth() {
    
    
        return new Dog();
    }
}

この例では、Dog クラスは Animal クラスを拡張し、giveBirth メソッドをオーバーライドします。サブクラスの戻り値の型は、親クラスのメソッドの戻り値の型のサブクラスです。

4. メソッドのシグネチャの一貫性を保ちます。

親クラスのメソッドを書き換える場合、サブクラスの書き換えメソッドは、メソッド名、パラメーターのリスト、戻り値の型など、親クラスのメソッドと可能な限り一致するようにすることをお勧めします。そうすることで、コードの可読性と保守性が向上し、理解と変更が容易になります。サブクラスのオーバーライドされたメソッドが親クラスのメソッドのメソッド シグネチャと一致しない場合、コンパイラはエラーを報告しませんが、混乱やエラーの原因となります。

class Animal {
    
    
    public void move() {
    
    
        System.out.println("Animal is moving");
    }
}

class Dog extends Animal {
    
    
    public void move(int distance) {
    
    
        System.out.println("Dog is moving " + distance + " meters");
    }
}

この例では、Dog クラスは Animal クラスから継承していますが、オーバーライドされたメソッドのシグネチャは親クラスのメソッドと矛盾しています。このようなオーバーライドは混乱やエラーを引き起こす可能性があるため、お勧めできません。

比較:

ここに画像の説明を挿入
Javaでは
ここに画像の説明を挿入
、Animal ccc = new Dog(); このコード行の意味は、新しい Dog オブジェクトを作成し、その参照を Animal 型の変数 ccc に割り当てることです。これは Java のポリモーフィズムの現れで​​す。

この場合、ccc はタイプ Animal の参照ですが、実際には Dog オブジェクトを参照しています。これは、Animal クラスで定義されたすべてのメソッドと、Dog クラスがオーバーライドする Animal クラスのメソッドを呼び出すことができることを意味します。

たとえば、 ccc.move(1); を呼び出すと、実際には、Animal クラスの move(int distance) メソッドではなく、Dog クラスの書き換えられた move(int distance) メソッドが呼び出されます。これは、Dog クラスが Animal クラスの move(int distance) メソッドをオーバーライドするためで、Animal タイプの参照を通じて move(int distance) メソッドを呼び出すと、実際には Dog クラスのバージョンを呼び出すことになります。

そのため、コード内で ((Animal) ccc).move(1); は実際には「動物が 1 メートル移動しています」ではなく、「犬が 1 メートル移動しています」を出力します。ccc は実際には Dog オブジェクトを参照するため、Dog クラスの move(int distance) メソッドを呼び出します。

5. プライベート メソッドはオーバーライドできません。

プライベート メソッドは、それが宣言されているクラス内でのみアクセスできるため、サブクラス内でアクセスすることはもちろん、オーバーライドすることもできません。プライベート メソッドも、そのメソッドを所有するクラス内でのみ表示されるため、オーバーライドできません。親クラスのプライベート メソッドと同じメソッドがサブクラスで定義されている場合、親クラスのメソッドをオーバーライドするのではなく、実際には新しいメソッドがサブクラスで作成されます。

class Animal {
    
    
    private void eat() {
    
    
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {
    
    
    public void eat() {
    
    
        System.out.println("Dog is eating");
    }
}

ここに画像の説明を挿入

この例では、Dog クラスは親クラスのプライベート メソッド Eat をオーバーライドしようとしますが、プライベート メソッドは宣言されているクラス内でのみアクセスできるため、サブクラスでアクセスしてオーバーライドすることはできません。

6. 静的メソッドはオーバーライドできません。

static修饰的方法可以被继承,但是不能被重写

静的メソッドはインスタンスではなくクラスに関連付けられているメソッドであるため、サブクラスは親クラスの静的メソッドをオーバーライドできません。ただし、サブクラスは、親クラスの静的メソッドと同じ名前を持つ独自のクラスで新しいメソッドを宣言できます。これはメソッド隠蔽と呼ばれます。メソッドの隠蔽は、親クラスの静的メソッドをオーバーライドするのではなく、サブクラスに新しい静的メソッドを作成するという点で、メソッドのオーバーライドとは異なります。

class Animal {
    
    
    public static void makeSound() {
    
    
        System.out.println("Animal is making a sound");
    }
}

class Dog extends Animal {
    
    
    public static void makeSound() {
    
    
        System.out.println("Dog is barking");
    }
}

この例では、Dog クラスは親クラスの静的メソッド makeSound をオーバーライドしようとしていますが、静的メソッドはインスタンス関連ではなくクラス関連であるため、子クラスでは使用できません。

詳細:

Java では、静的メソッドはクラスのインスタンスではなくクラスに関連付けられます。クラスで静的メソッドを定義すると、そのメソッドはクラスのインスタンスではなく、クラス自体に属します。したがって、静的メソッドは、クラスのインスタンスではなく、クラス名によって直接呼び出されます。

当子类定义了一个与父类相同名称和参数列表的静态方法时,
	实际上是在子类中创建了一个新的静态方法,而不是重写父类的静态方法。
在调用静态方法时,编译器会根据引用类型来确定要调用的方法。
	所以,无论是父类引用指向子类对象,还是子类引用指向父类对象,
调用的都是引用类型所属类的静态方法,而不是实际对象的类型。

静的メソッドはクラスに関連付けられているため、サブクラスによってオーバーライドすることはできません。サブクラスは、親クラスと同じ名前とパラメータ リストを持つ静的メソッドを定義できますが、実際には、親クラスの静的メソッドをオーバーライドするのではなく、サブクラスに新しい静的メソッドが作成されます。

クラス名で静的メソッドを呼び出す場合、コンパイラは参照型に基づいて呼び出すメソッドを決定します。親クラス参照がサブクラス オブジェクトを指しているか、サブクラス参照が親クラス オブジェクトを指しているかに関係なく、呼び出されるのは、実際のオブジェクトの型ではなく、参照型が属するクラスの静的メソッドです。

したがって、静的メソッドはクラスに関連付けられており、サブクラスによってオーバーライドできないため、Java では静的メソッドをオーバーライドできません。

7. 異常:

オーバーライドされたメソッドは、スーパークラス メソッドよりも多くの例外をスローすることはできませんが、より具体的な例外をスローすることも、例外をスローしないこともできます。これは、サブクラスのオーバーライドされたメソッドが、親クラス メソッドの例外処理と互換性のある新しい例外を導入しないようにするためです。サブクラスのオーバーライドされたメソッドがスーパークラスのメソッドよりも多くの例外をスローすると、コンパイル エラーが発生します。

class Animal {
    
    
    public void makeSound() throws IOException {
    
    
        // code that may throw IOException
    }
}

class Dog extends Animal {
    
    
    public void makeSound() throws FileNotFoundException {
    
    
        // code that may throw FileNotFoundException
    }
}

この例では、Dog クラスは Animal クラスを拡張し、makeSound メソッドをオーバーライドします。サブクラス内のオーバーライドされたメソッドは、より具体的な例外 (FileNotFoundException) をスローすることも、例外をスローしないこともできます。ただし、親クラスのメソッドより多くの例外をスローすることはできません。

8. @Override の使用:

Java では、@Overrideオーバーライドされたメソッドにアノテーションを付けることができます。このアノテーションは、コンパイラーが書き換え条件が満たされているかどうかをチェックするのに役立ち、満たされていない場合は、コンパイラーがエラーを報告します。アノテーションを使用すると、@Overrideコードの可読性と保守性が向上し、メソッドが親クラスをオーバーライドするメソッドであることが明確に示されます。

class Animal {
    
    
    public void move() {
    
    
        System.out.println("Animal is moving");
    }
}

class Dog extends Animal {
    
    
    @Override
    public void move() {
    
    
        System.out.println("Dog is running");
    }
}

この例では、Dog クラスはオーバーライドされたメソッドを @Override アノテーションでマークします。これは、コンパイラが書き換え条件が満たされているかどうかを確認するのに役立ち、満たされていない場合はエラーを報告します。@Override アノテーションを使用すると、コードの可読性と保守性が向上し、メソッドが親クラスをオーバーライドするメソッドであることが明確に示されます。

9. スーパーキーワード:

サブクラスでは、super 关键字親クラスのメソッドを呼び出すために使用できます。super キーワードを使用すると、サブクラスは親クラス メソッドを書き換えながら、親クラス メソッドの機能を拡張できます。サブクラスは、まずオーバーライドされたメソッドで親クラスのメソッドを呼び出してから、独自のロジックを追加できます。このようにして、親クラス メソッドの元の機能を保持し、これに基づいて拡張することができます。

class Animal {
    
    
    public void eat() {
    
    
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {
    
    
    public void eat() {
    
    
        super.eat(); // 调用父类的eat方法
        System.out.println("Dog is eating bones");
    }
}

この例では、Dog クラスが親クラスの Eat メソッドをオーバーライドし、super キーワードを使用して親クラスの Eat メソッドを呼び出します。このようにして、親クラス メソッドの機能をサブクラスで拡張でき、親クラス メソッドの元の機能は保持され、これに基づいて新しいロジックが追加されます。
ここに画像の説明を挿入

10. 最後の方法:

スーパークラス内のメソッドが として宣言されている場合final、そのメソッドはサブクラスによってオーバーライドできません。最終メソッドは、変更できない最終メソッドです。その実装は親クラスで最終的なものであり、サブクラスによって変更またはオーバーライドすることはできません。これは、親クラスのメソッドがサブクラスでも変更されず、変更できないようにするためです。

class Animal {
    
    
    public final void eat() {
    
    
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {
    
    
    public void eat() {
    
    
        System.out.println("Dog is eating");
    }
}

この例では、Animal クラスの Eat メソッドが Final として宣言されており、メソッドが Final であり、サブクラスによってオーバーライドできないことを示しています。したがって、ドッグクラスで食事をする

11. 目的と多態性:

メソッドをオーバーライドする主な目的は、サブクラスにサブクラス固有の実装を提供し、ポリモーフィズムと継承機能を有効にすることです。親クラスのメソッドを書き換えることにより、サブクラスはメソッド全体を書き換えることなく、独自のニーズに応じて特定の関数を実装できます。これにより、コードの再利用性と保守性が向上し、ポリモーフィズムも実現できます。つまり、親クラス参照を通じてサブクラス オブジェクトを指し、実際のオブジェクトの型に応じて対応するメソッドを呼び出すことができます。

class Animal {
    
    
    public void makeSound() {
    
    
        System.out.println("Animal is making a sound");
    }
}

class Dog extends Animal {
    
    
    public void makeSound() {
    
    
        System.out.println("Dog is barking");
    }
}

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Animal animal = new Animal();
        Animal dog = new Dog();

        animal.makeSound(); // 输出:Animal is making a sound
        dog.makeSound(); // 输出:Dog is barking
    }
}

この例では、Animal クラスと Dog クラスがそれぞれ makeSound メソッドを定義しています。ポリモーフィズムは、Animal クラスと Dog クラスのオブジェクトを作成し、それらの makeSound メソッドを呼び出すことによって実現されます。実行時には、オブジェクトの実際の型に応じて対応するメソッドが呼び出されますが、親クラスの参照を使用してサブクラスのオブジェクトを指定した場合でも、サブクラスによって書き換えられたメソッドを呼び出すことができます。

以上が書き換え方法の詳細な説明であり、それぞれのポイントは、サブクラスが親クラスのメソッドを正しく書き換えることと、ポリモーフィズムと継承を実現することです。これらのルールと考慮事項は Java では非常に重要であり、実際のプログラミングでは従う必要があります。

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

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

この例では、DogクラスはAnimalクラスを継承し、makeSound()メソッドをオーバーライドします。メソッドを呼び出すとmakeSound()、オブジェクトの場合はAnimal「動物が音を立てる」が出力され、Dogオブジェクトの場合は「犬の鳴き声」が出力されます。これは、実行時に Java がオブジェクト タイプに対応するメソッドの呼び出しを動的に選択するためです。

メソッドの書き換えを使用する場合は、メソッドの書き換えが継承関係にある親クラスのメソッドを正しくオーバーライドし、サブクラスのニーズを満たすことができるように、上記のルールに従うように注意してください。

方法重写(Override)的本质是子类提供了与父类相同签名的方法,以实现不同的功能。
	在运行时,JVM通过虚方法表(Virtual Method Table)来确定调用哪个方法,这就是动态绑定或者后期绑定。

当我们创建一个子类对象并调用一个方法时,JVM会首先在子类的虚方法表中查找该方法。
	如果找到,就执行该方法;如果没有找到,就在父类的虚方法表中查找。这就是为什么子类可以重写父类的方法的原因。

当子类重写父类的方法时,子类的虚方法表中的对应条目会被更新为指向子类的方法,而不是父类的方法。
	这就是所谓的“覆盖虚方法表中的方法”。

サブクラスコンストラクター:

Java では、通常、サブクラスのコンストラクターは親クラスのコンストラクターを呼び出して、親クラスのすべてのフィールドが適切に初期化されていることを確認します。これは、super キーワードを使用して実現されます。以下に例を示します。

public class Animal {
    
    
    private String name;

    public Animal(String name) {
    
    
        this.name = name;
    }
}

public class Dog extends Animal {
    
    
    private String breed;

    public Dog(String name, String breed) {
    
    
        super(name);  // 调用父类的构造器
        this.breed = breed;
    }
}

この例では、Dog クラスは Animal クラスのサブクラスです。Dog クラスのコンストラクターは、最初に super(name) を呼び出して親クラス Animal のコンストラクターを呼び出し、次に独自の品種フィールドを初期化します。

Javaでは継承により継承構造を持つJavaBeanを作成できます。

你的要求是创建一个JavaBean,它需要满足以下条件:

1. 类名见名知意
2. 所有的成员变量都需要私有
3. 构造方法(空参和带全部参数的构造)
4. get/set方法

まず、PERSON という名前の基本 JavaBean を作成します。

public class Person {
    
    
    private String name;
    private int age;

    public Person() {
    
    
    }

    public Person(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }
}

次に、Person を継承する Student クラスを作成します。

public class Student extends Person {
    
    
    private String school;

    public Student() {
    
    
    }

    public Student(String name, int age, String school) {
    
    
        super(name, age);
        this.school = school;
    }

    public String getSchool() {
    
    
        return school;
    }

    public void setSchool(String school) {
    
    
        this.school = school;
    }
}

この例では、Student クラスが Person クラスのプロパティとメソッドを継承し、独自のプロパティ school を追加します。以上が継承構造を持つ JavaBean の作成方法です。

おすすめ

転載: blog.csdn.net/m0_74154295/article/details/132049321