当使用ClassName.method()时,首先使用Compiler,Static或instance方法查找哪个方法?

时间:2015-03-28 09:46:01

标签: java static compiler-errors

我想正确理解为什么在编译错误之下? 根据我的理解如果我使用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等。

4 个答案:

答案 0 :(得分:3)

为什么会出现编译错误

编译通过不同的步骤进行。从JLS中提取,以下是解释您出现此错误的原因的规则。

我跳过与您的案例无关的first step。一切都发生在同一个班级。

第二步:Determine method signature

  

可能存在多种此类方法,在这种情况下,选择最具体的方法。最具体方法的描述符(签名加返回类型)是在运行时用于执行方法调度的方法

     

第一阶段(§15.12.2.2)执行重载解析而不允许装箱或拆箱转换,或使用变量arity方法调用。如果在此阶段没有找到适用的方法,则处理继续到第二阶段。

从上面的评论中,您使用Test.xyz(10);调用的方法是采用int参数的方法:

public void xyz(int i) {}

但现在,还有第三步:Choosing the appropriate method

  

如果方法调用在左括号之前具有 TypeName形式的MethodName。标识符,或者如果左括号之前的方法调用具有TypeName形式。 NonWildTypeArguments标识符,然后编译时声明必须是静态的,否则会发生编译时错误。

同样,从上面的评论中,您以static形式

调用该方法
Test.xyz(10);

但不幸的是,从第二步中选择的方法是静态。

这就是为什么像Eclipse这样的IDE会建议“将'xyz()'改为静态”。

但正如我的第一个回答(已删除)中所述,您可以在课程public void xyz(int i) {}的实例上调用Test,或使用static调用Integer方法参数:Test.xyz(Integer.valueOf(10));

两者都有效。

答案 1 :(得分:1)

这里没有返回类型:

public static xyz(Integer i) {
}

如果没有任何回报,这应该是无效的:

public static void xyz(Integer i) {
}

而且,您还需要将第一个方法设为静态:

public static void xyz(int i) {
}

因此可以从静态main方法中调用它。无法使用静态方法调用非静态方法。有关此问题的更详细说明:calling non-static method in static method in Java

答案 2 :(得分:0)

这就是我做静态类的方法。

public class test {
       public static void main(String arg[]) {
        xyz(10);    
        }     

        public static void xyz(int i) {
        }   
    }

答案 3 :(得分:0)

好的,这就是Java中autoboxing的概念。

你写道:

Test.xyz(10); // Here 10 is a primitive int and not a java.lang.Integer object.  

但是,由于您直接通过类名调用xyz方法,因此显然意味着您要访问类public static xyz(Integer)的{​​{1}}方法。

但是在编译过程中会发生什么,首先你的Test编译器检查要访问的方法签名,然后检查它的访问权限javac,{{1} },publicprivate)和非访问(protecteddefaultfinal)修饰符。

这段代码也发生了同样的事情。

Java做的第一件事是,它检查了签名static的方法是否存在,而不是etc因为你传递了xyz(int)而不是{{1} }作为参数。

它找到了两种方法,
  1. xyz(Integer)
  2. 10

如果new Integer(10)不存在,它会应用自动装箱的概念(即自动将xyz(int)转换为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

希望这会有所帮助。

相关问题