web-dev-qa-db-ja.com

メソッドをオーバーロードする必要があるのはなぜですか?

オーバーロードメソッドの本で2つの例を見つけましたが、なぜそれが役立つのかを明確に説明していません。

package keepo;
public class Main{
    public static void main(String [] args)
    {
        int newScore = calculateScore("Tim", 500);
        System.out.println("New Score is" + newScore);
        calculateScore(75);

    }
    public static int calculateScore(String playerName, int score){
        System.out.println("Player" + playerName +"Has score" + score);
        return score * 1000;
    }
    public static int calculateScore(int score){
        System.out.println("Unnamed player scored" + score + "points");
        return score * 1000;
    }
}

これは非常に簡単ですが、正直なところ、ここでメソッドのオーバーロードを行うのはかなり役に立たないようです。

本の次の例では、メソッドのオーバーロードを行っています。これは、プログラムがフィートからセンチメートルを計算し、フィートとインチを入力できる方法と、インチを入力できる方法があるため、少し便利です。ただし、これを行うために2つの個別のメソッドを作成するのは同じくらい簡単に思えます。

とはいえ、これを行うことには実際にメリットがありますか? (私は this を読みましたが、本当に満足していません。新しいメソッドを作成するのも同じくらい簡単に思えます。)

36
Muntasir Alam

関数/メソッドのオーバーロードの本当の利点について話せば、それがないと回避できません。質問で指摘したように、何も見つかりません。

しかし、それはどのように役立ちますか?この例を考えてみましょう。

名前で人を検索するアプリケーションを作成していて、メソッドを宣言して定義するとします

public Person[] findPerson(String name)

今、私たちは彼の生年月日によって人を見つける必要があるという要件を取得しているので、新しい方法を導入します

public Person[] findPerson_byDOB(Date date)

これが継続していて、アプリケーションにこれほど多くのメソッドがあるとします。

public Person[] findPerson(String name)
public Person[] findPerson_byDOB(Date date)
public Person[] findPerson_byAddress(Address address)
public Person[] findPerson_bySSN(SSN ssn)
public Person[] findPerson_byDepartment(Department department)
public Person[] findPerson_byMobile(Mobile mobile)

それはほんの一部です。これは、次のような複数のパラメータを導入するように求められたときにも実行できます

public Person[] findPerson_byMobileAndAddress(Mobile mobile, Address address)
public Person[] findPerson_byAddressAndDepartment(Address address, Department department)
public Person[] findPerson_byDOBAndDepartment(DOB dob, Department, department)
public Person[] findPerson_byAddressAndDOB(Address address, DOB dob)

その他多数...

これは少し誇張されているように思えるかもしれませんが、実際の業界レベルのアプリケーションを作成するときに、このような数百の方法が得られる状況に遭遇する可能性があり、最終的にこれらすべての方法のカタログが必要になります彼らが実際に行うこと。

それを使用しなければならないときにこれらすべてのメソッドの名前を見つける必要がある場合、それは実際には悪夢です。

ただし、すべてのパラメーターが異なる場合、関数に同じ名前を付けることができ、覚えるのが非常に簡単になります。

public Person[] findPerson(String name)
public Person[] findPerson(Date date)
public Person[] findPerson(Address address)
public Person[] findPerson(SSN ssn)
public Person[] findPerson(Department department)
public Person[] findPerson(Mobile mobile)
public Person[] findPerson(Mobile mobile, Address address)
public Person[] findPerson(Address address, Department department)
public Person[] findPerson(DOB dob, Department, department)
public Person[] findPerson(Address address, DOB dob)

Davidが 彼の回答 で指摘したように、整数のString値を取得する方法は誰でも知っています。おそらくどこかで読んだことでしょう。

static String.valueOf(new Integer(1));

しかし、同じ名前でオーバーロードされているメソッドがいくつあるか知っていますか?

static String.valueOf(boolean b)
static String.valueOf(char c)
static String.valueOf(char[] data)
static String.valueOf(double d)
static String.valueOf(float f)
static String.valueOf(int i)
static String.valueOf(long l)
static String.valueOf(Object obj)

利点は、それらすべてを記憶する必要がないことです。それはずっと同じ名前なので、あなたは推測する必要さえありません。


[〜#〜]編集[〜#〜]ナムノドレルのアドバイスに従って

このPrintStreamクラスのオーバーロードされたメソッドを検討してください。

void println()
void println(boolean x)
void println(char x)
void println(char[] x)
void println(double x)
void println(float x)
void println(int x)
void println(long x)
void println(Object x)
void println(String x)

書く必要がある場合は、読みやすさについて考えてください。

void println_emptyLine()
void println_boolean(boolean x)
void println_character(char x)
void println_characterArray(char[] x)
void println_double(double x)
void println_float(float x)
void println_integer(int x)
void println_long(long x)
void println_object(Object x)
void println_string(String x)
62
Raman Sahasi

オーバーロードは、異なる型の値で同じことを行うメソッドを作成するときに役立ちます。

Math クラスは完全な例を提供します-タイプごとの関数オーバーロードのグループがあります-4つのabs、4つのmin、4つのmax、 等々:

_int max(int a, int b) {...}
float max(float a, float b) {...}
long max(long a, long b) {...}
double max(double a, double b) {...}
_

オーバーロードのない代替案では、型をメソッドの名前に「エンコード」する必要があります。 Math.intMax(a, b)これは、ユーザーのコードの可読性に悪影響を及ぼします。

22
dasblinkenlight

シンプルかつ簡潔にするために:オーバーロードは、Java (しかし、現代の柔軟な言語のほとんどはそれを使用しています) (およびC++やC#などの他の言語)を使用すると、開発者は同じメソッド/関数名をいくつか作成できます。

どうして ?
メソッドの命名は重要であり、メソッドの命名はその動作を伝える必要があるためです。したがって、2つのメソッドの動作が同じ(たとえば、文字列に変換する)の場合、一方がlongを入力として使用し、もう一方がintを入力として使用する場合、メソッド名が異なるのはなぜですか?

    String myString = String.valueOf(new Integer(1));
    String myOtherString = String.valueOf(new Long(2));


意図と目標は同じで、入力パラメータが変更されるだけです。

オーバーロードに意味がある場合は、バリアントの不格好な名前を作成する代わりに、オーバーロードを使用する必要があります。

2
davidxxx

私はオブジェクトであり、機能があります。機能は固定されていますが、さまざまなパラメーターを受け入れることができます。

機能が1000種類のパラメーターを受け入れることができる場合、1000の機能名について考える必要がありますか?

他の投稿をオーバーロードの良い習慣として取り、JNIEnvが悪い習慣として行うことをCがオーバーロードをサポートしない原因とする。

CallStaticObjectMethod,
CallStaticObjectMethodV,
CallStaticObjectMethodA,
CallStaticBooleanMethod,
CallStaticBooleanMethodV,
CallStaticBooleanMethodA,
CallStaticByteMethod,
CallStaticByteMethodV,
CallStaticByteMethodA,
CallStaticCharMethod,
CallStaticCharMethodV,
CallStaticCharMethodA,
CallStaticShortMethod,
CallStaticShortMethodV,
CallStaticShortMethodA,
CallStaticIntMethod,
CallStaticIntMethodV,
CallStaticIntMethodA,
CallStaticLongMethod,
CallStaticLongMethodV,
CallStaticLongMethodA,
CallStaticFloatMethod,
CallStaticFloatMethodV,
CallStaticFloatMethodA,
CallStaticDoubleMethod,
CallStaticDoubleMethodV,
CallStaticDoubleMethodA,
CallStaticVoidMethod,
CallStaticVoidMethodV,
CallStaticVoidMethodA,

より詳細な構造体定義については、 [〜#〜] jni [〜#〜] に変更してください

1
Eugene

オーバーロードするもう1つの理由は、1つ以上のデフォルト引数を提供することです。

以下を検討してください。

_class Something {
    // Imagine that this is a real class, that does real work.

    public void doSomething(boolean b, char c, double d, int i) {
        // Imagine that this is one of the main components of class Something.
        System.out.println("Hi. You passed: " + b + ", " + c + ", " + d + ", and " + i + ".");
    }

    public void doSomething(boolean b, char c, double d) {
        doSomething(b, c, d, 42);
    }

    public void doSomething(boolean b, char c) {
        doSomething(b, c, 1.3579);
    }

    public void doSomething(boolean b) {
        doSomething(b, 'q');
    }

    public void doSomething() {
        doSomething(true);
    }
}
_

この例では、各オーバーロードがパラメーターの1つにデフォルトを提供し、実際に機能するバージョンのdoSomething()への完全な呼び出しを取得するまでパラメーターをチェーンします。

_Something s = new Something();
Something t = new Something();
Something u = new Something();

// ...

s.doSomething(true, 'c', 2.9);
t.doSomething(false, 'z');
u.doSomething();
_

例については here を参照してください。

メソッドのオーバーロードは、次のシナリオで役立ちます。

名前のリストを追跡するクラスがあるとします。上記のコードのスタイルがあり、各メソッドはこの名前のリストで操作を実行する独自の方法を持っています。

突然、リストの内部表現が変化します(多分arrayからArrayListへ、それは本当に重要ではありません)。 everyのリファクタリングを担当しますか? 単一。方法?

メソッドのオーバーロードは、単一の汎用メソッドを介してすべての操作をルーティングできるので便利です。つまり、内部表現が変更されても、そのジェネリックメソッドを変更するだけで、他のすべての専用メソッドは同じように機能します。


また、提供された例を検討してください。プログラムがメッセージを出力する方法を変更したい場合はどうなりますか?同じタイプのメッセージを出力するには、両方のメソッドを変更する必要があります。それは、メンテナンスの悪夢です。確かに、今は小さいように見えますが、プロジェクトが大きくなると、この(効果的に修正された)メッセージ形式に依存するメソッドがさらに増えるようになります。

1
Jeeter