banner
lMingyul

lMingyul

记录穿过自己的万物
jike

重载(overloading)和重写(overriding)是面向对象编程中的两个重要概念。 重载是指在同一个类中,可以定义多个同名的方法,但这些方法的参数类型或个数必须不同。通过重载,可以根据不同的参数类型或个数来调用不同的方法,提高代码的灵活性和复用性。 重写是指子类重新定义父类中已有的方法。子类可以根据自己的需求,重新实现父类中的方法,以改变方法的行为。通过重写,可以实现多态性,即同一个方法在不同的对象上具有不同的行为。 在使用重载和重写时,需要注意方法的签名(即方法名和参数列表)必须一致,否则会导致编译错误。 重载和重写是面向对象编程中的重要特性,能够提高代码的灵活性和可扩展性。在实际开发中,根据具体的需求选择合适的方式来使用重载和重写,可以使代码更加清晰和易于维护。

Java の学習ノートを記録しておきます。

重载#

重载:オーバーロードは、メソッドのオーバーロードを指し、オーバーロードの特徴は、2 つ以上のメソッドが同じ名前を持つことです。

クラシックなオーバーロードメソッド#

オーバーロードは主にコンストラクタメソッドで使用されます。なぜなら、コンストラクタの役割はオブジェクトの構築を初期化することであり、コンストラクタの名前はクラス名と同じでなければならないため、これがクラシックな引数なしコンストラクタと引数付きコンストラクタのオーバーロードメソッドのペアを形成します。

以下に例を示します:

/**
 * 作者:mingyu
 */
public class User {

    private Integer id;

    private String userName;
		
  	// 引数なしコンストラクタ
    public User() {
    }
		
  	// 単一の引数を持つコンストラクタ
    public User(Integer id) {
        this.id = id;
    }

  	// 全引数を持つコンストラクタ
    public User(Integer id, String userName) {
        this.id = id;
        this.userName = userName;
    }

}

なぜオーバーロードが必要なのか#

私たちは皆、Java で最も重要な概念である「オブジェクト」を知っています。メソッドはオブジェクトの行動です。同じ名前の行動をするオブジェクトは、異なることをしているかもしれません。例えば、小明が麻雀を打っているとします。

文字通りの意味:小明は他の人と一緒に麻雀をするという娯楽活動をしています。

他の意味:小明は「麻雀」という名前の人を「打つ」ことをしています。

したがって、現実の生活の言語の曖昧さはコードでも発生する可能性があります。

また、人が何かを食べている場合、私が彼に何かを与えると、彼はそれを食べます。私が彼に麺を与えると、彼の行動は麺を食べることです。私が彼にご飯を与えると、彼の行動はご飯を食べることですが、彼の行動はすべて「食べる」と呼ばれます。

まとめると、オーバーロードはコードで非常に必要です。

オーバーロードの区別#

同じ名前の異なるメソッドをどのように区別しますか?

オーバーロードを区別するための重要な原則:各オーバーロードメソッドには一意のパラメータタイプリストが必要です(つまり、各メソッドには他の同名のメソッドと異なる引数があります)

では、どのような点が異なるのでしょうか?

パラメータタイプの違い#

public class Test {

    public static void main(String[] args) {
      	// ageの型が異なるため、同じ名前の2つのメソッドを区別できます
        getPerson("mingyu", 18);
        getPerson("mingyu", "18");
    }

    static void getPerson(String name, int age) {
        System.out.println("name: " + name + ", " + "int_age: " + age);
    }

    static void getPerson(String name, String age) {
        System.out.println("name: " + name + ", " + "String_age: " + age);
    }

}

出力結果:

name: mingyu, int_age: 18
name: mingyu, String_age: 18

パラメータの順序の違い#

パラメータの順序が異なる場合、同じ名前のオーバーロードメソッドを区別することはできますが、このような方法で区別することはお勧めしません。なぜなら、このようなコードを書くと、メンテナンスが困難になるからです。

public class Test {

    public static void main(String[] args) {
        getPerson("mingyu", 18);
        getPerson(18,"mingyu");
    }

    static void getPerson(String name, int age) {
        System.out.println("name: " + name + ", " + "behind_age: " + age);
    }

    static void getPerson(int age, String name) {
        System.out.println("name: " + name + ", " + "first_age: " + age);
    }

}

出力結果:

name: mingyu, behind_age: 18
name: mingyu, first_age: 18

戻り値でオーバーロードメソッドを区別する#

パラメータリストの型、順序だけでなく、戻り値でオーバーロードメソッドを区別することはできますか?

答えはできません、以下に例を示します。

 void f() {}
    
 int f() { return 1; }

f() メソッドを呼び出す必要があり、メソッドの戻り値は必要ない場合(System.out.println メソッドなど)、Java はどのメソッドを呼び出す必要があるかを区別することができません。

基本型のオーバーロード#

基本型のみが異なるオーバーロードメソッドの場合、基本型は小さい型から大きい型に自動的に昇格する場合があります。

public class Test {

    public static void main(String[] args) {
        int x = 5;
        checkBasicTypes(x);
    }

    static void checkBasicTypes(long x) {
        System.out.println("Type long: " + x);
    }

    static void checkBasicTypes(float x) {
        System.out.println("Type float: " + x);
    }

    static void checkBasicTypes(double x) {
        System.out.println("Type double: " + x);
    }

}

出力結果:

Type long: 5

変数 x は int 型ですが、checkBasicTypes() メソッドには int 型の引数がありません。プログラムが実行されると、int 型よりも大きい型のメソッドを呼び出すため、渡されるデータ型は自動的に昇格されます。( int -> long)

重写#

オーバーライドは通常、親子クラスの関係で発生し、親クラスと子クラスの間には名前とパラメータリストの両方が同じメソッドが 2 つあります。同じメソッド名を持つため、メソッド呼び出し時には子クラスのメソッドが親クラスの同名メソッドを上書きします。

以下はオーバーライドの例です。

public class Test {

    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.say();
    }
}

class Animal {
    public void say() {
        System.out.println("I'm animal.");
    }
}

class Dog extends Animal {

    @Override
    public void say() {
        System.out.println("I'm Dog.");
    }

    public void eat() {
        System.out.println("Dog like eat meat.");
    }
}

出力結果:

I'm Dog.

上記の例では、親クラスと子クラスの両方で say() メソッドが定義されていますが、実際には子クラスが親クラスの say() メソッドをオーバーライドしています。

オーバーライドされたメソッドでは、子クラスのオブジェクトの型が Animal であっても、Java は依然として Dog の say() メソッドを呼び出します。なぜなら、子クラスのメソッドは同名の親クラスのメソッドを上書きするからです。

オーバーライドの原則#

メソッドをオーバーライドする場合、リスコフの置換原則を満たす必要があります。

  • サブクラスのメソッドのアクセス権限は、スーパークラスのメソッドのアクセス権限以上でなければなりません。
    • 例:スーパークラスのメソッドの修飾子が protected の場合、サブクラスのメソッドの修飾子は protected または public でなければなりません。
  • サブクラスのメソッドの戻り値の型は、スーパークラスのメソッドの戻り値の型と同じか、そのサブタイプでなければなりません。
    • 例:B extends A の場合、スーパーメソッドの戻り値の型が A の場合、サブクラスのメソッドは A 型または B 型を返すことができます。
  • サブクラスのメソッドがスローする例外の型は、スーパークラスがスローする例外の型と同じか、そのサブタイプでなければなりません。

@Override アノテーション#

@Override アノテーションは Java のキーワードではありませんが、キーワードと同じように使用できます。このアノテーションをオーバーライドメソッドに追加すると、コンパイラが上記の 3 つの制限条件をチェックし、オーバーライドメソッドが有効かどうかを確認してくれます。時には、意図しないオーバーロードを防ぐのにも役立ちます。

参考資料#

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。