wood burning stoves 2.0*
The moose likes Programmer Certification (SCJP/OCPJP) and the fly likes Var args ... explanation needed Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Programmer Certification (SCJP/OCPJP)
Bookmark "Var args ... explanation needed" Watch "Var args ... explanation needed" New topic
Author

Var args ... explanation needed

Sanjeev Singh
Ranch Hand

Joined: Nov 01, 2006
Posts: 381
Hi Ranchers,
Can anybody explains the behaviour of

?


~Sanjeev Singh<br />SCJP 1.5
Jae Stryker
Greenhorn

Joined: Oct 31, 2006
Posts: 21
It doesn't compile.

However I've changed the code slighty to try and help you along



This is an example of how you can use varargs and how you can overload them

Hope this helps a little.
Prashant kumar Singh
Greenhorn

Joined: Nov 04, 2006
Posts: 22
Hi,
I think in this type of overloading with varargs.You have to use different name of methods.Because at compile time compiler become confuse .i have written it as
If any Wrong in my explanation then.Please tell me

Thanks,
Prashant Kumar Singh
Ganesh Pujar
Ranch Hand

Joined: Mar 22, 2006
Posts: 45
Nor does this compile
Can anyone tell us the reason WHY?

Sanjeev Singh
Ranch Hand

Joined: Nov 01, 2006
Posts: 381
Dear Ranchers,

The output here is obvious,there are matching arguments for both of the method calls.
My question is why there is ambiguity in the code

Does the rule of preference of the overloaded method not exists here,when there is no matching parameter?Imagine the case when there is no var args and the argument in the methods are (long x) and (Integer x),it is the (long x) which dominates,why not such a case is here?
[ November 07, 2006: Message edited by: Sanjeev Kumar Singh ]
Rancy Chadha
Ranch Hand

Joined: Jul 12, 2006
Posts: 135
Hi all,

class Vararg
{
static void vararg(long ... x){ System.out.println("long...");}static void vararg(Integer ... x){ System.out.println("Integer...");}public static void main(String [] args) { int i = 5; vararg(5,5);}}


Thanks,<br />-Rancy
Rancy Chadha
Ranch Hand

Joined: Jul 12, 2006
Posts: 135
Hi all,

class Vararg
{
static void vararg(long ... x) ---------- (1)
{ System.out.println("long...");
}
static void vararg(Integer ... x) ----------- (2)
{ System.out.println("Integer...");
}
public static void main(String [] args)
{ int i = 5;
vararg(5,5);
}
}
At compile time a vararg is converted to an array.
What happens after we calls vararg(5,5)
at (1) after widening it can be converted to long[] = {5,5}
at (2) after autoboxing it can be converted to Integer[] = {5,5}
in this case compiler does not find MOST SPECIFIC method to use when it is working out method overloading, because both long[] and Integer[] are Array objects so it gives us error stating ambiguity.

The above reason is the reason that I think would be holding true, I may be wrong on this. If anybody finds this answer wrong please do correct me.

Thanks,
Rancy
Bram Maes
Ranch Hand

Joined: Sep 27, 2006
Posts: 32
I think this is strange because I thought the rule is to take the 'old style' when there's a doubt. So i'd think the compiler would take long..., because widening existed long time before autoboxing. Apparently I'm missing something here...


SCJP 5.0, SCEA part I
Krishna Srinivasan
Ranch Hand

Joined: Jul 28, 2003
Posts: 1844

Article on Varargs :
http://www.javabeat.net/javabeat/scjp2/ht/index.php?examType=SCJP&msgId=19


Krishna Srinivasan
Spring Tutorials, OCAJP Mock Questions, 400+ OCPJP Mock Questions
Sanjeev Singh
Ranch Hand

Joined: Nov 01, 2006
Posts: 381
The above link gives only a primary knowlege of var-args and a lot of things is missing...
Saurabh Vyas
Ranch Hand

Joined: Sep 02, 2003
Posts: 72
Hi Ranchers,

We know that at compile time a vararg is converted to an array.

Thus after compilation the code may look something like this :

public class VarArgs {

// static void vararg(long ... x) {
static void vararg(long[] x) {
System.out.println("long...");
System.out.println(x instanceof Object); // returns true;
}

// static void vararg(Integer ... x) {
static void vararg(Integer[] x) {
System.out.println("Integer...");
System.out.println(x instanceof Object); // returns true;
}

public static void main(String [] args) {
int i = 5;
vararg(5,5);
}

}

Now while calling the method varag, lets say its arguments get converted to an Object of some array type.
Now there are 3 possibilities for this array type � It can be either converted to long[], or Integer[] or Object[].

So lets modify the main method a bit for these arrays. Now the code looks as shown below:

public class VarArgs {

// static void vararg(long ... x) {
static void vararg(long[] x) {
System.out.println("long...");
System.out.println(x instanceof Object); // returns true;
}

// static void vararg(Integer ... x) {
static void vararg(Integer[] x) {
System.out.println("Integer...");
System.out.println(x instanceof Object); // returns true;
}

public static void main(String [] args) {
int i = 5;
Object[] obj = {i,i};
long[] ln = {i,i};
Integer[] in = {i,i};

//vararg((Integer[])obj); // gives runtime exception ClassCastException
// vararg((long[])obj); // compilation error of inconvertible type
vararg(ln);
vararg(in);
}

}

Now for the above code it gives error if converted to Object[]. Thus the possibility of the vararg method�s arguments getting converted to Object[] can be canceled.

But the above code runs fine for both long[] and Integer[] if the arguments of vararg method are converted to any one of that type.

Thus compiler is showing ambiguous method call error during compilation of our original problem. B�cos compiler is confused as to which type of array it should convert the arguments of vararg method.

I guess I sound somewhat logical here.


regards
Saurabh
Sanjeev Singh
Ranch Hand

Joined: Nov 01, 2006
Posts: 381
Another question raises:
is
Why ( 1 ) gives Runtime ClassCastException ?
Why ( 2 ) give compilation error ?
Saurabh Vyas
Ranch Hand

Joined: Sep 02, 2003
Posts: 72
1) Runtime Exception comes because we are trying to cast the object of a Parent class to its child class. This is not possible. We can cast an object of child to that of a Parent but can not cast a Parent to a Child.

2) Compilation error comes because both the array types are inconvertible.
Saurabh Vyas
Ranch Hand

Joined: Sep 02, 2003
Posts: 72
It would be a Runtime Error and not Compile time error.
Joe Harry
Ranch Hand

Joined: Sep 26, 2006
Posts: 9351
    
    2

I see that this post has slowly deviated to reference casting. So I'm presenting here my way of interpreting things when it comes to reference casting. I'm showing it here in terms of words rather than in sentence.

You can never assign a superclass reference to a subclass refernce without a cast to that corresponding subclass which otherwise would result in a compile time error (without a cast). At the same time, if the superclass reference variable has an object of superclass type itself, then the result of that assignment(assigning superclass reference to a subclass type with casting of subclass) would result in a run time ClassCastException.

Here is the code view,

class Super{}
class Sub extends Super{}

Super s = new Super();
Sub ss = (Sub)s //would result in run time ClassCastException

but saying,

Super s = new Sub();
Sub ss = (Sub)s //would work fine

I hope this helped.


SCJP 1.4, SCWCD 1.4 - Hints for you, Certified Scrum Master
Did a rm -R / to find out that I lost my entire Linux installation!
Burkhard Hassel
Ranch Hand

Joined: Aug 25, 2006
Posts: 1274
Hi ranchers,


thanks to Sanjeev for this interesting question. And also thanks to Ganesh, who found out that it has nothing to do with Boxing, as the same behaviour occured, when the parameter type of the second method was changed from Integer to int.


I was surprised in this behavior in simply not compiling.
By the way, compiler says:
reference to vararg is ambiguous, both method vararg(long...) in Vararg and method vararg(java.lang.Integer...) in Vararg match
vararg(5,5);
^
in Sanjeev's version and

reference to vararg is ambiguous, both method vararg(long...) in Vararg and method vararg(int...) in Vararg match
vararg(5,5);
^
in Ganesh's version of the problem.



I think it cannot compile, because the compiler cannot say, what the most specific method is.
The criteria by which it decides this are rather complicated in the Language Specification, but I think in the end, the compiler cannot dexide.



This strange behaviour occurs only with primitive varargs. If all the varargs are Objects, there is no ambiguity.


And for primitives, the ambiguity occurs only, when one arguments is the smallest (as in the example, an int where the parameter lists were int... and long...).

So in this example, only one line would not compile if commented in, the bold one:



the other five lines calling the method print five times "double...".


If you change for example the vararg(byte... to (int... then the lines that call the method with the short or int won't compile as well.




I guess, to really understand why it is so, you got to work through this conditions in the language specification (see link above). But I think there would be a high risk of falling asleep and then you have the pattern of the keyboard on your forehead.


I said, you won't find this strange behaviour when you have only Wrapper (or any object) classes:





Compiles and prints out the expected. The class should get a different name.




Yours,
Bu.

---
to all (most) of the US cowboys: Have a funny election day!

sorry, I accidently deleted one sentence, I put it in again, these are the two edits.


[ November 07, 2006: Message edited by: Burkhard Hassel ]
[ November 07, 2006: Message edited by: Burkhard Hassel ]

all events occur in real time
Atul Shukla
Ranch Hand

Joined: Oct 09, 2006
Posts: 34
Originally posted by Saurabh Vyas:

Thus compiler is showing ambiguous method call error during compilation of our original problem. B�cos compiler is confused as to which type of array it should convert the arguments of vararg method.


class Vararg {
static void vararg(long ... x)
{ System.out.println("long..."); }
static void vararg(Integer ... x)
{ System.out.println("Integer..."); }
public static void main(String [] args) {
int i = 5;
vararg(5,5);
}
}


?

--------------------

Thanks
Sanjeev KS
Posts: 60 | Registered: Nov 2006 | IP: Logged
Jae Stryker
greenhorn
Member # 137135

posted November 07, 2006 01:46 AM Profile for Jae Stryker Send New Private Message Edit/Delete Post Reply With Quote It doesn't compile.

However I've changed the code slighty to try and help you along

code:


class Vararg {
static void vararg(String ... x)
{ System.out.println("String..."); }
static void vararg(Integer ... x)
{ System.out.println("Integer..."); }
public static void main(String [] args) {

int i = 5;
vararg(i,i);

String testOne = "TestOne";
String testTwo = "TestTwo";
String testThree = "TestThree";
//vararg(testOne,testTwo,testThree); Now there is no Error
}
}

I agree with Saurabh as this program dosen't produce any error , if we do not attempt to call these ambiguous overloaded methods
Atul Shukla
Ranch Hand

Joined: Oct 09, 2006
Posts: 34
thank you so much Burkhard!! that was a very nice explanation..

i am really not able to get into that horrable language Specification!!

Sanjeev Singh
Ranch Hand

Joined: Nov 01, 2006
Posts: 381
Hi Ranchers,
reference to vararg is ambiguous, both method vararg(long...) in Vararg and method vararg(java.lang.Integer...) in Vararg match
vararg(5,5);
^


To understand this problem I have tried to find out what compiler does when it finds the var-args?
Considering our example


Lets us first recall the rules associated with Boxing,Var-Args and Widening.
  • Primitive widening uses the "smallest" method argument possible.
  • Used individually, boxing and var-args are compatible with overloading.
  • You CANNOT widen from one wrapper type to another. (IS-A fails.)
  • You CANNOT widen and then box. (An int can't become a Long.)
  • You can box and then widen. (An int can become an Object, via Integer.)
  • You can combine var-args with either widening or boxing.


  • Considering that there is only one method-method 1.This is what I gets when I compile the code and then again decompiled it...

    In the above code the comiler has followed the rules stated i.e.
    Primitive widening uses the "smallest" method argument possible.
    You can combine var-args with either widening or boxing.

    the integer type is first widened into long and then converted into long array.

    Now consider the second schenario when method 1 is missing and only method 2 exists.This is what i get after compilation and decompilation.

    int has been wrapped into Integer... no problem
    Now since both the overloaded method are valid and is sticked to the rules stated above,when used individually.Also there is no precedence rules in such cases... the API writter might have missed it .... or they may not because both the feature Boxing and varargs are Java5 features.

    So is the ambiguity....This is how I tried to understand the problem.

    Again a question get raised while doing cognitive operation on this proble.

    Why the compiler has inserted transient in the all the static method,though transient are meant for the instance variables?
    [ November 08, 2006: Message edited by: Sanjeev Kumar Singh ]
    Ramu Malur S R
    Greenhorn

    Joined: Oct 17, 2006
    Posts: 26
    Hi All,

    The ambiguity is because of the rule that Sanjeev has highlighted.
    "You can combine var-args with either widening or boxing."

    Which is same as,
    "You cannot combine var-args with both widening and boxing"

    Coming to transient being used for methods,

    It is mainly because of obfuscation in java(try to make the decompiled code not readable and/or recompilable).

    You can also see java keywords like for,if etc., used for method names in decompiled code.

    I found the below link usefull to understand obfuscation,
    http://today.java.net/pub/a/today/2004/10/22/obfuscation.html

    - Ramu


    "Excellency is rarely found, more rarely valued"
    Burkhard Hassel
    Ranch Hand

    Joined: Aug 25, 2006
    Posts: 1274
    Hi Ramu,

    I though that this was the explanation in the first place. But it is not.
    Please test the code posted by Ganesh first near the beginning of this thread.
    I'll repaste it here skipping the unused line:



    Does not compile due to ambiguity, and there is no Boxing in here.


    Yours,
    Bu.
     
     
    subject: Var args ... explanation needed