Which method is looked first by Compiler , Static

2019-02-20 10:39发布

问题:

I want to get proper understanding why below compilation error? As per my understanding If i use Test.xyz() then compiler look for only static method not for instance method then why below compilation fail?

class Test {
    public static void main(String arg[]) {
        Test.xyz(10);     // compilation fail
    }   

    public void xyz(int i) {
    }
    public static void xyz(Integer i) {
    }   
 }

Every one please suggest why compilation fail rather than other suggestions and how to use , I know all basic thing Autoboxing etc .

回答1:

Why there is a compilation error

Compilation proceeds through different steps. Extracted from the JLS, following are the rules that explain why you got this error.

I skip the first step which is not relevant in your case. Everything happens in the same class.

Second step: 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.

From above comments, the method you invoke with Test.xyz(10); is the one that takes an int parameter:

public void xyz(int i) {}

But now, there is a third step: 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.

Again, from the above comment, you invoke the method in a static form,

Test.xyz(10);

but unfortunately, the method chosen from the second step, is not static.

It's why an IDE like Eclipse will suggest to "Change 'xyz()' to static".

But as explained in my first answer (deleted), you can either call public void xyz(int i) {} on an instance of class Test, or call the static method with an Integer parameter: Test.xyz(Integer.valueOf(10));.

Both will work.



回答2:

You have no return type here:

public static xyz(Integer i) {
}

This should be void, if there is nothing to return:

public static void xyz(Integer i) {
}

And also, you need to make the first method static too:

public static void xyz(int i) {
}

So it can be called out of the static main method. It is not possible to call non-static methods out of static methods. More detailed explanation on this: calling non-static method in static method in Java



回答3:

This is how I did the static class.

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

        public static void xyz(int i) {
        }   
    }


回答4:

Ok, So here comes the concept of autoboxing in Java.

U wrote:

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

But since you are invoking the xyz method directly via class name, clearly means you want to access the public static xyz(Integer) method of the class Test.

But what happens in the compilation process is, first your javac compiler checks for method signature that is to be accessed, and after that, it checks for it's access(public, private, protected, default) and non-access(final, static, etc) modifiers.

The same thing happened with this code.

The first thing Java did was, it checked for the existence of the method with the signature xyz(int) and not xyz(Integer) coz you've passed in 10 and not new Integer(10) as a parameter.

It found two methods,
1. xyz(int)
2. xyz(Integer)

Had xyz(int) not existed, it would have applied the concept of autoboxing(ie, automatically convert 10 to new Integer(10)) and selected xyz(Integer) to be executed. But since xyz(int) exists, it does not autobox 10 to new Integer(10) and selects xyz(int) instead of xyz(Integer).

Now since your compiler has selected xyz(int) to be executed, it checks for it's non-access modifiers. Now since the method xyz(int) is non-static, you are expected to access it with an object of Test class as follows:

new Test().xyz(10);  

And still, if you want to access the static xyz(Integer) method, you may have to use:

Test.xyz(new Integer(10)); // You have to maunally autobox it.  

Hope this helps.