传递String数组作为参数

可以通过以下方式声明和初始化String数组:

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

但是对于一个接受String数组作为参数的方法,为什么不能在那里使用它?

例如:如果在下面的代码中,我将show(str);替换为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"}在将它们作为方法参数传递时如何与new String[]{"A", "B"}不同? Thanx提前!

语法{"A", "B"} (前面没有new String[] )只能用作数组初始化表达式。 在所有其他上下文(包括方法调用)中,您需要使用new运算符。

有关详细信息,请参阅arrays中的Java教程 。

String[] str = {"A", "B"};String[] str = new String[]{"A", "B"};缩小版本String[] str = new String[]{"A", "B"}; 除非你明确提到,否则编译器不会将plain {"A", "B"}知道为字符串数组。

当您传递{“A”,“B”}时,没有对象引用它,因为该数组尚未在内存中创建,并且需要传递该引用。 但是我们可以直接[没有引用]将类似“A”的字符串传递给接受String的方法,因为String是java的特殊对象,为其维护字符串池。 而这与数组的情况不同,就像简单的java对象一样。

简答

它与内存管理有关。


答案很长

背景

关于将数组作为参数传递 (标记为重复)还有另一个问题 ,即询问相同的行为但是对更深层的“为什么”感兴趣。

其他答案正确解释了它们之间的区别

一个)

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

B)

 {"A", "B"} 

将它们作为方法参数传递时。

A)在堆上构造数组的实例,表达式导致对实例的引用。

B)是定义数组的语法,但该语法仅在本地数组变量的初始化期间有效。 这个语法不是一个可以自己计算的表达式,它期望有一个数组已经实例化但未初始化,然后将该块用作初始化器。

归咎于Java

所有这些都已经提到了,所以我想回答的是语言设计决策背后的原因。

Java的基本原则之一是它管理内存以真正最小化当每个程序员必须理解所有细节时引入的巨大问题,所有边缘情况都采用动态内存管理。 因此,当他们设计语言的类型系统时,他们希望将每个变量都作为引用类型,但为了提高效率,它们允许一些基本类型可以通过值作为方法的参数传递,其中结果是一个简单的克隆变量的内容,这些被称为基本类型,int,char等。所有其他类型都需要对堆的引用,这允许参数传递的良好效率,这些被称为引用类型。 顾名思义,引用类型实际上是对通常在堆上分配的内存的引用,但可以是堆栈上的内存。

数组初始化器

好吧,那就是Java Primer,但为什么这很重要? 这是因为当您尝试按参数传递数组但使用文字语法时,语言需要引用类型,但数组初始化程序构造不会解析为引用。

现在,下一个问题可能是编译器是否可以采用初始化器语法并将其转换为正确分配的数组实例。 这将是一个公平的问题。 答案可以追溯到使用initializer子句的语法:

String [] str = {“A”,“B”}

如果你只在等号的右边有表达式,你怎么知道应该构造什么类型的数组? 简单的答案是你没有。 如果我们采用相同的初始化程序并像这样使用它

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

更清楚的是为什么会这样。 首先你可能会注意到’new’关键字似乎缺失了。 它不会丢失,但隐含地被编译器包含在内。 这是因为初始化器语法是以下代码的简短forms

 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 

由于String[] str = {"A", "B"}; 定义它是一个字符串数组, {"A", "B"}没有地方说这是一个字符串数组,因为对象数组也可以这样定义,因此编译器不知道你是什么类型的数组指的是:)

如果你这样做,它的工作原理

 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”}不是数组对象,因此不起作用。 第一种方法有效,因为您实际上指定传递给函数的是一个数组对象。

show({“A”“B”}); 这个表达式没有传递数组对象。 传递数组对象您必须先声明并初始化数组对象,然后将数组引用传递给方法。

String [] str = {“A”,“B”}; 显示(STR);

要么

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

在上面的例子中,show()方法的签名引导编译器在调用时期望String引用,因此我们只能在调用show()方法时传递String类型的引用变量。 另一方面,{“A”,“B”}只是一个表达而不是引用,这就是为什么它会给出像“非法表达式开始”这样的编译错误。