Что не так с этим объявлением массива Java String - очень странно - PullRequest
3 голосов
/ 14 марта 2020

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

В первой версии method2 не работает, но method3 делает.

public class weirdStringArray {

    String [] method1 = new String [] {"one","two","three"}; //<------ Works no matter where it's placed

    String [] method2;       //<------ "Syntax error on token ";", { expected after this token"
    method2 = new String[3]; //  Doesn't work in this postion
    method2[0] = "one";
    method2[1] = "two";
    method2[2] = "three";

    String [] method3 = new String[3]; //<-------  No issue, works fine in this position
    method3[0] = "one";                
    method3[1] = "two";
    method3[2] = "three";
} // <----- Syntax error, insert "}" to complete ClassBody (but it does seem to complete ClassBody...?)

Но, поменяйте положение и поменяйте местами рабочие декларации. Посмотрите, теперь method2 работает, но method3 не работает.

public class weirdStringArray {

    String [] method1 = new String [] {"one","two","three"};

    String [] method3 = new String[3]; //<------ "Syntax error on token ";", { expected after this token"
    method3[0] = "one";               //  Doesn't work in this postion
    method3[1] = "two";
    method3[2] = "three";

    String [] method2; //<---------- Put it in a different place and it works
    method2 = new String[3]; 
    method2[0] = "one";
    method2[1] = "two";
    method2[2] = "three";

} // <----- Syntax error, insert "}" to complete ClassBody (but it does seem to complete ClassBody...?)

Что здесь может происходить? Почему заказ имеет значение? Что происходит в положении 2? Между прочим, не имеет значения, удаляю ли я первую рабочую форму:

public class weirdStringArray {

    //String [] method1 = new String [] {"one","two","three"};

    String [] method2;        //<------ "Syntax error on token ";", { expected after this token"
    method2 = new String[3]; //  Doesn't work in this postion 
    method2[0] = "one";
    method2[1] = "two";
    method2[2] = "three";

    String [] method3 = new String[3]; //<-------  No issue, works fine in this position
    method3[0] = "one";               
    method3[1] = "two";
    method3[2] = "three";

} // <----- Syntax error, insert "}" to complete ClassBody (but it does seem to complete ClassBody...?)

Ответы [ 6 ]

1 голос
/ 15 марта 2020

Попробуйте, чтобы все заработало так, как вы, возможно, и предполагали:

public class weirdStringArray {

    String [] method1 = new String [] {"one","two","three"}; //<-- Works no matter where it's placed, because this is a valid one line initialisation

    String [] method2;
    {
        // We gave it the '{' the compiler asked for …
        method2 = new String[3];
        method2[0] = "one";
        method2[1] = "two";
        method2[2] = "three";
    }

    String [] method3 = new String[3];
    {
        method3[0] = "one";                
        method3[1] = "two";
        method3[2] = "three";
    } // <-- … and this is the missing '}'
}

Эти блоки {…} являются блоками инициализации, более известны / чаще используются в их варианте c stati, как 'static {…}' для static final атрибутов. Это потому, что код в этих инициализаторах обычно лучше помещается в конструктор.

Преимущество использования этих инициализаторов состоит в том, что они выполняются перед всеми конструкторами, недостатком является то, что они выполняются перед все конструкторы. Лучше всего это проявляется, когда вы играете с final атрибутами ...

Они отлично работают для всех постоянных инициализаций, как в приведенном здесь примере, и для других типов (потенциально) никогда не заканчивающихся инициализаций. Вы должны избегать вызова нестати c методов отсюда, а вызов нестати c методов текущего класса вообще не работает (this еще не был инициализирован, поскольку вы сейчас его инициализируете…).

1 голос
/ 15 марта 2020

TL; DR: Переместить весь кодовый блок внутри функции; эта проблема перестала бы существовать немедленно.

Единственное, что вы можете сделать с переменной вне тела метода / функции, это инициализировать ее, но даже при этом вам нужно сделать это в той же строке, в которой вы объявили переменную. Вы сталкиваетесь с этой проблемой, потому что пытаетесь выполнять реальные операции вне функционального блока. Давайте рассмотрим каждый подход один за другим ...

Первый подход:

String [] method1 = new String [] {"one","two","three"};

Приведенный выше подход работает просто отлично, потому что вы выполняете объявление и инициализацию в в то же время. Здесь не нарушено ни одно правило.

Второй подход:

String [] method2;       //<------ "Syntax error on token ";", { expected after this token"
method2 = new String[3]; //  Doesn't work in this postion
method2[0] = "one";
method2[1] = "two";
method2[2] = "three";

Во второй строке вы выполняете операцию с переменной, которую вы объявили в предыдущей строке. Это не может быть сделано вне функции. Следовательно, ошибка.

Третий подход:

String [] method3 = new String[3]; //<-------  No issue, works fine in this position
method3[0] = "one";                
method3[1] = "two";
method3[2] = "three";

Ожидается, что этот третий пример будет работать хорошо. И вот почему: первая строка представляет допустимый способ объявления и инициализации переменной. Несмотря на то, что последующие строки являются инициализацией элементов массива, они по-прежнему считаются допустимыми способами инициализации переменных, поскольку элементы массива в этом контексте рассматриваются как независимые объекты.

Помните, что ключевым моментом здесь является обеспечение того, чтобы весь код после декларации был заключен в тело метода / функции.

1 голос
/ 14 марта 2020

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

public class weirdStringArray {
    String[] method1 = new String[] { "one", "two", "three" };

    {
        String[] method2;
        method2 = new String[3];
        method2[0] = "one";
        method2[1] = "two";
        method2[2] = "three";

        String[] method3 = new String[3];
        method3[0] = "one";
        method3[1] = "two";
        method3[2] = "three";

        String[] method4;
        method4 = new String[3];
        method4[0] = "one";
        method4[1] = "two";
        method4[2] = "three";
    }

    public static void main(String[] args) {
        String[] method2;
        method2 = new String[3];
        method2[0] = "one";
        method2[1] = "two";
        method2[2] = "three";

        String[] method3 = new String[3];
        method3[0] = "one";
        method3[1] = "two";
        method3[2] = "three";

        String[] method4;
        method4 = new String[3];
        method4[0] = "one";
        method4[1] = "two";
        method4[2] = "three";
    }
}

Этот код компилируется без проблем, потому что любой код, который я поместил вне метода, предназначен для инициализации. Если я удаляю границу {} из кода инициализации в теле класса, код не будет компилироваться. Проверьте Инициализация элементов экземпляра раздел для получения дополнительной информации.

1 голос
/ 14 марта 2020

Помимо его инициализации, вы просто не можете ничего сделать с экземпляром атрибута (независимо от того, является ли он массивом или чем-то еще), если он находится "вне" метода или конструктора. Вот что вы хотите сделать:

public class weirdStringArray {

    String[] method1 = new String[] {"one", "two", "three"};
    String[] method2 = new String[3];
    String[] method3 = new String[3];

    public weirdStringArray() {
        method2[0] = "one";
        method2[1] = "two";
        method2[2] = "three";
        method3[0] = "one";
        method3[1] = "two";
        method3[2] = "three";
    }

}

Или, альтернативно, вы можете использовать блоки инициализации:

public class weirdStringArray {

    // this way also works, it counts as initialization
    String[] method1 = {"one", "two", "three"};

    String[] method2 = new String[3];
    {
        method2[0] = "one";
        method2[1] = "two";
        method2[2] = "three";
    }

    String[] method3 = new String[3];
    {
        method3[0] = "one";
        method3[1] = "two";
        method3[2] = "three";
    }

}
1 голос
/ 14 марта 2020

Эти типы операторов не допускаются в телах классов. Сначала оберните их в тело метода.

0 голосов
/ 14 марта 2020

Вы должны поместить операцию присваивания значения в тело функции, если она не состоит из одной строки, как method2 и method3. Java не позволяет этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...