代码改变世界

java collections读书笔记(3)Arrays

2013-06-13 09:57  很大很老实  阅读(274)  评论(0编辑  收藏  举报

---恢复内容开始---

因为,数组是通过引用方式组织的,因此,多维数组的存在,也就是理所当然的。

数组之间的引用,构成了多维数组的基础。而且,由于这个引用的方式,数组不一定是矩形的,如下图:

When accessing an array with multiple dimensions, each dimension expression is fully evaluated before the
next dimension expression to the right is ever examined. This is important to know if an exception happens
during an array access

另外,无论我们创建的是几维数组,由于计算机内存是线性的,因此,在内存里,都是按照一维数组组织和管理的。

因此,如果在访问时,按照内存里存放的方式访问,则是效率最高的。

数组创建后,如果没有复制,则缺省的初始化的值为:

DEFAULT VALUE    ARRAY
0           byte
           short
           int
           long
0.0          float
           double
\u0000        char
false          boolean
null          Object

从java1.1开始,引入了匿名数组。相对某个集合进行一些操作,而这个集合只会被用到一次的时候,用匿名数组是比较合适的。

public class Main {
    public static void main(String[] args) {
        out1(new String[] {"1", "2"});
        out2("1", "2");
    }
    
    static void out1(String[] ss){
        for (String str : ss) {
            System.out.println(str);
        }
    }
    
    static void out2(String... ss){
        for (String str : ss) {
            System.out.println(str);
        }
    }
}

数组的调用,比如传递到函数中,是引用的方式,不是值传递:

public class welcome {

    public static void  main(String[] args)
    {
        int[] a=new int[10];
        int[] b=createArray(10);
        
        
        for(int i=0;i<b.length;i++)
        {
            System.out.println("b["+i+"]:" +b[i]);
            
            
        }
        
        modifyarray(b);
    
        for(int i=0;i<b.length;i++)
        {
            System.out.println("b["+i+"]:" +b[i]);
            
        }
    
        
    }
    
    static int[] createArray(int size){
        return new int[size];
    }
    static void modifyarray(int[] arr){
        for(int i=arr.length-1;i>0;i--)
            arr[i]=arr.length-i;
    }
}

b[0]:0
b[1]:0
b[2]:0
b[3]:0
b[4]:0
b[5]:0
b[6]:0
b[7]:0
b[8]:0
b[9]:0
b[0]:0
b[1]:9
b[2]:8
b[3]:7
b[4]:6
b[5]:5
b[6]:4
b[7]:3
b[8]:2
b[9]:1

copy或者clone数组:

system类下的arraycopy()允许你把元素从一个array copy到另一个array。做这个操作的时候,目标array不能比初始array小,否则,会触发ArrayIndexOutOfBoundsException这个运行时异常。

public static void
arraycopy (Object sourceArray, int sourceOffset, Object destinationArray, int destinationOffset, int
numberOfElementsToCopy)

数组不变性

如果您不希望方法的调用程序修改底层数组结构,从方法返回数组克隆是非常有用的。您可以声明数组为 final ,像下面的示例那样:

final static int array[] = {1, 2, 3, 4, 5};

 

不过声明一个对象引用为 final (特别是这里的数组引用)并不限制您修改对象。它只限制您改变 final 变量引用的内容。下面的代码行导致了一个编译错误:

array = new int[] {6, 7, 8, 9};

 

不过改变个别的元素完全合法:

array[3] = 6;

 

提示:另一种从方法“返回”不变数组的方法是将 Enumeration 或者 Iterator 返回到数组,这比返回实际数组要好。任一接口都提供对单个元素的存取而不需要改变整个数组或要求制作整个数组的副本。您会在 Java Collections的后续章节学到更多的有关这些接口的知识。

 

数组赋值

数组赋值和变量赋值的操作一样。如果变量 x 是对 y 数组的引用,如果 z 类型的变量可以赋值给 y,那么 x 就可以成为对 z 的引用。例如,设想 y 是个 AWT Component 类,而 z 是个 AWT Button 类。因为 Button 变量可以被赋给 Component 变量,则 Button 数组可以被赋给 Component 数组:

Button buttons[] = {
  new Button("One"),
  new Button("Two"),
  new Button("Three")};
Component components[] = buttons;

 

当进行这样的赋值时,两个变量的 bottons 和 componets 引用的是内存的同一个堆空间。如图 2-6 所示。改变一个数组中的元素将会造成两个数组的元素都改变。


图 2-6. 数组赋值后的共享内存
数组赋值后的共享内存

如果,将一个数组变量赋值给一个超类数组变量之后(正如在前一个示例中将 botton 数组赋值给 component 数组变量一样),您接着试图将一个不同的子类实例放入数组,一个 ArrayStoreException 异常就会被抛出。继续前一个示例,如果您试图将一个 Canvas 对象放入 components 数组,一个 ArrayStoreException 异常就会被抛出。即使 components 数组被声明为 Component 对象数组也是如此,因为 components 数组是对 Button 对象数组的特别引用, Canvas 对象无法被存到数组中。这是个运行时异常,因为从类型安全编译器看,实际赋值是合法的。

检查数组等同性

检查两个数组之间的等同性可以用两种方式中的一种,这取决于您想要查找的等同性类型。是数组变量指向内存的同一位置因而指向同一数组?或是两数组中的元素相等?

检查对同一内存空间的两个引用可用由两个等号组成的运算符(==)来实现。例如,前面的 components 和 buttons 变量在这种情况下将是相等的,因为其中一个是另一个的引用:

components == buttons  //true

 

但是,如果您将数组和它的克隆版本比较,那么用 ==,它们是不会相等的。因为这两个数组虽然有相同的元素,但处于不同的内存空间,它们是不同的。为了让一个数组的克隆版本与原数组相等,您必须使用 java.util.Arrays 类中的 equals() 方法。

String[] clone = (String[]) strarray.clone();
boolean b1 = Arrays.equals(strarray, clone);   //Yes,they're equal

 

这就会检查每个元素的等同性。在参数是对象数组的情况下,每个对象的 equals() 方法会被用来检查等同性。 Arrays.equals() 方法也为非克隆的数组服务。

 

 数组反射:

如果因为某种原因,您并不确定参数或对象是不是数组,您可以检索对象的 Class 对象并询问它。 Class 类的 isArray() 方法将会告诉您。一旦您知道拥有了一个数组,您可以询问 ClassgetComponentType() 方法,您实际拥有的是什么类型的数组。如果 isArray() 方法返回 false,那么 getComponentType() 方法返回空。否则返回元素的 Class 类型。如果数组是多维的,您可以递归调用 isArray() 。它将仍只包含一个 component 类型。此外,您可以用在 java.lang.reflect 包里找到的 Array 类的 getLength() 方法获取数组的长度。

public class ArrayReflection {
  public static void main (String args[]) {
    printType(args);
  }
  private static void printType (Object object) {
    Class type = object.getClass();
    if (type.isArray()) {
      Class elementType = type.getComponentType();
      System.out.println("Array of: " + elementType);
      System.out.println(" Length: " + Array.getLength(object));
    }
  }
}

上述这个例子,需要引入:import java.lang.reflect.Array;

如果是:
import java.util.*;
import java.lang.reflect.Array;
public class welcome {

          public static void main (String args[]) {
            printType(args);
          }
          private static void printType (Object object) {
            Class type = object.getClass();
            if (type.isArray()) {
              Class elementType = type.getComponentType();
              

              System.out.println("Array of: " + type);
              System.out.println("Array of: " + elementType);
              System.out.println(" Length: " + Array.getLength(object));
            }
          }
}

则输出为:

Array of: class [Ljava.lang.String;
Array of: class java.lang.String
 Length: 0


字符数组:
字符数组在java里不是字符串。
虽然使用 String 构造器(采用 char 类型的对象数组)和 StringtoCharArray() 方法能很容易的在 Stringchar[]