我正在阅读Java培训手册,它说可以通过使用不同的参数列表来实现Java中的方法重载。它还说参数列表可能有所不同
(i)中。参数数量
(ii)中。参数的数据类型
(III)。参数序列
我关注的是(iii)。
仅通过更改参数序列来尝试重载方法有什么用?我无法通过这种方式想到任何好处。
答案 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
是消息的参数。在第二种情况下,cause
和recordName
都被解释为消息的参数。在第三种情况下没有原因,在第四种情况下没有原因,而message
参数处于错误的位置,将无法正确处理。
这是通过ABCException构造函数的几个有用的重载来实现的(尽管在这种情况下我们使用varargs来支持无限数量的参数)。