for(i=0;i>1000;i++)
  {data1[i]=new String(data2[i]);}

解决方案 »

  1.   

    data1=new String[data2.length];
    for(int i=0;i<data2.length;i++)
    data1[i]=data2[i];
      

  2.   

    String[] data1, data2;
    ……
    data1 =(String[])data2.clone();
      

  3.   

    12.2 制作本地副本
    稍微总结一下:Java中的所有自变量或参数传递都是通过传递句柄进行的。也就是说,当我们传递“一个对象”时,实际传递的只是指向位于方法外部的那个对象的“一个句柄”。所以一旦要对那个句柄进行任何修改,便相当于修改外部对象。此外:
    ■参数传递过程中会自动产生别名问题
    ■不存在本地对象,只有本地句柄
    ■句柄有自己的作用域,而对象没有
    ■对象的“存在时间”在Java里不是个问题
    ■没有语言上的支持(如常量)可防止对象被修改(以避免别名的副作用)
    若只是从对象中读取信息,而不修改它,传递句柄便是自变量传递中最有效的一种形式。这种做非常恰当;默认的方法一般也是最有效的方法。然而,有时仍需将对象当作“本地的”对待,使我们作出的改变只影响一个本地副本,不会对外面的对象造成影响。许多程序设计语言都支持在方法内自动生成外部对象的一个本地副本(注释①)。尽管Java不具备这种能力,但允许我们达到同样的效果。①:在C语言中,通常控制的是少量数据位,默认操作是按值传递。C++也必须遵照这一形式,但按值传递对象并非肯定是一种有效的方式。此外,在C++中用于支持按值传递的代码也较难编写,是件让人头痛的事情。12.2.1 按值传递
    首先要解决术语的问题,最适合“按值传递”的看起来是自变量。“按值传递”以及它的含义取决于如何理解程序的运行方式。最常见的意思是获得要传递的任何东西的一个本地副本,但这里真正的问题是如何看待自己准备传递的东西。对于“按值传递”的含义,目前存在两种存在明显区别的见解:
    (1) Java按值传递任何东西。若将基本数据类型传递进入一个方法,会明确得到基本数据类型的一个副本。但若将一个句柄传递进入方法,得到的是句柄的副本。所以人们认为“一切”都按值传递。当然,这种说法也有一个前提:句柄肯定也会被传递。但Java的设计方案似乎有些超前,允许我们忽略(大多数时候)自己处理的是一个句柄。也就是说,它允许我们将句柄假想成“对象”,因为在发出方法调用时,系统会自动照管两者间的差异。
    (2) Java主要按值传递(无自变量),但对象却是按引用传递的。得到这个结论的前提是句柄只是对象的一个“别名”,所以不考虑传递句柄的问题,而是直接指出“我准备传递对象”。由于将其传递进入一个方法时没有获得对象的一个本地副本,所以对象显然不是按值传递的。Sun公司似乎在某种程度上支持这一见解,因为它“保留但未实现”的关键字之一便是byvalue(按值)。但没人知道那个关键字什么时候可以发挥作用。
    尽管存在两种不同的见解,但其间的分歧归根到底是由于对“句柄”的不同解释造成的。我打算在本书剩下的部分里回避这个问题。大家不久就会知道,这个问题争论下去其实是没有意义的——最重要的是理解一个句柄的传递会使调用者的对象发生意外的改变。12.2.2 克隆对象
    若需修改一个对象,同时不想改变调用者的对象,就要制作该对象的一个本地副本。这也是本地副本最常见的一种用途。若决定制作一个本地副本,只需简单地使用clone()方法即可。Clone是“克隆”的意思,即制作完全一模一样的副本。这个方法在基础类Object中定义成“protected”(受保护)模式。但在希望克隆的任何衍生类中,必须将其覆盖为“public”模式。例如,标准库类Vector覆盖了clone(),所以能为Vector调用clone(),如下所示://: Cloning.java
    // The clone() operation works for only a few
    // items in the standard Java library.
    import java.util.*;class Int {
      private int i;
      public Int(int ii) { i = ii; }
      public void increment() { i++; }
      public String toString() { 
        return Integer.toString(i); 
      }
    }public class Cloning {
      public static void main(String[] args) {
        Vector v = new Vector();
        for(int i = 0; i < 10; i++ )
          v.addElement(new Int(i));
        System.out.println("v: " + v);
        Vector v2 = (Vector)v.clone();
        // Increment all v2's elements:
        for(Enumeration e = v2.elements();
            e.hasMoreElements(); )
          ((Int)e.nextElement()).increment();
        // See if it changed v's elements:
        System.out.println("v: " + v);
      }
    } ///:~clone()方法产生了一个Object,后者必须立即重新造型为正确类型。这个例子指出Vector的clone()方法不能自动尝试克隆Vector内包含的每个对象——由于别名问题,老的Vector和克隆的Vector都包含了相同的对象。我们通常把这种情况叫作“简单复制”或者“浅层复制”,因为它只复制了一个对象的“表面”部分。实际对象除包含这个“表面”以外,还包括句柄指向的所有对象,以及那些对象又指向的其他所有对象,由此类推。这便是“对象网”或“对象关系网”的由来。若能复制下所有这张网,便叫作“全面复制”或者“深层复制”。
    在输出中可看到浅层复制的结果,注意对v2采取的行动也会影响到v:v: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    v: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]一般来说,由于不敢保证Vector里包含的对象是“可以克隆”(注释②)的,所以最好不要试图克隆那些对象。②:“可以克隆”用英语讲是cloneable,请留意Java库中专门保留了这样的一个关键字。