Java数组类型

来源:互联网 发布:香港恐怖在线知乎 编辑:程序博客网 时间:2024/06/11 10:43

在Java中,数组可以说是经常用到的,但关于数组是什么类型的这个问题,我却没有深入研究过。以下内容参考自《Java语言规范》,记录了数组的类型是什么?更进一步地说,数组对象的getClass()返回的是什么?

1.数组更详细的特点

数组具有以下几点特点:

a.在Java编程语言中,数组是动态创建的对象,可以被赋值给Object类型的变量。Object类的所有方法都可以在数组上调用。

b.数组对象包含大量的变量。

c.数组的所有元素都具有相同的类型,称为数组的元素类型。如果数组的元素类型为T,那么数组自身的类型就写作T[ ]。

这里针对数组的特点a进行详细说明:
下面代码片段中,会创建一个数组对象,并且这个对象可以赋值给Object对象。

int[] ai1 = {1,2};//隐式地创建一个新的数组对象int[] ai = new int[2];//显式地创建一个数组对象Object o = ai;//数组对象可以赋值给Object类型的变量o = ai1;

通过上面的代码片段,再联系“数组是动态创建的对象”这句话,我们可以猜测:数组的类型很可能是运行时通过反射动态创建的,并且其类型是Object的子类。

既然知道数组具有特定类型了,那么这个类型具有什么成员呢?下面将进行说明。

2.数组类型的成员

数组类型的成员包括以下所有内容:

  • public final 域 length,它包含了数组的元素数量。length可以是正数或0。
  • public 方法 clone,它覆盖了Object类中的同名的方法,并且不会抛出任何受检异常。
    多维数组的克隆是浅复制,即它只创建单个新数组,子数组是共享的。
  • 所有从Object类继承而来的成员,Object中唯一没有被继承的方法就是clone方法。

因此,数组具有与下面的类相同的public域和方法:

class A<T> implements Cloneable,java.io.Serializable {    public final int length = X;    public T[] clone() {        try{            return (T[])super.clone();        } catch (CloneNotSupportedException e) {            throw new InternalError(e.getMessage());        }    }}

注意:在上面例子中,如果数组真的以这种方式实现,那么其中向T[ ]的强制类型转换会产生非受检警告。

从上面可以知道,数组是可克隆的

class Test1 {    public static void main(String[] args) {        int ia1[] = {1,2};        int ia2[] = ia1.clone();        System.out.print((ia1 == ia2) + " ");        ia1[1]++;        System.out.println(ia2[1]);    }}

这个程序会产生下面的输出:
false 2
该输出展示了ia1和ia2所引用的数组元素是不同的变量。

下面的例子说明多维数组克隆后共享子数组:

class Test2 {    public static void main(String[] args) throws Throwable {        int ia[][] = { { 1, 2 }, null };        int ja[][] = ia.clone();        System.out.print((ia == ja) + " ");        System.out.println(ia[0] == ja[0] && ia[1] == ja[1]);    }}

这个程序会产生下面的输出:
false true
该输出展示了 int[ ] 数组 ia[0] 和 int[ ] 数组 ja[0] 是同一个数组。

3.数组的Class对象

每个数组都与一个Class对象关联,并与其他具有相同元素类型的数组共享该对象。尽管数组类型不是类,但是每一个数组的Class对象起到的作用看起来都像是:

  • 每个数组类型的直接超类都是Object。
  • 每个数组类型都实现了Cloneable 接口和 java.io.Serializable 接口

    下面的代码用于测试上面的特点:

package com.test;class A {}class B extends A implements Comparable<B>{    @Override    public int compareTo(B o) {        return 0;    }}public class Test2 {    public static void main(String[] args) throws Throwable {        B[] ba = new B[2];        B b = new B();        B[] ba1 = new B[2];        //测试数组的Class对象是共享的        System.out.println(ba == ba1);        System.out.println(ba.getClass() == ba1.getClass());        //测试数组ba和b的Class对象是否一样        System.out.println(ba.getClass() + " | " + b.getClass());        //测试数组ba和b的超类是否一样        System.out.println(ba.getClass().getSuperclass() + " | " + b.getClass().getSuperclass());        //测试数组ba和b实现的接口分别是什么        for(Class<?>c : ba.getClass().getInterfaces())            System.out.println("Superinterfaces: " + c);        System.out.println("-----------");        for(Class<?>c : b.getClass().getInterfaces())            System.out.println("Superinterfaces: " + c);    }}

上面程序输出是:
false
true
class [Lcom.test.B; | class com.test.B
class java.lang.Object | class com.test.A
Superinterfaces: interface java.lang.Cloneable
Superinterfaces: interface java.io.Serializable
- - - - - - - - - - -
Superinterfaces: interface java.lang.Comparable

其中,字符串“[Lcom.test.B”是“元素类型为com.test.B的数组”的Class对象的运行时类型签名

根据上面的输出结果,可得出以下总结。

  • 数组的Class对象是共享的。

  • 虽然每个数组都与一个 Class 对象关联,但数组的Class对象并不等于数组元素的Class对象
    从上面这个输出可以看出:class [Lcom.test.B; | class com.test.B

  • 数组的类型是Object类的子类,并且数组的类型和数组元素的类型不一样。
    如上面的输出中, B[ ] 的超类是Object,而B的超类是A。B[ ]类型实现的是Cloneable 和 Serializable 接口,而B类实现的是Comparable 接口。

0 0
原创粉丝点击