• 数组


    一、何谓数组?

    1.数组是一种复合数据类型,是系列有序数据的集合,特点是数组中每一个数据的数据类型一定是相同的,通过索引可以快速定位数组中元素,获取数组中数据速度非常快。在java中,数组本质上是对象。数组是保存一组对象最有效一种方式,同样数组是一种效率最高的存储和 随机访问对象引用序列的方式,缺点是数组的大小固定,并且在生命周期内部可改变,数组之所以优于泛型之前的容器,是因为数组持有某种具体的类型,可在编译器检查,防止插入类型错误或者抽取不当类型,数组可以持有基本类型,泛型之前的容器则不能,不过由于自动包装机制,使容器看起来具备持有基本类型的能力。也是因为这个导致数组仅存的优势是效率。

     1 /**      
     2 *    数组
     3 */
     4 public class Demo{
     5     public static void main(String[] args){
     6         int a[] = new int[10];
     7         System.out.println(a.getClass());
     8         System.out.println(a.getClass().getSuperclass());
     9     }
    10 }

    结果输出:

    class [I
    class java.lang.Object

    从结果可以看出,数组的父类是object,数组的类名class [I,这是java虚拟机生成的一个特殊类。同时也可以看出数组和普通的Java类是不同的,普通的java类是以全限定路径名+类名来作为自己的唯一标示的,而数组则是以若干个[+L+数组元素类全限定路径+类来最为唯一标示的。

    2.数组类是否有其他属性和方法呢?以及我们经常用的length字段,是否是数组类的成员属性之一呢?

     1 public class Demo{
     2     public static void main(String[] args){
     3         int a[] = new int[10];
     4         Class clazz = a.getClass();
     5         System.out.println(clazz.getDeclaredFields().length);   
     6         System.out.println(clazz.getDeclaredMethods().length);   
     7         System.out.println(clazz.getDeclaredConstructors().length);   
     8         System.out.println(clazz.getDeclaredAnnotations().length);   
     9         System.out.println(clazz.getDeclaredClasses().length); 
    10     }
    11 }

    结果输出:

    0
    0
    0
    0
    0

    结果可知,与我们想的不一样,数组类没有生命任何成员变量、成员方法、构造函数、Annotation甚至连length成员变量这个都没有,它就是一个彻彻底底的空类。length并不是数组类的一个成员属性,那么获取数组长度的方式实际是通过arraylength指令,当编译器在编译int b=a.length的时候,直接做了特殊处理。

    二、数组的使用

    1.数组的使用非常简单,同其他类一样,需要声明和new。

     1 /**      
     2 *    数组
     3 */
     4 public class Demo{
     5     public static void main(String[] args){
     6         int a[] = new int[10];//声明和分配空间
     7         Demo demos[] = new Demo[10];
     8         System.out.println(demos[0]);
     9         System.out.println(a[0]);
    10         a[0]=1;
    11         demos[0] = new Demo();//数组的赋值
    12         System.out.println(a[0]);
    13         System.out.println(demos[0]);
    14     }
    15 }

    结果输出:

    null
    0
    1
    com.demo.Demo@6d06d69c

    当我们声明一个数组,并分配了内存空间,会给予一个初始值。紧接着可以按我们的意愿进行赋值。当数组是基本类型数组的时候,可以看做生成的数组类的属性为基本类型,存放的即基础类型数据的值,当数据是引用类型的时候,生成数组类的成员属性类型为引用类型,存放的即引用类型数据的引用。数组是引用类型,它的元素相当于类的成员变量,因此给数组分配内存空间后,每个元素也被按照成员变量的规则被隐式初始化。

    2.数组的初始化

    数组的初始化可分为:动态初始化和静态初始化两种,具体的使用如下:

     1 public class Demo{
     2     public static void main(String[] args){
     3         //1.静态初始化,在定义数组的同时给数组分配空间并赋值
     4         int a[] = {1,10,2};
     5         Test t[] ={new Test(0),new Test(2),new Test(10)};//数组的大小,自动判定
     6         
     7         //2.动态初始化,数组的空间分配和赋值分开操作
     8         int b[] = new int[3];
     9         b[0]=0;b[1]=2;b[3]=10;
    10         Test s[] = new Test[3];
    11         s[0] = new Test(10);//可以知道引用类型数组中存放是一个指向我们new的对象的引用
    12         s[1] = new Test(100);
    13         s[2] = new Test(0);
    14         
    15     }
    16 }
    17 
    18 
    19 class Test{
    20     private int i;
    21     public Test(int i) {
    22         this.i = i;
    23     }
    24 }

    三、数组的复制问题

    数组复制,通常是借助工具类Arrays完成的。数组复制是典型的浅复制

     1 /**      
     2 *    数组复制
     3 */
     4 public class Demo{
     5     public static void main(String[] args){
     6         Test []tests = new Test[1];//1定义一个引用类型的数组,tests是一个引用,指向java堆中生成的[Lcom.test.Test对象.
     7         Test t1 = new Test(10);//2.new一个Test对象
     8         tests[0] = t1; //给数组赋值,可以看做是[Lcom.test.Test对象的一个引用类型属性被赋值,即这个引用类型属性指向我们new的Test的对象
     9         tests[0].getData();
    10         //借助工具类进行数组的复制
    11         Test [] tests2 = Arrays.copyOf(tests,tests.length);
    12         System.out.println("复制的数组的大小:"+tests2.length);
    13         tests2[0].getData();
    14         
    15         t1.setData(1000);//修改数组中的引用指向对象的数据
    16         System.out.println("-------------------------");
    17         tests[0].getData();
    18         tests2[0].getData();//结果是两个数组的中数据都发生了变化
    19         
    20     }
    21 }
    22 
    23 
    24 class Test{
    25     private int i;
    26     public Test(int i) {
    27         this.i = i;
    28     }
    29     public void getData(){
    30         System.out.println(this.i);
    31     }
    32     public void setData(int i){
    33         this.i = i;
    34     }
    35 }

    结果输出:

    10
    复制的数组的大小:1
    10
    -------------------------
    1000
    1000

    四、数组与List之间的转换

     1 /**      
     2 *    数组与list之间的转换
     3 */
     4 public class Demo{
     5     public static void main(String[] args){
     6         int[] a = new int[]{1,2,3,4};
     7         List list = Arrays.asList(a);
     8         System.out.println(list.size());
     9         System.out.println(list.get(0));
    10         
    11         Integer[] b = new Integer[]{1,2,3};
    12         List list2 = Arrays.asList(b);
    13         System.out.println(list2.size());
    14         System.out.println(list2.get(0));
    15     }
    16 }

    结果输出:

    1
    [I@6d06d69c
    3
    1

    结果可能与很多人想的不一样,造成的原因,需要借助源代码进行理解,查看asList方法的源码
    public static <T> List<T> asList(T... a) {
      return new ArrayList<>(a);
    }
    注意点:1.参数:T…a,这个参数是一个泛型的变长参数,基本类型是不能被泛型化的,基本类型数组被当成一个对象类处理,它是可以泛型的,所以我们的程序是把一个int型的数组作为了T的类型
    将int改为Integer,结果就完全不一样了。
    2.通过Arrays.asList 转换的list,不能进行add操作,因为asList返回的ArrayList是Arrays工具类中的一个内部类,与java.util.ArrayList类是两个不同的类,所具备的方法和行为可能不一致,具体看参考源码

  • 相关阅读:
    Ant利用第三方的task
    读《NoSQL精粹》前三章有感
    opensuse12.3 桌面设置备忘录
    clojure中符号symbols 和变量vars的正确理解
    vim配置clojure开发环境备忘录
    移动端调试痛点?——送你五款前端开发利器
    SyntaxError: missing ) after argument list
    铺满屏幕的布局方法
    剖析height百分比和min-height百分比
    父元素高度设置为min-height,子元素高度设置为100%,但实际上子元素高度你知道是多少吗?(2019-10-26更新)
  • 原文地址:https://www.cnblogs.com/liupiao/p/9273636.html
Copyright © 2020-2023  润新知