为什么我应该重载方法?

Why should I ever overload methods?

我在我的重载方法一书中找到了两个例子,但它并没有清楚地解释它为什么有用:

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;
    }
}

这很简单,但老实说,在这里重载方法似乎没什么用,而且似乎只是为了做而做。

书中的下一个示例进行了方法重载,这似乎更有用,因为该程序将英尺计算为厘米,并且有一种方法可以输入英尺和英寸,还有一种方法可以输入英寸。但是,为此创建两个单独的方法似乎仍然很容易。

话虽这么说,这样做有什么真正的好处吗? (我看过this,但我不是很满意。似乎制作新方法也很容易。)

方法重载在以下场景中很有用:

假设您有一个 class 来跟踪姓名列表。你有上面的代码风格,其中每个方法都有自己对这个名称列表执行操作的看法。

突然,列表的内部表示发生了变化(可能从 array 变为 ArrayList,这并不重要)。你想成为负责重构 every 的人吗? 单身。方法?

方法重载很有用,因为这样您就可以通过单个通用方法路由所有操作。这意味着每当内部表示发生变化时,您只需更改该通用方法,所有其他专用方法仍然有效。


另外,请考虑您提供的示例。如果您想更改程序打印消息的方式会怎样?您必须修改这两种方法才能打印相同类型的消息,这是维护的噩梦。当然,它现在看起来很小,但是想想当你的项目增长时,你开始有更多依赖这种(有效固定的)消息格式的方法。

当您使用不同类型的值执行相同操作的方法时,重载很有用。

Math class 提供了一个完美的例子——它有按类型划分的函数重载组——四个 abs、四个 min、四个 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) {...}

没有重载的替代方案会强制您将类型 "encode" 放入您的方法名称中,例如Math.intMax(a, b) 这将不利于用户代码的可读性。

我是一个对象,我有一个能力,这个能力是固定的,但可以接受各种参数。

如果capability可以接受1000种参数,你要绞尽脑汁想1000个capability名字吗?

将其他 post 视为重载的良好做法,将 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 以获得更详细的结构定义

简明扼要: 重载只是 Java 提供的一种可能性(但大多数现代和灵活的语言都使用它)(以及其他语言,如 C++ 或 C#)允许开发人员创建一个相同的 method/function 名称,其中有几个。

为什么?
因为方法命名很重要,方法命名应该传达它的行为。 因此,如果两个方法具有相同的行为(例如转换为字符串) 但是比一个使用 long 作为输入而另一个使用 int 作为输入,为什么有不同的方法名称?

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


目的和目的是一样的,只是输入参数变了。

当重载有意义时​​,您应该使用它而不是创建一些变体笨拙的名称。

我想如果你谈论 function/method 重载的真正好处,没有它你将无法解决问题,那么正如你在问题中指出的那样,你将找不到任何。

但这有什么用呢?让我们考虑这个例子。

假设我正在制作一个应用程序,通过他的名字找到一个人,我声明并定义了一个方法

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)

好处是您不必将它们全部记住。你甚至不必猜测,因为它一直都是同一个名字。


编辑 按照 Namnodorel 的建议

考虑 PrintStream class.

的重载方法
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)

重载的另一个原因是提供一个或多个默认参数。

考虑以下几点:

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);
    }
}

在此示例中,每个重载都为其中一个参数提供默认值,将它们链接在一起,直到您完全调用实际完成工作的 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