Understanding unexpected behaviors of varargs in Java










13















I was reading this answer, where it says




Note also that calling a generic vararg method with an explicit array parameter may silently produce different behaviour than expected:



public <T> void foo(T... params) ... 
int arr = 1, 2, 3;
foo(arr); // passes an int array containing a single int element



Similar behavior is exaplained in this answer gotcha 3:




int myNumbers = 1, 2, 3 ;
System.out.println(ezFormat(myNumbers));
// prints "[ [I@13c5982 ]"


Varargs only works with reference types. Autoboxing does not apply to array of primitives. The following works:



Integer myNumbers = 1, 2, 3 ;
System.out.println(ezFormat(myNumbers));
// prints "[ 1 ][ 2 ][ 3 ]"



I tried simpler examples:



private static <T> void tVarargs(T ... s)

System.out.println("nntVarargs ==========");
System.out.println(s.getClass().getName());
System.out.println(s.length);
for(T i : s)
System.out.print(s + ",");


private static void objVarargs(Object ... a)

System.out.println("nnobjVarargs =========== ");
System.out.println(a.getClass().getName());
System.out.println(a.length);
for(Object i : a)
System.out.print(i + ",");


int intarr = 1,2,3;
Integer Intarr = 1,2,3;

objVarargs(intarr);
objVarargs(Intarr);

tVarargs(intarr);
tVarargs(Intarr);


This prints



objVarargs =========== 
[Ljava.lang.Object;
1
[I@7852e922,

objVarargs ===========
[Ljava.lang.Integer;
3
1,2,3,

tVarargs ==========
[[I
1
[[I@4e25154f,

tVarargs ==========
[Ljava.lang.Integer;
3
[Ljava.lang.Integer;@70dea4e,[Ljava.lang.Integer;@70dea4e,[Ljava.lang.Integer;@70dea4e,


  • Notice passing intarr to tVarargs results in creation of single 2 dimensional array [[I wit single element. However, what is the types of this array?

  • Also, passing intarr to objVarargs() results in creation of 1-D array [Ljava.lang.Object containing single array element.

  • For rest, it creates 1-D array with as many elements as passed - the desired behavior.

Can someone shed more light on first two behaviors? Are these two different behaviors or same behaviors, I mean having different or same reason behind them. What are those reasons, in depth? Is there any other cases resulting in different unexpected behavior?










share|improve this question






















  • I am not sure what is confusing you here. Type... is just Type but allows us to pass arguments of Type as list instead of wrapping it into array manually. <T> is limited to reference types only (it can't represent primitive type like int) which means T... as T can't be int. If you pass int array then most specific object type which T can use is array itself. So since T is now int T... is like int... which results in int (that is what [[I represents). Object... is simply Object array and that is what you see in other method

    – Pshemo
    Nov 13 '18 at 14:05
















13















I was reading this answer, where it says




Note also that calling a generic vararg method with an explicit array parameter may silently produce different behaviour than expected:



public <T> void foo(T... params) ... 
int arr = 1, 2, 3;
foo(arr); // passes an int array containing a single int element



Similar behavior is exaplained in this answer gotcha 3:




int myNumbers = 1, 2, 3 ;
System.out.println(ezFormat(myNumbers));
// prints "[ [I@13c5982 ]"


Varargs only works with reference types. Autoboxing does not apply to array of primitives. The following works:



Integer myNumbers = 1, 2, 3 ;
System.out.println(ezFormat(myNumbers));
// prints "[ 1 ][ 2 ][ 3 ]"



I tried simpler examples:



private static <T> void tVarargs(T ... s)

System.out.println("nntVarargs ==========");
System.out.println(s.getClass().getName());
System.out.println(s.length);
for(T i : s)
System.out.print(s + ",");


private static void objVarargs(Object ... a)

System.out.println("nnobjVarargs =========== ");
System.out.println(a.getClass().getName());
System.out.println(a.length);
for(Object i : a)
System.out.print(i + ",");


int intarr = 1,2,3;
Integer Intarr = 1,2,3;

objVarargs(intarr);
objVarargs(Intarr);

tVarargs(intarr);
tVarargs(Intarr);


This prints



objVarargs =========== 
[Ljava.lang.Object;
1
[I@7852e922,

objVarargs ===========
[Ljava.lang.Integer;
3
1,2,3,

tVarargs ==========
[[I
1
[[I@4e25154f,

tVarargs ==========
[Ljava.lang.Integer;
3
[Ljava.lang.Integer;@70dea4e,[Ljava.lang.Integer;@70dea4e,[Ljava.lang.Integer;@70dea4e,


  • Notice passing intarr to tVarargs results in creation of single 2 dimensional array [[I wit single element. However, what is the types of this array?

  • Also, passing intarr to objVarargs() results in creation of 1-D array [Ljava.lang.Object containing single array element.

  • For rest, it creates 1-D array with as many elements as passed - the desired behavior.

Can someone shed more light on first two behaviors? Are these two different behaviors or same behaviors, I mean having different or same reason behind them. What are those reasons, in depth? Is there any other cases resulting in different unexpected behavior?










share|improve this question






















  • I am not sure what is confusing you here. Type... is just Type but allows us to pass arguments of Type as list instead of wrapping it into array manually. <T> is limited to reference types only (it can't represent primitive type like int) which means T... as T can't be int. If you pass int array then most specific object type which T can use is array itself. So since T is now int T... is like int... which results in int (that is what [[I represents). Object... is simply Object array and that is what you see in other method

    – Pshemo
    Nov 13 '18 at 14:05














13












13








13


1






I was reading this answer, where it says




Note also that calling a generic vararg method with an explicit array parameter may silently produce different behaviour than expected:



public <T> void foo(T... params) ... 
int arr = 1, 2, 3;
foo(arr); // passes an int array containing a single int element



Similar behavior is exaplained in this answer gotcha 3:




int myNumbers = 1, 2, 3 ;
System.out.println(ezFormat(myNumbers));
// prints "[ [I@13c5982 ]"


Varargs only works with reference types. Autoboxing does not apply to array of primitives. The following works:



Integer myNumbers = 1, 2, 3 ;
System.out.println(ezFormat(myNumbers));
// prints "[ 1 ][ 2 ][ 3 ]"



I tried simpler examples:



private static <T> void tVarargs(T ... s)

System.out.println("nntVarargs ==========");
System.out.println(s.getClass().getName());
System.out.println(s.length);
for(T i : s)
System.out.print(s + ",");


private static void objVarargs(Object ... a)

System.out.println("nnobjVarargs =========== ");
System.out.println(a.getClass().getName());
System.out.println(a.length);
for(Object i : a)
System.out.print(i + ",");


int intarr = 1,2,3;
Integer Intarr = 1,2,3;

objVarargs(intarr);
objVarargs(Intarr);

tVarargs(intarr);
tVarargs(Intarr);


This prints



objVarargs =========== 
[Ljava.lang.Object;
1
[I@7852e922,

objVarargs ===========
[Ljava.lang.Integer;
3
1,2,3,

tVarargs ==========
[[I
1
[[I@4e25154f,

tVarargs ==========
[Ljava.lang.Integer;
3
[Ljava.lang.Integer;@70dea4e,[Ljava.lang.Integer;@70dea4e,[Ljava.lang.Integer;@70dea4e,


  • Notice passing intarr to tVarargs results in creation of single 2 dimensional array [[I wit single element. However, what is the types of this array?

  • Also, passing intarr to objVarargs() results in creation of 1-D array [Ljava.lang.Object containing single array element.

  • For rest, it creates 1-D array with as many elements as passed - the desired behavior.

Can someone shed more light on first two behaviors? Are these two different behaviors or same behaviors, I mean having different or same reason behind them. What are those reasons, in depth? Is there any other cases resulting in different unexpected behavior?










share|improve this question














I was reading this answer, where it says




Note also that calling a generic vararg method with an explicit array parameter may silently produce different behaviour than expected:



public <T> void foo(T... params) ... 
int arr = 1, 2, 3;
foo(arr); // passes an int array containing a single int element



Similar behavior is exaplained in this answer gotcha 3:




int myNumbers = 1, 2, 3 ;
System.out.println(ezFormat(myNumbers));
// prints "[ [I@13c5982 ]"


Varargs only works with reference types. Autoboxing does not apply to array of primitives. The following works:



Integer myNumbers = 1, 2, 3 ;
System.out.println(ezFormat(myNumbers));
// prints "[ 1 ][ 2 ][ 3 ]"



I tried simpler examples:



private static <T> void tVarargs(T ... s)

System.out.println("nntVarargs ==========");
System.out.println(s.getClass().getName());
System.out.println(s.length);
for(T i : s)
System.out.print(s + ",");


private static void objVarargs(Object ... a)

System.out.println("nnobjVarargs =========== ");
System.out.println(a.getClass().getName());
System.out.println(a.length);
for(Object i : a)
System.out.print(i + ",");


int intarr = 1,2,3;
Integer Intarr = 1,2,3;

objVarargs(intarr);
objVarargs(Intarr);

tVarargs(intarr);
tVarargs(Intarr);


This prints



objVarargs =========== 
[Ljava.lang.Object;
1
[I@7852e922,

objVarargs ===========
[Ljava.lang.Integer;
3
1,2,3,

tVarargs ==========
[[I
1
[[I@4e25154f,

tVarargs ==========
[Ljava.lang.Integer;
3
[Ljava.lang.Integer;@70dea4e,[Ljava.lang.Integer;@70dea4e,[Ljava.lang.Integer;@70dea4e,


  • Notice passing intarr to tVarargs results in creation of single 2 dimensional array [[I wit single element. However, what is the types of this array?

  • Also, passing intarr to objVarargs() results in creation of 1-D array [Ljava.lang.Object containing single array element.

  • For rest, it creates 1-D array with as many elements as passed - the desired behavior.

Can someone shed more light on first two behaviors? Are these two different behaviors or same behaviors, I mean having different or same reason behind them. What are those reasons, in depth? Is there any other cases resulting in different unexpected behavior?







java






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 13 '18 at 13:07









aniranir

423214




423214












  • I am not sure what is confusing you here. Type... is just Type but allows us to pass arguments of Type as list instead of wrapping it into array manually. <T> is limited to reference types only (it can't represent primitive type like int) which means T... as T can't be int. If you pass int array then most specific object type which T can use is array itself. So since T is now int T... is like int... which results in int (that is what [[I represents). Object... is simply Object array and that is what you see in other method

    – Pshemo
    Nov 13 '18 at 14:05


















  • I am not sure what is confusing you here. Type... is just Type but allows us to pass arguments of Type as list instead of wrapping it into array manually. <T> is limited to reference types only (it can't represent primitive type like int) which means T... as T can't be int. If you pass int array then most specific object type which T can use is array itself. So since T is now int T... is like int... which results in int (that is what [[I represents). Object... is simply Object array and that is what you see in other method

    – Pshemo
    Nov 13 '18 at 14:05

















I am not sure what is confusing you here. Type... is just Type but allows us to pass arguments of Type as list instead of wrapping it into array manually. <T> is limited to reference types only (it can't represent primitive type like int) which means T... as T can't be int. If you pass int array then most specific object type which T can use is array itself. So since T is now int T... is like int... which results in int (that is what [[I represents). Object... is simply Object array and that is what you see in other method

– Pshemo
Nov 13 '18 at 14:05






I am not sure what is confusing you here. Type... is just Type but allows us to pass arguments of Type as list instead of wrapping it into array manually. <T> is limited to reference types only (it can't represent primitive type like int) which means T... as T can't be int. If you pass int array then most specific object type which T can use is array itself. So since T is now int T... is like int... which results in int (that is what [[I represents). Object... is simply Object array and that is what you see in other method

– Pshemo
Nov 13 '18 at 14:05













1 Answer
1






active

oldest

votes


















5














These two behaviors result from the same issue - both generic type parameters and Object variables can only hold reference types. A primitive (such as int) is not a reference type, so passing an int array to a varargs method (and it doesn't matter if it's Object ... a or T ... s) results in the method accepting an array having a single element, and that single element is the int array.



Therefore you can consider it as a 2 dimensional int array (i.e. int) containing a single row.



Note that you have a typo in tVarargs(T ... s) which results in confusing output. It should be System.out.print(i + ",");, not System.out.print(s + ",");



Once you fix that, both methods produce the same output for the Integer input:



[Ljava.lang.Integer;
3
1,2,3,


The difference in the outputs for the int input results from the fact that in objVarargs(Object ... a), the type of the varargs array is Object, and in tVarargs(T ... s) it's T (and when T is an int, the type of the array is an int).



BTW, [[I is the class name of a two dimensional int array (i.e. int).






share|improve this answer
























    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53281688%2funderstanding-unexpected-behaviors-of-varargs-in-java%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    5














    These two behaviors result from the same issue - both generic type parameters and Object variables can only hold reference types. A primitive (such as int) is not a reference type, so passing an int array to a varargs method (and it doesn't matter if it's Object ... a or T ... s) results in the method accepting an array having a single element, and that single element is the int array.



    Therefore you can consider it as a 2 dimensional int array (i.e. int) containing a single row.



    Note that you have a typo in tVarargs(T ... s) which results in confusing output. It should be System.out.print(i + ",");, not System.out.print(s + ",");



    Once you fix that, both methods produce the same output for the Integer input:



    [Ljava.lang.Integer;
    3
    1,2,3,


    The difference in the outputs for the int input results from the fact that in objVarargs(Object ... a), the type of the varargs array is Object, and in tVarargs(T ... s) it's T (and when T is an int, the type of the array is an int).



    BTW, [[I is the class name of a two dimensional int array (i.e. int).






    share|improve this answer





























      5














      These two behaviors result from the same issue - both generic type parameters and Object variables can only hold reference types. A primitive (such as int) is not a reference type, so passing an int array to a varargs method (and it doesn't matter if it's Object ... a or T ... s) results in the method accepting an array having a single element, and that single element is the int array.



      Therefore you can consider it as a 2 dimensional int array (i.e. int) containing a single row.



      Note that you have a typo in tVarargs(T ... s) which results in confusing output. It should be System.out.print(i + ",");, not System.out.print(s + ",");



      Once you fix that, both methods produce the same output for the Integer input:



      [Ljava.lang.Integer;
      3
      1,2,3,


      The difference in the outputs for the int input results from the fact that in objVarargs(Object ... a), the type of the varargs array is Object, and in tVarargs(T ... s) it's T (and when T is an int, the type of the array is an int).



      BTW, [[I is the class name of a two dimensional int array (i.e. int).






      share|improve this answer



























        5












        5








        5







        These two behaviors result from the same issue - both generic type parameters and Object variables can only hold reference types. A primitive (such as int) is not a reference type, so passing an int array to a varargs method (and it doesn't matter if it's Object ... a or T ... s) results in the method accepting an array having a single element, and that single element is the int array.



        Therefore you can consider it as a 2 dimensional int array (i.e. int) containing a single row.



        Note that you have a typo in tVarargs(T ... s) which results in confusing output. It should be System.out.print(i + ",");, not System.out.print(s + ",");



        Once you fix that, both methods produce the same output for the Integer input:



        [Ljava.lang.Integer;
        3
        1,2,3,


        The difference in the outputs for the int input results from the fact that in objVarargs(Object ... a), the type of the varargs array is Object, and in tVarargs(T ... s) it's T (and when T is an int, the type of the array is an int).



        BTW, [[I is the class name of a two dimensional int array (i.e. int).






        share|improve this answer















        These two behaviors result from the same issue - both generic type parameters and Object variables can only hold reference types. A primitive (such as int) is not a reference type, so passing an int array to a varargs method (and it doesn't matter if it's Object ... a or T ... s) results in the method accepting an array having a single element, and that single element is the int array.



        Therefore you can consider it as a 2 dimensional int array (i.e. int) containing a single row.



        Note that you have a typo in tVarargs(T ... s) which results in confusing output. It should be System.out.print(i + ",");, not System.out.print(s + ",");



        Once you fix that, both methods produce the same output for the Integer input:



        [Ljava.lang.Integer;
        3
        1,2,3,


        The difference in the outputs for the int input results from the fact that in objVarargs(Object ... a), the type of the varargs array is Object, and in tVarargs(T ... s) it's T (and when T is an int, the type of the array is an int).



        BTW, [[I is the class name of a two dimensional int array (i.e. int).







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 13 '18 at 13:35

























        answered Nov 13 '18 at 13:14









        EranEran

        285k37463551




        285k37463551





























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53281688%2funderstanding-unexpected-behaviors-of-varargs-in-java%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Use pre created SQLite database for Android project in kotlin

            Darth Vader #20

            Ondo