Передача массива String в качестве аргумента

Строковый массив может быть объявлен и инициализирован следующим образом:

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

но для метода, который принимает массив String в качестве аргумента, почему его нельзя использовать там?

Например: если в приведенном ниже коде я заменяю вызов show() от show(str); до show({"A" "B"});, он показывает ошибку-совместимость. Почему?

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]);
    }
}

Показанные ошибки компилятора:

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

Также допускается использование show(new String[] {"A", "B"});. Как new String[]{"A", "B"} отличается от {"A", "B"} при передаче их в качестве аргументов метода? Thanx заранее!

Ответ 1

Синтаксис {"A", "B"} (без new String[] перед ним) может использоваться только как выражение инициализатора массива. Во всех других контекстах (включая вызовы методов) вам нужно использовать оператор new.

Дополнительную информацию см. в Учебном пособии по Java на массивах.

Ответ 2

String[] str = {"A", "B"}; является сокращенной версией String[] str = new String[]{"A", "B"};, компилятор не знает о plain {"A", "B"} как массив строк, если вы явно не упоминаете.

Ответ 3

Когда вы передаете { "A", "B" }, нет объекта, ссылающегося на него, потому что этот массив еще не создан в памяти и эта ссылка необходима для передачи. Но мы можем передать строку типа "A" непосредственно [без ссылки] методу, принимающему String, потому что String является специальным объектом java, для которого поддерживается String-пул. и это не относится к массиву, который похож на простой Java-объект.

Ответ 4

Краткий ответ

Он имеет все, что связано с управлением памятью.


Длинный ответ

Фон:

Существует еще один вопрос о передаче массивов в качестве аргументов (помечен как дубликат), который спрашивает о том же поведении, но заинтересован в более глубоком "почему".

Другие ответы правильно объяснили разницу между

A)

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

и

B)

{"A", "B"} 

при передаче их в качестве аргументов метода.

A) создает экземпляр массива в куче, и выражение приводит к ссылке на экземпляр.

B) является синтаксисом для определения массива, но этот синтаксис действителен только во время инициализации локальной переменной массива. Этот синтаксис не является выражением, которое может быть оценено само по себе, он ожидает, что будет уже создан массив, но не инициализирован, где этот блок затем используется как инициализатор.

Назовите его на Java

Все это уже упоминалось, поэтому я хотел бы ответить, почему решение, принятое в языковом дизайне, ставит это поведение на место.

Одним из основных принципов Java является то, что он управляет памятью, чтобы действительно минимизировать огромные проблемы, которые возникают, когда каждый программист должен понимать все входы и выходы, все крайние случаи с динамическим управлением памятью. Таким образом, когда они разрабатывали систему типов языков, они хотели бы, чтобы каждая переменная была ссылочным типом, но для эффективности они допускали некоторые базовые типы, которые могут передаваться по значению в качестве аргумента для метода, где результат представляет собой простой клон содержимое переменной, они называются примитивными типами, int, char и т.д. Все остальные типы требуют ссылки на кучу, что обеспечивает хорошую эффективность при передаче параметров, они называются ссылочными типами. Типы ссылок, как следует из названия, на самом деле являются ссылкой на память, которая была распределена обычно в куче, но может быть памятью в стеке.

Инициализаторы массива

Хорошо, что это для Java Primer, но почему это важно? Это потому что, когда вы пытаетесь передать массив как аргумент, но используете синтаксис literal, язык ожидает ссылочного типа, но конструктор инициализатора массива не разрешает ссылку.

Теперь следующий вопрос может заключаться в том, возможно ли компилятору взять синтаксис инициализатора и преобразовать его в правильно выделенный экземпляр массива. Это был бы справедливый вопрос. Ответ возвращается к синтаксису, который использует предложение initializer:

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

Если у вас есть только выражение в правой части знака равенства, как вы знаете, какой тип массива должен быть сконструирован? Простой ответ: нет. Если бы мы взяли тот же самый инициализатор и использовали его как это

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

становится понятнее, почему это так. Во-первых, вы можете заметить, что ключевое слово "новое" кажется отсутствующим. Он не пропущен, но неявно включается компилятором. Это связано с тем, что синтаксис инициализатора является короткой формой следующего кода

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

Компилятор использует конструктор для переменной массива для создания экземпляра каждого элемента массива на основе предоставленного списка. Поэтому, когда вы пытаетесь передать

{"A", "B"}

у компилятора нет информации о том, какой тип массива должен быть построен, и он не знает, как построить отдельные элементы массива, следовательно, необходимо использовать форму, которая явно выделяет память.

Для студента языков

Это разделение между типом ссылки и типом каждого элемента массива также является тем, что позволяет типу массива быть родительским типом элементов, например

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

и использование Java родительского класса Object для всех классов позволяет массивы с полностью несвязанными объектами

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

Ответ 5

Так как String[] str = {"A", "B"}; определяет, что это массив строк, {"A", "B"} нигде не говорит, что это массив строки, так как массив объектов может быть определен так же, поэтому компилятор не знает, какой тип массива вы ссылаются на:)

Ответ 6

Он работает, если вы делаете это как

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]);
    }
}

потому что вы на самом деле создаете новый "объект" массива. Другой способ: { "A", "B" } ничего не значит. { "A", "B" } не является объектом массива, поэтому он не будет работать. Первый способ работает, потому что вы на самом деле указываете, что то, что передается функции, является объектом массива.

Ответ 7

show ({ "A" "B" }); это выражение не передает объект массива. Передача объекта массива Вы должны сначала объявить и инициализировать объект массива, а затем передать ссылку на массив в метод.

String [] str = { "A", "B" }; шоу (ул);

ИЛИ

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

Ответ 8

В приведенном выше примере сигнатура метода show() направляет компилятор, что он ожидает ссылки на String во время вызова, поэтому мы можем передать только ссылочную переменную типа String при вызове метода show(), С другой стороны, { "A", "B" } является просто выражением, а не ссылкой, почему он дает ошибку компиляции, например "Незаконный запуск выражения".