C#和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) ,它会给出歧义。 现在让我在第一个方法中交换floatlong位置,如下所示:

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

现在它打印“方法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) ,它会产生歧义错误。 为什么它不是最佳匹配,这是第二种方法(有intfloat )? 根据我的说法,它应该将方法2作为输出。

从C#规范 , 7.5.3.2 Better Function成员

给定一个参数列表A,其中包含一组参数表达式{E1,E2,…,EN}和两个适用的函数成员MP和MQ,参数类型为{P1,P2,…,PN}和{Q1,Q2, …,QN},MP被定义为比MQ更好的函数成员

  • 对于每个参数,从EX到QX的隐式转换并不比从EX到PX的隐式转换更好
  • 对于至少一个参数,从EX到PX的转换优于从EX到QX的转换。

请注意,规范使用术语隐式转换 ,其方式包括身份转换。 请参见6.1隐式转换

以下转化归类为隐式转化:

  • 身份转换
  • 隐式数字转换
  • […]

6.1.1身份转换

身份转换从任何类型转换为相同类型。 […]


您的参数类型集是:

 { int, int } 

在第一种情况下,候选人是:

 { float, long } { int, float } 

让MP成为第一个候选者,MQ成为第二个候选者。

  • 有一个参数X(= 1),其中从EX到QX的隐式转换优于从EX到PX的隐式转换: intint优于intfloat (因为它是相同的类型)。

让MP成为第二个候选者,MQ成为第一个候选者。

  • 有一个参数X(= 2),其中从EX到QX的隐式转换优于从EX到PX的隐式转换: int to long优于int to float

两个候选人都不满足第一个子弹。 这里描述的打破平局机制在这里不适用(因为这两种方法都不是通用的,也不是可变参数,也没有可选参数等)。 因此,这种呼吁是模棱两可的。


在第二种情况下,候选人是:

 { long, float } { int, float } 

让MP成为第一个候选者,MQ成为第二个候选者。

  • 有一个参数X(= 1),其中从EX到QX的隐式转换优于从EX到PX的隐式转换: intint优于intlong (因为它是相同的类型)。

让MP成为第二个候选者,MQ成为第一个候选者。

  • 没有参数X,从EX到QX的隐式转换优于从EX到PX的隐式转换。
  • 有一个参数X(= 1),其中从EX到PX的隐式转换优于从EX到QX的转换: intint优于intlong

由于第二个候选人满足两个子弹,因此它比第一个更好。


在第三种情况下,候选人是:

 { long, long } { int, float } 

就像第一种情况一样:

  • intintint更好。
  • int to longint更好float

因此,呼叫再次模棱两可。


Java语言规范在15.12.2.5中说明选择最具体的方法

一个适用的方法m1比另一个适用的方法m2更具体,用于参数表达式e1,…,ek的调用,如果满足以下任何条件:

  • m2是通用的,并且根据§18.5.4推断m1对于参数表达式e1,…,ek比m2更具体。
  • m2不是通用的,m1和m2适用于严格或松散的调用,并且m1具有forms参数类型S1,…,Sn和m2具有forms参数类型T1,…,Tn,类型Si更多对于所有i,参数ei的特定于Ti(1≤i≤n,n = k)。
  • m2不是通用的,m1和m2适用于变量arity调用,并且m1的前k个变量arity参数类型是S1,…,Sk和m2的前k个变量arity参数类型是T1,..对于所有i(1≤i≤k),对于参数ei,Si类型比Ti更具特异性。 另外,如果m2具有k + 1个参数,则m1的第k + 1个可变参数类型是第m + 1个可变参数类型m2的子类型。

上述条件是一种方法可能比另一种方法更具体的唯一情况。

如果S <:T(§4.10),则类型S对于任何表达式比类型T更具体。

和以前一样,请注意这里描述的关系包括S和T是相同类型的情况,而不是彼此的严格子类型 (这将是正确的子类型 )。

对于原始类型,在4.10.1原始类型之间的子类型中描述:

以下规则定义了基本类型之间的直接超类型关系:

  • 双> 1浮动
  • 浮> 1长
  • 长> 1 int
  • int> 1个字符
  • int> 1短
  • 短> 1个字节

有了这些,对于这种特殊情况,重载决策规则实际上与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; } 

添加(1,1)这个方法不清楚应该选择哪个版本,所以为了解决这个问题(第一个参数中的float或int,long或第二个中的float)你必须在方法中指定一个输入参数的类型

  Add(1F, 1); Add(1, 1F); 

但是在下面的代码中,编译器将int类型视为第一个方法参数中数字1的最接近的matche

 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