使用 ClassName.method() 时,Compiler、Static 或实例方法首先查看哪个方法?
Which method is looked first by Compiler , Static or instance method when ClassName.method() is used?
我想正确理解为什么会出现以下编译错误?
根据我的理解,如果我使用 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) {
}
}
每个人都请提出编译失败的原因而不是其他建议以及如何使用,我知道所有基本的东西自动装箱等。
这就是我制作静态 class 的方式。
public class test {
public static void main(String arg[]) {
xyz(10);
}
public static void xyz(int i) {
}
}
您没有return类型:
public static xyz(Integer i) {
}
这应该是无效的,如果没有什么可以 return:
public static void xyz(Integer i) {
}
此外,您还需要将第一个方法设为静态:
public static void xyz(int i) {
}
所以可以从静态main方法中调用出来。不可能从静态方法中调用非静态方法。更详细的解释:calling non-static method in static method in Java
为什么会出现编译错误
编译通过不同的步骤进行。从 JLS 中提取,以下是解释为什么会出现此错误的规则。
我跳过了与您的情况无关的 first step。一切都发生在同一个 class.
第二步:Determine method signature
There may be more than one such method, in which case the most specific one is chosen. The descriptor (signature plus return type) of the most specific method is one used at run time to perform the method dispatch
The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.
根据上面的评论,您使用 Test.xyz(10);
调用的方法是采用 int
参数的方法:
public void xyz(int i) {}
但是现在,还有第三步:Choosing the appropriate method
If the method invocation has, before the left parenthesis, a MethodName of the form TypeName . Identifier, or if the method invocation, before the left parenthesis, has the form TypeName . NonWildTypeArguments Identifier, then the compile-time declaration must be static, or a compile-time error occurs.
同样,根据上面的注释,您以 static
形式调用方法,
Test.xyz(10);
但不幸的是,从第二步选择的方法不是静态的。
这就是为什么像 Eclipse 这样的 IDE 会建议“将 'xyz()' 更改为静态”。
但是正如我在第一个回答(已删除)中所解释的那样,您可以在 class Test
的实例上调用 public void xyz(int i) {}
,或者调用 static
方法Integer
参数:Test.xyz(Integer.valueOf(10));
.
两者都可以。
好的,那么Java中autoboxing
的概念就来了。
你写道:
Test.xyz(10); // Here 10 is a primitive int and not a java.lang.Integer object.
但是因为你是通过class名字直接调用xyz
方法,很明显你想访问classTest
的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
class 的对象访问它,如下所示:
new Test().xyz(10);
而且,如果您想访问 static xyz(Integer)
方法,您可能必须使用:
Test.xyz(new Integer(10)); // You have to maunally autobox it.
希望这对您有所帮助。
我想正确理解为什么会出现以下编译错误? 根据我的理解,如果我使用 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) {
}
}
每个人都请提出编译失败的原因而不是其他建议以及如何使用,我知道所有基本的东西自动装箱等。
这就是我制作静态 class 的方式。
public class test {
public static void main(String arg[]) {
xyz(10);
}
public static void xyz(int i) {
}
}
您没有return类型:
public static xyz(Integer i) {
}
这应该是无效的,如果没有什么可以 return:
public static void xyz(Integer i) {
}
此外,您还需要将第一个方法设为静态:
public static void xyz(int i) {
}
所以可以从静态main方法中调用出来。不可能从静态方法中调用非静态方法。更详细的解释:calling non-static method in static method in Java
为什么会出现编译错误
编译通过不同的步骤进行。从 JLS 中提取,以下是解释为什么会出现此错误的规则。
我跳过了与您的情况无关的 first step。一切都发生在同一个 class.
第二步:Determine method signature
There may be more than one such method, in which case the most specific one is chosen. The descriptor (signature plus return type) of the most specific method is one used at run time to perform the method dispatch
The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.
根据上面的评论,您使用 Test.xyz(10);
调用的方法是采用 int
参数的方法:
public void xyz(int i) {}
但是现在,还有第三步:Choosing the appropriate method
If the method invocation has, before the left parenthesis, a MethodName of the form TypeName . Identifier, or if the method invocation, before the left parenthesis, has the form TypeName . NonWildTypeArguments Identifier, then the compile-time declaration must be static, or a compile-time error occurs.
同样,根据上面的注释,您以 static
形式调用方法,
Test.xyz(10);
但不幸的是,从第二步选择的方法不是静态的。
这就是为什么像 Eclipse 这样的 IDE 会建议“将 'xyz()' 更改为静态”。
但是正如我在第一个回答(已删除)中所解释的那样,您可以在 class Test
的实例上调用 public void xyz(int i) {}
,或者调用 static
方法Integer
参数:Test.xyz(Integer.valueOf(10));
.
两者都可以。
好的,那么Java中autoboxing
的概念就来了。
你写道:
Test.xyz(10); // Here 10 is a primitive int and not a java.lang.Integer object.
但是因为你是通过class名字直接调用xyz
方法,很明显你想访问classTest
的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
class 的对象访问它,如下所示:
new Test().xyz(10);
而且,如果您想访问 static xyz(Integer)
方法,您可能必须使用:
Test.xyz(new Integer(10)); // You have to maunally autobox it.
希望这对您有所帮助。