C# 和 Java 中的方法重载
Method overloading in C# and Java
我运行 C#中的以下方法。
public float Add(float num1, long num2)
{
Console.WriteLine("method 1");
return 0;
}
public float Add(int num1, float num2)
{
Console.WriteLine("method 2");
return 0;
}
在这里,如果我调用Add(1,1)
,它会产生歧义。
现在让我交换第一种方法中 float
和 long
的位置,如下所示:
public float Add(long num1, float num2)
{
Console.WriteLine("method 1");
return 0;
}
public float Add(int num1, float num2)
{
Console.WriteLine("method 2");
return 0;
}
现在它打印 "method 2" 作为输出。第一种情况的歧义背后的原因是什么?
如果我在代码中编写以下两个方法:
public float Add(long num1, long num2)
{
Console.WriteLine("method 1");
return 0;
}
public float Add(int num1, float num2)
{
Console.WriteLine("method 2");
return 0;
}
调用Add(1,1)
时,出现歧义错误。为什么它不进行最佳匹配,这是第二种方法(具有 int
和 float
)?根据我的说法,它应该将方法 2 作为输出。
在这种情况下,编译器会寻找与输入变量最匹配的方法
public float Add(float num1, long num2)
{
Console.WriteLine("method 1");
return 0;
}
public float Add(int num1, float num2)
{
Console.WriteLine("method 2");
return 0;
}
Add(1,1)这个方法不清楚应该选择哪个版本,所以为了解决这个问题(第一个参数是float或int,第二个参数是long或float)你必须指定类型方法中的输入参数
Add(1F, 1);
Add(1, 1F);
但是下面的代码,编译器将 int 类型视为第一个方法参数中数字 1 的最接近匹配
public float Add(long num1, float num2)
{
Console.WriteLine("method 1");
return 0;
}
public float Add(int num1, float num2)
{
Console.WriteLine("method 2");
return 0;
}
所以如果你想调用第一个方法你应该这样做
Add(1L, 1);
第三部分代码
public float Add(long num1, long num2)
{
Console.WriteLine("method 1");
return 0;
}
public float Add(int num1, float num2)
{
Console.WriteLine("method 2");
return 0;
}
同样不清楚编译器应该使用哪个版本,因为你的方法中有第二个输入参数(float 或 long),所以为了解决这个问题你必须指定输入
Add(1L, 1);//method 1
Add(1, 1F);// method 2
来自C# specification,7.5.3.2 Better Function成员:
Given an argument list A with a set of argument expressions { E1, E2, ..., EN } and two applicable function members MP and MQ with parameter types { P1, P2, ..., PN } and { Q1, Q2, ..., QN }, MP is defined to be a better function member than MQ if
- for each argument, the implicit conversion from EX to QX is not better than the implicit conversion from EX to PX, and
- for at least one argument, the conversion from EX to PX is better than the conversion from EX to QX.
请注意,规范使用术语 隐式转换 的方式包括身份转换。请参阅 6.1 隐式转换:
The following conversions are classified as implicit conversions:
- Identity conversions
- Implicit numeric conversions
- [...]
从6.1.1 身份转换:
An identity conversion converts from any type to the same type. [...]
您的参数类型集是:
{ int, int }
第一种情况,候选人是:
{ float, long }
{ int, float }
设MP为第一候选,MQ为第二候选
- 有一个参数 X (= 1),其中从 EX 到 QX 的隐式转换 优于从 EX 到 PX 的隐式转换:
int
到 int
比 int
到 float
好(因为是同一类型)。
设MP为第二候选,MQ为第一候选
- 有一个参数 X (= 2),其中从 EX 到 QX 的隐式转换 优于从 EX 到 PX 的隐式转换:
int
到 long
优于 int
至 float
.
两位候选人都不符合第一个要点。规范中描述的打破平局的机制在这里不适用(因为这两种方法都不是通用的,也不是可变的,也没有可选参数,等等)。因此,这个调用是不明确的。
第二种情况,候选人是:
{ long, float }
{ int, float }
设MP为第一候选,MQ为第二候选
- 有一个参数 X (= 1),其中从 EX 到 QX 的隐式转换 优于从 EX 到 PX 的隐式转换:
int
到 int
比 int
到 long
好(因为类型相同)。
设MP为第二候选,MQ为第一候选
- 没有参数 X,其中从 EX 到 QX 的隐式转换优于从 EX 到 PX 的隐式转换。
- 有一个参数 X (= 1),其中从 EX 到 PX 的隐式转换 优于从 EX 到 QX 的转换:
int
到 int
优于 int
至 long
.
由于第二个候选人同时满足两个要点,因此比第一个更匹配。
第三种情况,候选人是:
{ long, long }
{ int, float }
就像第一种情况:
int
到 int
优于 int
到 long
.
- 但是
int
到 long
比 int
到 float
好。
这样调用又是模棱两可的。
Java Language Specification 在 15.12.2.5 选择最具体的方法 中指出:
One applicable method m1 is more specific than another applicable method m2, for an invocation with argument expressions e1, ..., ek, if any of the following are true:
- m2 is generic, and m1 is inferred to be more specific than m2 for argument expressions e1, ..., ek by §18.5.4.
- m2 is not generic, and m1 and m2 are applicable by strict or loose invocation, and where m1 has formal parameter types S1, ..., Sn and m2 has formal parameter types T1, ..., Tn, the type Si is more specific than Ti for argument ei for all i (1 ≤ i ≤ n, n = k).
- m2 is not generic, and m1 and m2 are applicable by variable arity invocation, and where the first k variable arity parameter types of m1 are S1, ..., Sk and the first k variable arity parameter types of m2 are T1, ..., Tk, the type Si is more specific than Ti for argument ei for all i (1 ≤i≤k). Additionally, if m2 has k+1 parameters, then the k+1'th variable arity parameter type of m1 is a subtype of the k+1'th variable arity parameter type of m2.
The above conditions are the only circumstances under which one method may be more specific than another.
A type S is more specific than a type T for any expression if S <: T (§4.10).
和以前一样,请注意这里描述的关系包括 S 和 T 是同一类型的情况,而不是彼此严格的子类型(这将是 正确的子类型 ) .
对于基本类型,在4.10.1 基本类型之间的子类型化:
中有描述
The following rules define the direct supertype relation among the primitive types:
- double >1 float
- float >1 long
- long >1 int
- int >1 char
- int >1 short
- short >1 byte
有了这些,对于这种特殊情况,重载决议规则实际上与 C# 相同。前面的解释是适用的。
我运行 C#中的以下方法。
public float Add(float num1, long num2)
{
Console.WriteLine("method 1");
return 0;
}
public float Add(int num1, float num2)
{
Console.WriteLine("method 2");
return 0;
}
在这里,如果我调用Add(1,1)
,它会产生歧义。
现在让我交换第一种方法中 float
和 long
的位置,如下所示:
public float Add(long num1, float num2)
{
Console.WriteLine("method 1");
return 0;
}
public float Add(int num1, float num2)
{
Console.WriteLine("method 2");
return 0;
}
现在它打印 "method 2" 作为输出。第一种情况的歧义背后的原因是什么?
如果我在代码中编写以下两个方法:
public float Add(long num1, long num2)
{
Console.WriteLine("method 1");
return 0;
}
public float Add(int num1, float num2)
{
Console.WriteLine("method 2");
return 0;
}
调用Add(1,1)
时,出现歧义错误。为什么它不进行最佳匹配,这是第二种方法(具有 int
和 float
)?根据我的说法,它应该将方法 2 作为输出。
在这种情况下,编译器会寻找与输入变量最匹配的方法
public float Add(float num1, long num2)
{
Console.WriteLine("method 1");
return 0;
}
public float Add(int num1, float num2)
{
Console.WriteLine("method 2");
return 0;
}
Add(1,1)这个方法不清楚应该选择哪个版本,所以为了解决这个问题(第一个参数是float或int,第二个参数是long或float)你必须指定类型方法中的输入参数
Add(1F, 1);
Add(1, 1F);
但是下面的代码,编译器将 int 类型视为第一个方法参数中数字 1 的最接近匹配
public float Add(long num1, float num2)
{
Console.WriteLine("method 1");
return 0;
}
public float Add(int num1, float num2)
{
Console.WriteLine("method 2");
return 0;
}
所以如果你想调用第一个方法你应该这样做
Add(1L, 1);
第三部分代码
public float Add(long num1, long num2)
{
Console.WriteLine("method 1");
return 0;
}
public float Add(int num1, float num2)
{
Console.WriteLine("method 2");
return 0;
}
同样不清楚编译器应该使用哪个版本,因为你的方法中有第二个输入参数(float 或 long),所以为了解决这个问题你必须指定输入
Add(1L, 1);//method 1
Add(1, 1F);// method 2
来自C# specification,7.5.3.2 Better Function成员:
Given an argument list A with a set of argument expressions { E1, E2, ..., EN } and two applicable function members MP and MQ with parameter types { P1, P2, ..., PN } and { Q1, Q2, ..., QN }, MP is defined to be a better function member than MQ if
- for each argument, the implicit conversion from EX to QX is not better than the implicit conversion from EX to PX, and
- for at least one argument, the conversion from EX to PX is better than the conversion from EX to QX.
请注意,规范使用术语 隐式转换 的方式包括身份转换。请参阅 6.1 隐式转换:
The following conversions are classified as implicit conversions:
- Identity conversions
- Implicit numeric conversions
- [...]
从6.1.1 身份转换:
An identity conversion converts from any type to the same type. [...]
您的参数类型集是:
{ int, int }
第一种情况,候选人是:
{ float, long }
{ int, float }
设MP为第一候选,MQ为第二候选
- 有一个参数 X (= 1),其中从 EX 到 QX 的隐式转换 优于从 EX 到 PX 的隐式转换:
int
到int
比int
到float
好(因为是同一类型)。
设MP为第二候选,MQ为第一候选
- 有一个参数 X (= 2),其中从 EX 到 QX 的隐式转换 优于从 EX 到 PX 的隐式转换:
int
到long
优于int
至float
.
两位候选人都不符合第一个要点。规范中描述的打破平局的机制在这里不适用(因为这两种方法都不是通用的,也不是可变的,也没有可选参数,等等)。因此,这个调用是不明确的。
第二种情况,候选人是:
{ long, float }
{ int, float }
设MP为第一候选,MQ为第二候选
- 有一个参数 X (= 1),其中从 EX 到 QX 的隐式转换 优于从 EX 到 PX 的隐式转换:
int
到int
比int
到long
好(因为类型相同)。
设MP为第二候选,MQ为第一候选
- 没有参数 X,其中从 EX 到 QX 的隐式转换优于从 EX 到 PX 的隐式转换。
- 有一个参数 X (= 1),其中从 EX 到 PX 的隐式转换 优于从 EX 到 QX 的转换:
int
到int
优于int
至long
.
由于第二个候选人同时满足两个要点,因此比第一个更匹配。
第三种情况,候选人是:
{ long, long }
{ int, float }
就像第一种情况:
int
到int
优于int
到long
.- 但是
int
到long
比int
到float
好。
这样调用又是模棱两可的。
Java Language Specification 在 15.12.2.5 选择最具体的方法 中指出:
One applicable method m1 is more specific than another applicable method m2, for an invocation with argument expressions e1, ..., ek, if any of the following are true:
- m2 is generic, and m1 is inferred to be more specific than m2 for argument expressions e1, ..., ek by §18.5.4.
- m2 is not generic, and m1 and m2 are applicable by strict or loose invocation, and where m1 has formal parameter types S1, ..., Sn and m2 has formal parameter types T1, ..., Tn, the type Si is more specific than Ti for argument ei for all i (1 ≤ i ≤ n, n = k).
- m2 is not generic, and m1 and m2 are applicable by variable arity invocation, and where the first k variable arity parameter types of m1 are S1, ..., Sk and the first k variable arity parameter types of m2 are T1, ..., Tk, the type Si is more specific than Ti for argument ei for all i (1 ≤i≤k). Additionally, if m2 has k+1 parameters, then the k+1'th variable arity parameter type of m1 is a subtype of the k+1'th variable arity parameter type of m2.
The above conditions are the only circumstances under which one method may be more specific than another.
A type S is more specific than a type T for any expression if S <: T (§4.10).
和以前一样,请注意这里描述的关系包括 S 和 T 是同一类型的情况,而不是彼此严格的子类型(这将是 正确的子类型 ) .
对于基本类型,在4.10.1 基本类型之间的子类型化:
中有描述The following rules define the direct supertype relation among the primitive types:
- double >1 float
- float >1 long
- long >1 int
- int >1 char
- int >1 short
- short >1 byte
有了这些,对于这种特殊情况,重载决议规则实际上与 C# 相同。前面的解释是适用的。