当使用ClassName.method()时,首先使用Compiler,Static或instance方法查找哪个方法?
我想正确理解为什么在编译错误之下? 根据我的理解如果我使用Test.xyz()然后编译器只查找静态方法而不是实例方法然后为什么在编译失败?
class Test { public static void main(String arg[]) { Test.xyz(10); // compilation fail } public void xyz(int i) { } public static void xyz(Integer i) { } }
每个人请建议为什么编译失败而不是其他建议和如何使用, 我知道所有基本的东西Autoboxing等。
为什么会出现编译错误
编译通过不同的步骤进行。 从JLS中提取,以下是解释您遇到此错误的原因的规则。
我跳过了与你的情况无关的第一步 。 一切都发生在同一个class级。
第二步: 确定方法签名
可能存在多于一种这样的方法,在这种情况下,选择最具体的方法。 最具体方法的描述符(签名加返回类型)是在运行时用于执行方法分派的方法
第一阶段(§15.12.2.2)执行重载解析而不允许装箱或拆箱转换 ,或使用变量arity方法调用。 如果在此阶段没有找到适用的方法,则处理继续到第二阶段。
从上面的注释中,您使用Test.xyz(10);
调用的方法Test.xyz(10);
是一个采用int
参数的那个:
public void xyz(int i) {}
但现在,还有第三步: 选择合适的方法
如果方法调用在左括号之前具有TypeNameforms的MethodName 。 标识符 ,或者左括号之前的方法调用,具有TypeNameforms。 NonWildTypeArguments标识符,然后编译时声明必须是静态的 ,否则会发生编译时错误。
同样,从上面的注释中,您以static
forms调用该方法,
Test.xyz(10);
但不幸的是,从第二步中选择的方法并不是静态的。
这就是为什么像Eclipse这样的IDE会建议“将’xyz()’改为静态”。
但正如我在第一个答案(删除)中所解释的那样,您可以在类Test
的实例上调用public void xyz(int i) {}
,或者使用Integer
参数调用static
方法: Test.xyz(Integer.valueOf(10));
。
两者都有效。
你这里没有返回类型:
public static xyz(Integer i) { }
如果没有任何回报,这应该是无效的:
public static void xyz(Integer i) { }
而且,您还需要将第一个方法设为静态:
public static void xyz(int i) { }
因此可以从静态main方法中调用它。 无法使用静态方法调用非静态方法。 更详细的解释: 在Java中调用静态方法中的非静态方法
这就是我做静态类的方法。
public class test { public static void main(String arg[]) { xyz(10); } public static void xyz(int i) { } }
好的,所以这里有Java中的autoboxing
概念。
你写道:
Test.xyz(10); // Here 10 is a primitive int and not a java.lang.Integer object.
但是由于您通过类名直接调用xyz
方法,显然意味着您要访问类Test
的public static xyz(Integer)
方法。
但是在编译过程中发生的事情是,首先你的javac
编译器检查要访问的方法签名,然后检查它的访问权限( public
, private
, protected
, default
)和非访问( final
, static
, etc
)修饰语。
这段代码也发生了同样的事情。
Java做的第一件事是,它检查了签名xyz(int)
的方法是否存在,而不是xyz(Integer)
因为你已经传入10
而不是new Integer(10)
作为参数。
它找到了两种方法,
1. xyz(int)
2. xyz(Integer)
如果xyz(int)
不存在,它将应用自动装箱的概念(即,自动将10
转换为new Integer(10)
)并选择要执行的xyz(Integer)
。 但是由于xyz(int)
存在,它不会将10
自动装箱到new Integer(10)
并选择xyz(int)
而不是xyz(Integer)
。
现在,由于您的编译器选择了要执行的xyz(int)
,它会检查它的非访问修饰符。 现在因为方法xyz(int)
是非静态的,所以你需要使用Test
类的对象访问它,如下所示:
new Test().xyz(10);
而且,如果要访问static xyz(Integer)
方法,您可能必须使用:
Test.xyz(new Integer(10)); // You have to maunally autobox it.
希望这可以帮助。