当通过更改参数列表中的参数序列来实现Java中的方法重载时有什么用?

时间:2011-01-07 04:05:04

标签: java overloading

我正在阅读Java培训手册,它说可以通过使用不同的参数列表来实现Java中的方法重载。它还说参数列表可能有所不同

(i)中。参数数量

(ii)中。参数的数据类型

(III)。参数序列

我关注的是(iii)。

仅通过更改参数序列来尝试重载方法有什么用?我无法通过这种方式想到任何好处。

8 个答案:

答案 0 :(得分:4)

(iii)只是(ii)的一个特例。

“int,long,String”和“String,int,long”是(ii)=不同的数据类型,但恰好是同一组类型。

但是,混杂的重载会导致令人困惑的代码。

答案 1 :(得分:3)

如果您的意图仅仅是参数序列,方法重载是无用的,因为恕我直言,您只是鼓励样板代码(重复相同的代码),如果参数都是相同的数据类型,您将收到编译错误因为方法签名不明确。

当参数可以作为多种数据类型存在时,为方便起见,我在API中执行了很多方法重载:

public class Client {

   public Status get(String request) {
      return get(new Request(request));
   }

   public Status get(Request request) {
      // do stuff
   }

}

如果您有很多参数,并且其中许多是可选的,我建议您查看Builder pattern。构建器模式的目的是创建由可选参数构造的不可变对象。例如:

public String get(String arg0, String arg1, String arg2) {
   // do stuff
}

public String get(String arg0, String arg1) {
   return method(arg0, arg1, null);
}

public String method(String arg0) {
   return method(arg0, null, null);
}

可能可以通过构建器进行改进:

class Request {

    final String arg0;
    final String arg1;
    final String arg2;

    private Request(Builder b) {
        this.arg0 = b.arg0;
        this.arg1 = b.arg1;
        this.arg2 = b.arg2;
    }

    // getter methods

    public static class Builder {
        String arg0, arg1, arg2;

        public Builder arg0(String arg) {
            this.arg0 = arg;
            return this;
        }

        public Builder arg1(String arg) {
            this.arg1 = arg;
            return this;
        }

        public Builder arg2(String arg) {
            this.arg2 = arg;
            return this;
        }

        public Request build() {
            return new Request(this);
        }

    }

}

class Client {
    public String get(Request request) { }
}

new Client().get(Request.Builder().arg0("arg0").arg1("arg1").arg2("arg2").build());

我做的另一个重载是当一个方法可以接受不同数据类型的参数时:

public String lookup(String variant) {
   return lookup(Integer.parseInt(variant));
}

public String lookup(int ordinal) {
   // logic
}

答案 2 :(得分:3)

啊!说得通!我在思考 -

public String buildUrl(String protocol, String host, int port){
    return protocol + "://" + host + ":" + port;
}

public String buildUrl(String protocol, int port, String host){
    return protocol + "://" + host + ":" + port;
}

所以,我认为这没用。但可能会出现这样的情况(需要很长时间才能提出来:-)) -

public int countTotalTruckWheels(boolean hasSpare, int numberOfTrucks){
    if(hasSpare){
        return (numberOfTrucks+1)*4;
    } else{
        return numberOfTrucks*4;
    }
}

public int countTotalTruckWheels(int numberOfAxlesInTruck, boolean strongAxle){
    if(strongAxle){
        //each axle can hold 4 wheels
        return numberOfAxlesInTruck*4;
    } else {
        return numberOfAxlesInTruck*2;
    }
}

这里参数的数据类型不只是重新排序,而是参数的整个含义已经改变。

我基于上面的许多答案理解这一点。我无法选择一个特定的答案。另外,我想将此添加为评论,但它太大而无法发表评论。因此在这里添加了它。

答案 3 :(得分:1)

  

它还说,参数列表可能有所不同   (三)。参数序列

(iii)完全错了。您无法通过简单地更改参数的顺序来更改过载。举个例子:

int add(int x, int y)
int add(int y, int x)

这不是合法的超载。现在考虑这个例子:

int fill(int number, char c)
int fill(char c, int number)

请记住,参数名称并不重要,所以实际上它对编译器来说是这样的:

int pad(int, char)
int pad(char, int)

这是有效的重载,但不是,因为您更改了参数的顺序,而是因为一个或多个参数的类型已更改。这两种方法不同,因为第一个参数的类型在方法之间是不同的(就像第二个参数的类型一样)。


  

仅通过更改参数序列来尝试重载方法有什么用?

没有用。文本 NOT 表示你“应该”通过改变参数序列来进行方法重载,文本只是说它可能(只要重新排序创建一个唯一的参数签名)。这只是重载如何工作的结果(副作用) - 我确信这是语言设计者试图支持的用例。换句话说:

  

仅仅因为你可以这样做,并不意味着你应该

答案 4 :(得分:0)

进行这种超载的原因并不多,但我能想到一对。

您的API会公开,并且您的所有方法签名都是相同的,但是一个相当常见(但未被发现)的方法。假设它们都是myFunct(String,int),其中一个碰巧是myFunct(int,String)。您将希望保留该函数以实现向后兼容性,但您也可能会使一个类也具有myFunct(String,int)以保持其一致。

另一个原因(即使它是一个糟糕的原因)是你可能让人们习惯于一个订单,也许是来自不同的图书馆,或者他们可能只是阅读障碍...但你可能会把它重载为交换参数如果方便的话。显然,这可能很棘手,因为如果你有(String,int,int)你可能不想做(int,int,String)或(int,String,int)。最好只保留一个。

答案 5 :(得分:0)

这似乎有点无意义,在很多情况下,我可以看到为什么有些人可能只是简单地改变参数序列,只是为了支持重载,实际上它们只是设计不良的代码。但是,它在某些情况下是完全合理的。

大多数程序员会根据这样的概念选择某些参数序列,即这些参数在特定顺序中更有意义,或者因为顺序实际上对某些计算的结果具有根本重要性。以这些重载方法为例:

int raise(int i, String n);
int raise(String i, int n);

正如你在数学课上很早就学到的那样,将一个值提高到另一个值是一个非交换操作(即2 ^ 3!= 3 ^ 2)。

所以在这个例子中,每个方法都会引发一些数值。第一个参数始终是由作为第二个参数给出的值引发的值(顺序很重要)。但是,如您所见,参数列表的每个参数可以用String或int类型表示。然而,操作的语义保持不变。

raise("12", 2);
raise(12, "2");

当然,出于显而易见的原因,这是一个非常人为的例子,但你可以看到它原则上是合理的。

我敢肯定,如果我能提供一些更好的例子,我可以想出一个更好的例子,其中参数属于某种特殊类型,这种情况更有意义。

答案 6 :(得分:0)

你是对的,iii通常没有强有力的案例。通常,有必要保持强类型,如下所示

void save(String key, int value);
void save(String key, float value);
void save(String key, byte value);

答案 7 :(得分:0)

参数列表由参数的数量和类型决定。因此,如果您的参数具有不同的类型,则重新排序参数会产生不同的重载,因为编译器会在不同的插槽中看到不同的类型。

f(int a, String b)

f(String b, int a)

两个函数都有两个参数,但类型不匹配,因此它们是有效的重载。

至于为什么你可能想要这样做,通常情况是参数的顺序很重要。在代码库中我维护我们有可能有原因,消息和其他参数的异常。所以以下两个调用不一样:

Exception cause;
String msgFormat = "An error occurred while processing {0}";
String recordName = "abc123";

throw new ABCException(cause, message, recordName);

throw new ABCException(message, cause, recordName);

throw new ABCException(message, recordName);

throw new ABCException(recordName, message);

在第一种情况下,cause是异常的原因,message是要显示的消息,record是消息的参数。在第二种情况下,causerecordName都被解释为消息的参数。在第三种情况下没有原因,在第四种情况下没有原因,而message参数处于错误的位置,将无法正确处理。

这是通过ABCException构造函数的几个有用的重载来实现的(尽管在这种情况下我们使用varargs来支持无限数量的参数)。