简体   繁体   中英

passing a String array as argument

A String array can be declared and initialized in the following way:

String[] str = {"A", "B"};

but for a method which accepts a String array as argument, why can't the same be used there?

For example: if in the code below, i replace the call to show() from show(str); to show({"A" "B"}); , it shows complier error. Why?

public class StringArray {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String[] str = {"A", "B"};
        show(str);
    }
    static void show(String[] s) {
        System.out.println(s[0] + s[1]);
    }
}

The compiler errors shown are:

StringArray.java:9: illegal start of expression
                show({"A", "B"});
                     ^
StringArray.java:9: ';' expected
                show({"A", "B"});
                      ^
StringArray.java:9: illegal start of expression
                show({"A", "B"});
                         ^
StringArray.java:9: ';' expected
                show({"A", "B"});
                          ^
StringArray.java:9: illegal start of type
                show({"A", "B"});
                               ^
StringArray.java:11: class, interface, or enum expected
        static void show(String[] s) {
               ^
StringArray.java:13: class, interface, or enum expected
        }
        ^
7 errors

Also using show(new String[] {"A", "B"}); is allowed. How is new String[]{"A", "B"} different from {"A", "B"} when passing them as method arguments? Thanx in advance!

The syntax {"A", "B"} (without new String[] in front of it) can only be used as an array initializer expression. In all other contexts (including method calls), you need to use the new operator.

See the Java Tutorial on Arrays for more info.

String[] str = {"A", "B"}; is minified version of String[] str = new String[]{"A", "B"}; , Compiler doesn't know about plain {"A", "B"} as a string array unless you explicitly mention.

Short Answer

It has everything to do with memory management.


Long Answer

Background :

There is another question about passing arrays as arguments (marked as a duplicate) that is asking about the same behavior but is interested in a deeper 'why'.

Other answers have correctly explained the difference between

A)

new String[]{"A", "B"} 

and

B)

{"A", "B"} 

when passing them as method arguments.

A) constructs an instance of an array on the heap and the expression results in a reference to the instance.

B) is the syntax to define an array but that syntax is only valid during the initialization of a local array variable. This syntax is not an expression that can be evaluated by itself, it expects there to be an array already instantiated but uninitialized where this block is then used as the initializer.

Blame it on Java

All this has already been mentioned, so what I'd like to answer is the why behind the language design decision that puts this behavior in place.

One of the basic tenets of Java is that it manages memory to really minimize the huge problems that introduces when each programmer has to understand all the ins and outs, all the edge cases with dynamic memory management. So, when they designed the language's type system they would have liked to have every variable be a reference type but for efficiency they allowed some basic types that can be passed by value as an argument to a method, where the result is a simple clone of the contents of the variable, these are called primitive types, int, char, etc. All other types require a reference to the heap, which allows for good efficiency in parameter passing, these are called reference types. Reference types, as the name implies, are actually a reference to memory that has been allocated usually on the heap but can be memory on the stack.

Array Initializers

Ok, that's it for the Java Primer, but why is that important? It's because when you attempt to pass an array as in argument but use the literal syntax, the language expects a reference type but the array initializer construct does not resolve to a reference.

Now, the next question might be whether it would have been possible for the compiler to take the initializer syntax and transform it into a properly allocated instance of an array. That would be a fair question. The answer goes back to the the syntax that uses the initializer clause:

String[] str = {"A", "B"}

If you only have the expression on the right-hand-side of the equals sign, how do you know what type of array should be constructed? The simple answer is you don't. If we took that same initializer and used it like this

Circle[] cir = {"A", "B"}

it becomes more clear why this is the case. First you might notice the 'new' keyword seems to be missing. It's not missing but is implicitly being included by the compiler. This is because the initializer syntax is a short form of the following code

Circle[2] cir = new Circle[]();
cir[0] = new Circle("A");
cir[1] = new Circle("B");

The compiler uses the constructor for the array variable to instantiate each element of the array based on the list provided, So when you try to pass

{"A", "B"}

the compiler has no information about what type of array should be constructed nor does it know how to construct the individual elements of the array, hence the need to use the form that explicitly allocates memory.

For the Student of Languages

This separation between the type of the reference and the type of each element of the array is also what allows the array type to be a parent type of the elements, such as

Circle[2] shapes = new Circle[]();
shapes[0] = new Circle();  // parent
shapes[1] = new Ellipse(); // child of Circle 

and Java's use of a parent class, Object for all classes allows arrays with completely unrelated objects

Object[2] myThings = new Object[]();
myThings[0] = new Car();  
myThings[1] = new Guitar(); // unrelated object

When you pass {"A", "B"}, there is no object referencing to it because that array is not yet created in memory and that reference is needed to be passed. But we can pass a string like "A" directly [without a reference] to a method accepting String, because String is java's special object for which String pool is maintained. and that is not the case with array which is like simple java object.

Since String[] str = {"A", "B"}; defines that it is an array of strings, {"A", "B"} nowhere says this is an array of string as an array of objects could be defined like that too, thus compiler doesn't know what type of array you are referring to :)

It works if you do it like this

public class StringArray 
{

    /**
     * @param args
     */
    public static void main(String[] args) 
    {
        show(new String[]{"A", "B"});
    }
    static void show(String[] s)
    {
        System.out.println(s[0] + s[1]);
    }
}

because you are actually creating a new array "object". The other way, {"A", "B"} doesn't mean anything. {"A", "B"} isn't an array object, so it won't work. The first way works because you are actually specifying that what is being passed to the function is an array object.

show({"A" "B"}); this expression is not passing array object. Passing array object You have to first declare and intialize the array object then passing array reference into method.

String[] str = {"A", "B"}; show(str);

OR

String[] str = {"A", "B"}; show(new String[]{"A", "B"});

In the above example, the signature of the show() method guides the compiler that it is expecting a String reference at the time of calling, thus we can pass only a reference variable of type String while calling the show() method. On the other hand {"A","B"} is just an expression not a reference that's why it is giving a compilation error like "Illegal Start of Expression".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM