-2

I am a little bit puzzled by this:

void a(){
 Log.d(TAG, "Noargs");
}
void a(int... s){
 Log.d(TAG, "Varargs");
}

My first question is what will be logged if I call a();? Please try to guess because I am trying to illustrate the confusion with this. I tested it and the answer is in the end of the question.

The real question is then how does Varargs really work, how does JVM know which method you are calling since the way to call them is the same?

Also is there something in Java (or something planned) to allow for this

AS3 Code: function sayHello(somebody:String = “world”):void{}
//This allows you to specify default values of arguments and have them as optional

Answer is Noargs even Ecipse references this method.

Igor Čordaš
  • 5,785
  • 4
  • 42
  • 54
  • 1
    "how does Varargs really work?" As described in the spec. –  Jun 20 '14 at 10:18
  • I don't get what you are saying if there is some documentation where this is explained please link to it. – Igor Čordaš Jun 20 '14 at 10:19
  • 1
    I'm not sure where the confusion is arising here. You told the JVM to invoke a method with the signature `a()` and that's exactly what it did. Why would it do anything else? – JonK Jun 20 '14 at 10:19
  • Check Java Language Specification. – Abimaran Kugathasan Jun 20 '14 at 10:20
  • Becouse if you delete the noarguments method it then calls the Varargs one. That is what I find confusing. – Igor Čordaš Jun 20 '14 at 10:21
  • 1
    http://ideone.com/G1mIhH The Runtime finds the closest possible match. It has a choice between `0...*` and `0`. `0` is a closer match to a zero argument call, hence it runs the no argument method. – christopher Jun 20 '14 at 10:22
  • 1
    Like JonK said. The JVM links the best fitting method to your method call. The most specific one will be linked. Look at overloading in Java – Maze Jun 20 '14 at 10:24
  • 2
    Java will always call the *most specific* method based on the signature. When you have a no-args signature and you tell the JVM to invoke the no-args version, that's the most specific method it can find. It matches up *exactly* with what you wanted. The varargs one is less specific...until you pass in at least one `int` argument. – JonK Jun 20 '14 at 10:25
  • These last comments do explain it so thank you. So method call doesn't look for a value pair in the map to find the method definition but essentially does a search? Does this mean that if I use excessive method overloading it will (probably marginally) slow down JVM? – Igor Čordaš Jun 20 '14 at 10:33
  • No, the choice of which version of an overloaded method is called is made at compile time, not at runtime. You can verify that using the `javap` tool to inspect the generated bytecode for both versions of the class. – JonK Jun 20 '14 at 10:46
  • I miss-formulated the comment (and then time limit passed for edit) and you are right about the compile time. But than the question would still be does excessive overloading of methods slows the compiling process since mapping names to definitions requires a search? @JonK Your comment is what answered my question so if you want you can formulate it as an answer for me to accept. – Igor Čordaš Jun 20 '14 at 10:50
  • 1
    just to answer how varargs works, its no different than `void a(int[] s)` so there isn't anything special in it except for the user convenience, the way its used (1,2) instead of creating an array and then pass it to the method (well you can pass an array to instead of multiple arguments). also you can't provide default values for method arguments (maybe like c++) in java. – Shailesh Aswal Jun 20 '14 at 11:03
  • Stack Overflow is not the index of the Java Language Specification, which answers this question perfectly clearly. – Dawood ibn Kareem Jun 20 '14 at 11:16
  • Hm that also explains this. So essentially input type of varargs method is actually an array of listed type and ... is just syntax sugar am I right? About the default values I know that suggested way for that in Java is via method overloading but was just wondering if that is something planned for Java 9. I know that features like Lambda expressions get all the hype but having a better way to specify default values would be much more useful. I mean you can do it in C# and I suspect Lambdas were C# "Inspired" (not like they invented it or something, just it was a nice feature found there). – Igor Čordaš Jun 20 '14 at 11:18
  • I don't get the hate this question is getting based on "See the Specification it's all there"... There are many Java questions on SO which can be answered by reading specification but keep in mind that document is huge and sometimes it's hard to connect which part of the specification regards things asked in the question. – Igor Čordaš Jun 20 '14 at 11:25
  • 1
    @DavidWallace Ultimately every programming question could be answered by reading the language specification/API documentation. Following that reasoning, all questions are bad. [Once upon a time these sorts of questions were considered good](http://stackoverflow.com/questions/8710619/java-operator)... – JonK Jun 20 '14 at 11:28
  • @PSIXO: yes its just syntax sugar. The compiler converts a(1,2) to an array {1,2} and then pass that as a([]). – Shailesh Aswal Jun 20 '14 at 11:34
  • Thank you @Shail016 that cleared things a bit. – Igor Čordaš Jun 20 '14 at 12:17
  • @JonK That's like saying that everything Shakespeare ever wrote could have been done by cutting and pasting words from a dictionary. There's a world of difference between a genuine programming question, (which deserves to be answered) and an "I can't be bothered finding the documentation" question (which deserves to be closed). – Dawood ibn Kareem Jun 20 '14 at 12:29

1 Answers1

1

The behaviour you're observing is because Java always chooses the most specific version of an overloaded method based on the arguments that you pass to it (further reading).

Given your scenario:

void a() {
    Log.d(TAG, "Noargs");
}

void a(int... s) {
    Log.d(TAG, "Varargs");
}

A call to a() matches up exactly with the void a() { ... } method - it's the most specific version of the method given the arguments. When you remove void a() { ... } the varargs method becomes the most specific version and so will be called instead.

You can take this a step further:

public class VarargsTest {

    public static void a(int... s) {
        System.out.println("int varargs invoked.");
    }

    public static void a(short... s) {
        System.out.println("short varargs invoked.");
    }

    public static void a(long... s) {
        System.out.println("long varargs invoked.");
    }

    public static void a(byte... s) {
        System.out.println("byte varargs invoked.");
    }

    public static void main(String... args) {
        a();
    }
}

This invokes the byte... overload of a. If you remove that, the short... version gets called, then int... and finally long....

If you instead add another overload with char... as the argument, it becomes a compilation error because char and byte have the same specificity - the compiler is unable to determine which version is the correct one to call unless you explicitly provide an argument to the method call.

JonK
  • 2,097
  • 2
  • 25
  • 36
  • Great edge case examples. Key point then is actually that compiler finds the closest method and there is no 1-1 mapping. But your answer explains exactly what I wanted to know, thank you. – Igor Čordaš Jun 25 '14 at 08:45