我试图理解方法重载,我有这些方法。
public void method(int a){
System.out.println("int a");
}
//implementing interface method
@Override
public void method() {
System.out.println("interface");
}
//varargs
public void method(int ... a){
System.out.println("int ... a");
}
用这些参数调用后,
int[] a = new int[5];
stack.method();
stack.method(1);
stack.method(5,6);
stack.method(null);
stack.method(a);
我有这些结果:
接口
int a int ... a int ... a int ... a
据我所知,该程序不应该编译,因为模糊不清,但无论如何都是如此。编译器不应该抛出错误吗?
答案 0 :(得分:4)
Eran和Bathsheba已经说过为什么选择不使用null
的各种人。
问题的其余部分是:为什么stack.method(null);
甚至编译?
答案是它与varargs签名匹配,因为varargs method(int...)
在编译器的视角与method(int[])
实际上是相同的。由于数组是通过引用引用的,因此null
可以在需要int[]
的地方使用。
所以:
stack.method();
界面中method()
签名的完全匹配。与method(int...)
不一致,因为仅当其他人不匹配时才会考虑varargs。
stack.method(1);
匹配method(int)
。由于与上述相同的原因,并不含糊。
stack.method(5,6);
匹配method(int...)
,因为没有一个非varargs匹配,但是varargs匹配了。
stack.method(null);
见前面的解释。
stack.method(a);
匹配match(int...)
的原因与method(null0
相同:因为match(int...)
实际上与编译器的match(int[])
相同。
答案 1 :(得分:3)
方法重载分辨率有三个阶段。第一阶段和第二阶段不考虑使用varargs(也称为变量arity方法)作为候选者的方法,因此,只有在没有找到没有varargs的匹配方法的情况下,编译器才会将varargs视为候选方法。 / p>
因此,在第一次和第二次方法调用中,您的void method(int ... a)
被忽略,并且没有歧义。
15.12.2. Compile-Time Step 2: Determine Method Signature
第二步搜索上一步中确定的类型 成员方法。此步骤使用方法的名称和参数 表达式,用于查找既可访问又适用的方法, 也就是说,可以在给定的上正确调用的声明 参数。
可能有多种这样的方法,在这种情况下最多 选择特定的一个。描述符(签名加返回类型) 最具体的方法是在运行时使用的方法来执行 方法调度。
如果通过严格调用之一适用,则该方法适用 (§15.12.2.2),松散调用(§15.12.2.3),或变量arity 调用(§15.12.2.4)。
某些包含隐式类型lambda的参数表达式 表达式(第15.27.1节)或不精确的方法引用(第15.13.1节)是 被适用性测试忽略了,因为它们的含义不可能 确定,直到选择目标类型。
虽然方法调用可能是poly表达式,但只有它的 参数表达式 - 不是调用的目标类型 - 影响 选择适用的方法。
确定适用性的过程从确定适用性开始 可能适用的方法(§15.12.2.1)。
该过程的其余部分分为三个阶段,以确保 与之前的Java编程语言版本的兼容性 Java SE 5.0。阶段是:
第一阶段(§15.12.2.2)执行重载解析而不允许装箱或拆箱转换,或使用变量arity 方法调用。如果在此阶段没有找到适用的方法 然后处理继续到第二阶段。 这保证了在Java SE 5.0之前在Java编程语言中有效的任何调用都不会被认为是不明确的 作为引入变量arity方法的结果,隐含的 装箱和/或拆箱。但是,声明变量arity 方法(第8.4.1节)可以更改为给定方法方法选择的方法 调用表达式,因为变量arity方法被视为一个 固定arity方法在第一阶段。例如,声明 m(Object ...)在已经声明m(Object)的类中导致 不再为某些调用表达式选择m(Object)(例如 如m(null)),因为m(Object [])更具体。
第二阶段(§15.12.2.3)执行重载解析,同时允许装箱和拆箱,但仍然排除使用变量 arity方法调用。如果在此期间未找到适用的方法 阶段然后处理继续到第三阶段。 这确保了如果通过固定arity方法适用,则永远不会通过变量arity方法调用来选择方法 调用
- 醇>
第三阶段(§15.12.2.4)允许重载与变量arity方法,装箱和拆箱相结合。
答案 2 :(得分:1)
只有所有其他可能性都已用完后,编译器才会考虑带有可变参数列表的方法。
这些“其他可能性”以正常方式考虑。
因此,在您的情况下,没有歧义,因此编译器不会发出错误。
答案 3 :(得分:1)
没有问题没有歧义:<!DOCTYPE html>
<html>
<head>
<title>Contact Form | PHP, AJAX and MySQL</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
</head>
<body>
<br /><br />
<div class="container" style="width:500px;">
<form id="submit_form">
<label for="name">Name</label>
<input type="text" name="name" id="name" class="form-control" />
<br />
<label for="message">Message</label>
<textarea name="message" id="message" class="form-control"></textarea>
<br />
<input type="submit" name="submit" id="submit" class="btn btn-info" value="Submit" />
<span id="error_message" class="text-danger"></span>
<span id="success_message" class="text-success"></span>
</form>
</div>
</body>
</html>
<script>
jQuery(function($){
$('form#submit_form').submit(function(e){
e.preventDefault();
var name = $(this).find('#name').val(),
message = $(this).find('#message').val();
if(name == '' || message == '') {
$('#error_message').html("All Fields are required");
}
else {
$('#error_message').html('');
$.ajax({
url:"mailer.php",
method:"POST",
data:{
name: name,
message: message
},
success:function(data){
$("form").trigger("reset");
$('#success_message').fadeIn().html(data).fadeOut(3000);
}
});
}
});
});
</script>
很好,因为该方法表示许多整数,传递passing "(5,6)"
也很好,因为a是一个整数数组"(a)"
也很好passing"(null)"
可以转换为null
之类的任何引用类型,因此可以在期望int []的地方使用;
所以所有这些调用都调用了第三种方法
integer []
前两个方法调用是自解释的,他们调用方法
public void method(int ... a){
System.out.println("int ... a");
}
和
public void method(){
System.out.println("interface");
}
分别