可以通过以下方式声明和初始化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"}
与{{1}}有什么不同?
Thanx提前!
答案 0 :(得分:12)
语法{"A", "B"}
(前面没有new String[]
)只能用作数组初始化表达式。在所有其他上下文(包括方法调用)中,您需要使用new
运算符。
有关详细信息,请参阅Java Tutorial on Arrays。
答案 1 :(得分:6)
String[] str = {"A", "B"};
是String[] str = new String[]{"A", "B"};
的缩小版本,除非您明确提及,否则编译器不会将普通{"A", "B"}
知道为字符串数组。
答案 2 :(得分:1)
当您传递{“A”,“B”}时,没有对象引用它,因为该数组尚未在内存中创建,并且需要传递该引用。 但是我们可以直接[没有引用]将类似“A”的字符串传递给接受String的方法,因为String是java的特殊对象,为其维护字符串池。而数组就不像简单的java对象那样。
答案 3 :(得分:1)
它与内存管理有关。
背景:
有another question about passing arrays as arguments(标记为重复)询问相同的行为,但对更深层的'为什么'感兴趣。
Other answers已正确解释了
之间的区别A)
new String[]{"A", "B"}
和
B)
{"A", "B"}
将它们作为方法参数传递时。
A)在堆上构造一个数组实例,表达式导致对该实例的引用。
B)是定义数组的语法,但该语法仅在本地数组变量的初始化期间有效。这个语法不是一个可以自己计算的表达式,它期望有一个数组已经实例化但未初始化,然后将该块用作初始化器。
所有这些都已经提到了,所以我想回答的是语言设计决策背后的原因。
Java的基本原则之一是它管理内存以真正最小化每个程序员必须了解所有细节时所引入的巨大问题,所有边缘情况都采用动态内存管理。因此,当他们设计语言的类型系统时,他们希望将每个变量都作为引用类型,但为了提高效率,它们允许一些基本类型可以通过值作为参数传递给方法,其中结果是一个简单的克隆变量的内容,这些被称为基本类型,int,char等。所有其他类型都需要对堆的引用,这允许参数传递的良好效率,这些被称为引用类型。顾名思义,引用类型实际上是对通常在堆上分配但可以是堆栈上的内存的内存的引用。
好的,那就是Java Primer,但为什么这很重要?这是因为当您尝试按参数传递数组但使用文字语法时,语言需要引用类型,但数组初始化程序构造不会解析为引用。
现在,下一个问题可能是编译器是否可能采用初始化器语法并将其转换为正确分配的数组实例。这将是一个公平的问题。答案可以追溯到使用初始化子句的语法:
String [] str = {“A”,“B”}
如果你只在等号的右边有表达式,你怎么知道应该构造什么类型的数组?简单的答案是你没有。如果我们采用相同的初始化程序并像这样使用它
Circle[] cir = {"A", "B"}
更清楚为什么会出现这种情况。首先你可能会注意到'new'关键字似乎缺失了。它不会丢失,但隐含地被编译器包含在内。这是因为初始化器语法是以下代码的简短形式
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
答案 4 :(得分:0)
由于String[] str = {"A", "B"};
定义它是一个字符串数组,{"A", "B"}
没有地方说这是一个字符串数组,因为对象数组也可以这样定义,因此编译器不知道是什么您所指的数组类型:)
答案 5 :(得分:0)
如果你这样做的话,它会起作用
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”}不是数组对象,因此不起作用。第一种方法有效,因为您实际上指定传递给函数的是一个数组对象。
答案 6 :(得分:0)
show({“A”“B”});这个表达式没有传递数组对象。传递数组对象您必须先声明并初始化数组对象,然后将数组引用传递给方法。
String [] str = {“A”,“B”}; 显示(STR);
OR
String [] str = {“A”,“B”}; show(new String [] {“A”,“B”});
答案 7 :(得分:0)
在上面的例子中,show()方法的签名引导编译器在调用时期望String引用,因此我们只能在调用show()方法时传递String类型的引用变量。另一方面,{“A”,“B”}只是一个表达而不是引用,这就是为什么它会给出像“非法表达式开始”这样的编译错误。