你的setData(String[] goodsName1,double[] goodsPrice1,int[] custNo1,String[] custBirth1,int[] custScore1)方法在你的第一个类中,所以,要在别的类中调用这个方法的话,就要new一个这个类对象,通过对象调用这个方法, 假设你的第一个类的名字为First,First first=new First();first.setDate(这里是你对应的参数);这样就可以了.但是,因为你这个setData(String[] goodsName1,double[] goodsPrice1,int[] custNo1,String[] custBirth1,int[] custScore1)前面有关static关键字,你也可以直接用你的第一个类的类名直接调用这个方法. 假设你的第一个类的名字为First;First.setData(这里是你对应的参数);这样就可以了.  有一点不是那么令人满意的地方是,在很多情况下,你要传递的数字已经存储在数组里,或是至少是在某些集成的形式中:

//用这种方法来取得数字

int[] numbers = getListOfNumbers( );

要把这些数字传递给max()方法是不可能的。你需要检查list的长度,从中截取掉第一个对象(如果存在第一个对象的话),然后检查类型来确保是int型。完成了这些,你才可以带着数组中剩余的部分一起传递进入方法。而这数组中剩余的部分还要重复,或者要人工地转化为适合的格式。总之,这个过程会很辛苦,你需要做许多琐碎的事情。仔细想想,你要记得编译器是将这个方法解释为下面的语句:public static int max(int first, int[] rest)

所以,你可以做些调整,把max()方法改写成下面这个样子:

public static int max(int... values) {
int max = Integer.MIN_VALUE;
for (int i : values) {
if (i > max)
max = i;
}
return

你现在已经定义了一个可以很容易接受数组的方法。

//用这种方法来取得数字
int[] numbers = getListOfNumbers( );
int max = MathUtils.max(numbers);

当接受单一的可变长度参数时,你使用这种方法会很简单。但是,如果在最好的情况下,你传递了一个零长度的数组进去,这就会带来问题,你会得到难以预料的结果。为了解决这个问题,你需要一个小的错误检查。例5-3是MathUtils类的完整代码列表,在这里是一个功能更强的MathUtil类。

例5-3 处理零参数的方法

package com.oreilly.tiger.ch05;
public class MathUtils {
public static int max(int... values) {
if (values.length == 0) {
throw new IllegalArgumentException("No values supplied.");
}

任何时候,你都可能会要处理零长度的参数列表,这时你就需要执行这类的错误检查。通常,一个功能强大的IllegalArgumentException类是一个好的选择。

int max = Integer.MIN_VALUE;
for (int i : values) {
if (i > max)
max = i;
}
return max;
}
}

那么关于调用同样的方法来处理通常参数不是数组的方法,又会如何呢?这当然是完全合法的。下面的代码都是合法调用max()方法的手段:

int max = MathUtils.max(myArray);
int max = MathUtils.max(new int[] { 2, 4, 6, 8 });
int max = MathUtils.max(2, 4, 6, 8);
int max = MathUtils.max(0);
int max = MathUtils.max( );

指定对象参数,而非基本类型

在第四章中我们谈到,Tiger通过拆箱增加了一系列的新特征。你可以在处理可变参数时,在你的方法接受的参数中使用对象包装类。

如何实现?

你一定记得在Java中所有的类最终都是java.lang.Object的子类。这就意味着任何对象可以被转化成一个Object对象。更进一步说,因为像int和short这样的基本类型会自动转化成他们对应的对象包装类(就像Integer和Short),任何Java类型可以被转化成一个Object对象。

所以,如果你需要你的可变参数方法可以接受最多种参数的类型,那么你可以将Object类型作为参数的类型。更好的是,为了达到多重功能,绝大多数情况下都会使用Object对象。例如,写个用来打印方法。

private String print(Object... values) {
StringBuilder sb = new StringBuilder( );
for (Object o : values) {
sb.append(o)
.append(" ");
}
return sb.toString( );
}

这儿最简单的意思是打印出所有的东西。然而,这个方法更通用的定义是下面的样子:

private String print(String... values) {
StringBuilder sb = new StringBuilder( );
for (Object o : values) {
sb.append(o)
.append(" ");
}
return sb.toString( );
}

这个方法的问题是方法自身不能接受字符串,整数,浮点数,数组和其他的类型数据,而这些数据你都想要正常的打印出来。通过使用Object这个更为通用的类型,你可以来打印所有的一切。

private String print(Object... values) {
StringBuilder sb = new StringBuilder( );
for (Object o : values) {
sb.append(o)
.append(" ");
}
return sb.toString( );
}

避免数组自动转化

Tiger增加了各种类型的自动转化和便利,这些东西在绝大多数的情况下是很好用的。不幸的是,有些时候所有的这些东西会变成你的障碍。其中一种情况是,在可变参数方法中将多个Object对象转化为Object[]数组对象,你会发现在个别的情况下,你需要用Java来书写。

如何实现?

在将要仔细讨论这件事情前,你要确信自己理解这个问题。Java新的printf()方法是一个很好的便利,举这个方法作个例子:

System.out.printf("The balance of %s's account is $%(,6.2f\n",account.getOwner()。getFullName( ),account.getBalance( ));

如果你看一下Java文档中关于printf()方法的说明,你就会看到它是一个可变参数的方法。它有两个参数:一个是用于设置字符串格式的String类型变量,另一个是所有要传递进字符串的Object对象:

PrintStream printf(String format, Object…… args)

现在,你可以把上面的代码默认为下面的形式:

PrintStream printf(String format, Object[] args)

两种书写是不是完全相同呢?大多数情况下是相同的。考虑一下下面的代码:

Object[] objectArray = getObjectArrayFromSomewhereElse( );out.printf("Description of object array: %s\n", obj);

这是乎有点牵强,然而要把它看作是为了自省的代码而付出的正常开销。比起其它代码,这样写要简洁的多。如果你正在编写一个代码分析工具,或者一个集成开发环境,或者其他可能使用reflection或简单API来判断出应用程序会需要何种对象的东西,这些马上会成为一个通用的案例。这儿,你不是真正关心对象数组的内容,就像你同样不会去关心数组自身一样。它是什么类型?它的内存地址是多少?它的字符串代表什么意思?请紧记所有这些问题都是和数组本身有关的,和数组的内容无关。例如:我们来看看下面的数组代码:

public Object[] getObjectArrayFromSomewhereElse( ) {return new String[] {"Hello", "to", "all", "of", "you"};}

在这种情况下,你肯能会写一些像下面一样的代码来回答某些关于数组的问题:

out.printf("Description of object array: %s\n", obj);

然而,输出结果并不是你所期望的那样:

run-ch05:[echo] Running Chapter 5 examples from Java Tiger: A Developer's Notebook[echo] Running VarargsTester……[java] Hello

这倒是怎么回事?这就不是你想看到的结果。然而,编译器做了它应该做的,它把在printf()方法里的Object……转换为Object[].实际上,当编译器得到你方法的调用时,它看到的参数是Object[].所以编译器不是把这个数组看作一个Object对象本身,而是把它分成不同的部分。这样被传递给字符串格式 (%s)的就是第一个参数部分“Hello”字符串,所以结果“Hello”就显示出来了。

仔细看看这件事,你需要去告诉编译器你要把整个对象数组obj看作是一个简单的对象,而不是一组参数。请看下面奇特的代码:

out.printf("Description of object array: %s\n", new Object[] { obj });

作为选择,还有一种更为简单的方法:

out.printf("Description of object array: %s\n", (Object)obj);

在上面两种书写情况下,编译器不再认为是对象的数组,而是直接认为是一个简单的Object对象,而这个Object对象又恰好是一个对象数组。那么结果就如你所愿(至少在这种简单的应用下):

run-ch05:[echo] Running Chapter 5 examples from Java Tiger: A Developer's Notebook[echo] Running VarargsTester……[java] [Ljava.lang.String;@c44b88

有一点不是那么令人满意的地方是,在很多情况下,你要传递的数字已经存储在数组里,或是至少是在某些集成的形式中:

//用这种方法来取得数字
int[] numbers = getListOfNumbers( );

要把这些数字传递给max()方法是不可能的。你需要检查list的长度,从中截取掉第一个对象(如果存在第一个对象的话),然后检查类型来确保是int型。完成了这些,你才可以带着数组中剩余的部分一起传递进入方法。而这数组中剩余的部分还要重复,或者要人工地转化为适合的格式。总之,这个过程会很辛苦,你需要做许多琐碎的事情。仔细想想,你要记得编译器是将这个方法解释为下面的语句:public static int max(int first, int[] rest)

所以,你可以做些调整,把max()方法改写成下面这个样子:

public static int max(int... values) {
int max = Integer.MIN_VALUE;
for (int i : values) {
if (i > max)
max = i;
}
return

你现在已经定义了一个可以很容易接受数组的方法。

//用这种方法来取得数字
int[] numbers = getListOfNumbers( );
int max = MathUtils.max(numbers);

当接受单一的可变长度参数时,你使用这种方法会很简单。但是,如果在最好的情况下,你传递了一个零长度的数组进去,这就会带来问题,你会得到难以预料的结果。为了解决这个问题,你需要一个小的错误检查。例5-3是MathUtils类的完整代码列表,在这里是一个功能更强的MathUtil类。

例5-3 处理零参数的方法

package com.oreilly.tiger.ch05;
public class MathUtils {
public static int max(int... values) {
if (values.length == 0) {
throw new IllegalArgumentException("No values supplied.");
}

任何时候,你都可能会要处理零长度的参数列表,这时你就需要执行这类的错误检查。通常,一个功能强大的IllegalArgumentException类是一个好的选择。

int max = Integer.MIN_VALUE;
for (int i : values) {
if (i > max)
max = i;
}
return max;
}
}

那么关于调用同样的方法来处理通常参数不是数组的方法,又会如何呢?这当然是完全合法的。下面的代码都是合法调用max()方法的手段:

int max = MathUtils.max(myArray);
int max = MathUtils.max(new int[] { 2, 4, 6, 8 });
int max = MathUtils.max(2, 4, 6, 8);
int max = MathUtils.max(0);
int max = MathUtils.max( );

指定对象参数,而非基本类型

在第四章中我们谈到,Tiger通过拆箱增加了一系列的新特征。你可以在处理可变参数时,在你的方法接受的参数中使用对象包装类。

如何实现?

你一定记得在Java中所有的类最终都是java.lang.Object的子类。这就意味着任何对象可以被转化成一个Object对象。更进一步说,因为像int和short这样的基本类型会自动转化成他们对应的对象包装类(就像Integer和Short),任何Java类型可以被转化成一个Object对象。

所以,如果你需要你的可变参数方法可以接受最多种参数的类型,那么你可以将Object类型作为参数的类型。更好的是,为了达到多重功能,绝大多数情况下都会使用Object对象。例如,写个用来打印方法。

private String print(Object... values) {
StringBuilder sb = new StringBuilder( );
for (Object o : values) {
sb.append(o)
.append(" ");
}
return sb.toString( );
}

这儿最简单的意思是打印出所有的东西。然而,这个方法更通用的定义是下面的样子:

private String print(String... values) {
StringBuilder sb = new StringBuilder( );
for (Object o : values) {
sb.append(o)
.append(" ");
}
return sb.toString( );
}

这个方法的问题是方法自身不能接受字符串,整数,浮点数,数组和其他的类型数据,而这些数据你都想要正常的打印出来。通过使用Object这个更为通用的类型,你可以来打印所有的一切。

private String print(Object... values) {
StringBuilder sb = new StringBuilder( );
for (Object o : values) {
sb.append(o)
.append(" ");
}
return sb.toString( );
}

避免数组自动转化

Tiger增加了各种类型的自动转化和便利,这些东西在绝大多数的情况下是很好用的。不幸的是,有些时候所有的这些东西会变成你的障碍。其中一种情况是,在可变参数方法中将多个Object对象转化为Object[]数组对象,你会发现在个别的情况下,你需要用Java来书写。

如何实现?

在将要仔细讨论这件事情前,你要确信自己理解这个问题。Java新的printf()方法是一个很好的便利,举这个方法作个例子:

System.out.printf("The balance of %s's account is $%(,6.2f\n",account.getOwner()。getFullName( ),account.getBalance( ));

如果你看一下Java文档中关于printf()方法的说明,你就会看到它是一个可变参数的方法。它有两个参数:一个是用于设置字符串格式的String类型变量,另一个是所有要传递进字符串的Object对象:

PrintStream printf(String format, Object…… args)

现在,你可以把上面的代码默认为下面的形式:

PrintStream printf(String format, Object[] args)

两种书写是不是完全相同呢?大多数情况下是相同的。考虑一下下面的代码:

Object[] objectArray = getObjectArrayFromSomewhereElse( );out.printf("Description of object array: %s\n", obj);

这是乎有点牵强,然而要把它看作是为了自省的代码而付出的正常开销。比起其它代码,这样写要简洁的多。如果你正在编写一个代码分析工具,或者一个集成开发环境,或者其他可能使用reflection或简单API来判断出应用程序会需要何种对象的东西,这些马上会成为一个通用的案例。这儿,你不是真正关心对象数组的内容,就像你同样不会去关心数组自身一样。它是什么类型?它的内存地址是多少?它的字符串代表什么意思?请紧记所有这些问题都是和数组本身有关的,和数组的内容无关。例如:我们来看看下面的数组代码:

this.builder = builder;
this.model = model;
this.backSidesWood = backSidesWood;
this.topWood = topWood;
this.nutWidth = nutWidth;
this.fretboardInlay = fretboardInlay;
this.topInlay = topInlay;
}
}

刚才发生了什么?

当你指定了一个可变长度参数列表,Java编译器实际上读入 “create an array of type ”。你键入:

public Guitar(String builder, String model, String…… features)

然而:编译器解释这些为:

public Guitar(String builder, String model, String[] features)

这意味着重复参数列表变得简单(这将在“重复可变长度参数列表”里讲述),这与你需要完成的其他程序设计目标是一样。

你可以像使用数组一样来使用可变参数。

然而,这同样存在一些限制。第一,在每个方法中,你只可以使用一次省略号。所以,下面的书写是不合法的:

public Guitar(String builder, String model,String…… features, float…… stringHeights)

另外,省略号必须作为方法的最后一个参数。

如果你不需要传递任何可变参数呢?

那没关系,你只需要以旧的方式调用构造器:

Guitar guitar = new Guitar("Martin", "D-18");

我们再仔细看看,虽然程序中没有与下面代码相匹配的构造器:

public Guitar(String builder, String model)

那么,代码到底传递了什么呢?作为可变参数的特例,在参数中不传递东西是一个合法的选项。所以,当你看到 String…… features,你应该把它认为是零个或者更多个String参数。这省却你再去创建另一个不带可变参数构造器的麻烦。

重复可变长度参数类表

所有这些可变参数是很好的。但是实际上,如果你不在你的方法中使用它们的话,他们显然仅仅是吸引眼球的东西或是窗户的装饰品而已。

然而,你可以像你使用数组一样来使用可变参数,你会觉得这种用法很简单。

那我怎么来使用可变参数呢?

首先你要确保阅读了“创建一个可变长度的参数列表”,你会从中了解到可变参数方法最重要的东西,那就是我们把可变参数当作数组来看待。

所以,继续前面的例子,你可以写出下面的代码:

public Guitar(String builder, String model,
GuitarWood backSidesWood, GuitarWood topWood,float nutWidth,
GuitarInlay fretboardInlay, GuitarInlay topInlay,String... features) {
this.builder = builder;
this.model = model;
this.backSidesWood = backSidesWood;
this.topWood = topWood;
this.nutWidth = nutWidth;
this.fretboardInlay = fretboardInlay;
this.topInlay = topInlay;
for (String feature : features) {
System.out.println(feature);
}
}

上面的这段代码看上是不是不是那么的有吸引力?但这确实体现了可变参数的精髓。作为另一个例子,下面这个简单的方法从一组数字中计算出最大值:

public static int max(int first, int... rest) {
int max = first;
for (int i : rest) {
if (i > max)
max = i;
}
return max;
}

是不是,够简单吧?

那么如何存储可变长度参数呢?

正因为Java编译器把这些看作数组,所以数组显然是一个存储的好选择,这将在下面的例5-2中体现。

Example 5-2. 存储作为成员变量的可变参数

package com.oreilly.tiger.ch05;
public class Guitar {
private String builder;
private String model;
private float nutWidth;
private GuitarWood backSidesWood;
private GuitarWood topWood;
private GuitarInlay fretboardInlay;
private GuitarInlay topInlay;
private String[] features;
private static final float DEFAULT_NUT_WIDTH = 1.6875f;
public Guitar(String builder, String model, String... features) {
this(builder, model, null, null, DEFAULT_NUT_WIDTH, null, null, features);
}
public Guitar(String builder, String model,
GuitarWood backSidesWood, GuitarWood topWood,
float nutWidth, String... features) {
this(builder, model, backSidesWood, topWood, nutWidth, null, null, features);
}
public Guitar(String builder, String model,
GuitarWood backSidesWood, GuitarWood topWood,
float nutWidth,
GuitarInlay fretboardInlay, GuitarInlay topInlay,
String... features) {
this.builder = builder;
this.model = model;
this.backSidesWood = backSidesWood;
this.topWood = topWood;
this.nutWidth = nutWidth;
this.fretboardInlay = fretboardInlay;
this.topInlay = topInlay;
this.features = features;
}
}

你可以简单地在Java的Collection类中存储这些可变参数。

//变量声明

private List features;

//在方法中或是构造器中的书写

this.features = java.util.Arrays.asList(features);

允许零长度的参数列表

可变参数的一个显著的特性是可变长度参数可以接受零到N个参数。这就意味着你可以调用这些方法中的一个方法而不传递任何参数,程序同样可以运行。从另一方面来说,这又意味着,作为一个程序员,你最好意识到你必须防范这种情况的发生。

如何实现它呢?

记得在“重复可变长度参数类表”中,你读到过下面这个简单的方法:

public static int max(int first, int... rest) {
int max = first;
for (int i : rest) {
if (i > max)
max = i;
}
return max;
}

你可以以多种形式来调用这个方法:

int max = MathUtils.max(1, 4);
int max = MathUtils.max(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int max = MathUtils.max(18, 8, 4, 2, 1, 0);