这个Java字符串数组声明有什么问题 - 非常奇怪。

3

我有三种不同的方法来声明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...?)

这里可能会发生什么?为什么顺序会有关系?第二个位置发生了什么?顺便提一下,如果我删除第一个有效的表单,也不会有任何影响。
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...?)

1
这只是对Java工作原理的误解。除了实例化代码之外,您不能在类体内放置随机代码,大多数逻辑必须放在方法中。 - Óscar López
6个回答

1
除了初始化之外,如果实例属性(无论是数组还是其他类型)在方法或构造函数之外,你就不能对其进行任何操作。这是你想要做的:
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";
    }

}

非常感谢,这真的很有帮助。但是为什么第一个版本能够工作呢?看起来我在这一行中做了更多的事情,不仅仅是初始化数组? - user7390817
@user7390817 第一个版本能够工作是因为你在单行中实例化了对象 - 是的,它仅仅是用一些给定的值初始化了数组。换句话说:除了声明和初始化属性的单行之外,任何其他行都必须放在其他地方。可以是构造函数、初始化块或方法中。 - Óscar López

1
请注意,除了实例化之外,您不能在类的主体中放置代码。请查看以下示例代码:
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

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

尝试以下方法,以使它按照您的意图正常工作:

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 '}'
}

这些“{...}”块是初始化块,更常用的是它们的静态变量形式,“static {...}”,用于静态final属性。这是因为这些初始化器中的代码通常最好放在构造函数中。
使用这些初始化器的优点是它们在所有构造函数之前执行,缺点是它们在所有构造函数之前执行。当您尝试使用final属性时会更容易看出来...
它们适用于所有常量初始化,例如此处的示例以及其他类型的(潜在)不会失败的初始化。应避免从这里调用非静态方法,并且根本无法调用当前类的非静态方法(因为您正在初始化它,而此时“this”尚未初始化...)。

1

这种类型的语句不允许在类体中出现。请先将它们包装在方法体中。


0

如果赋值操作不像method2和method3那样只有一行,你应该将其放在函数体中。Java不允许这样做。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接