数组
复习一下java中数组方面的知识。
1. 数组介绍
数组是java中的一种数据结构,用来存储类型相同的一组数据。和基本数据类型区别,数组属于引用数据类型。(有关基本数据类型的介绍移步这里)
2.数组的声明/初始化
数组的使用可以分为两部分,首先是声明一个数组变量,这时候会在栈中创建一个引用,初始化以后才会在堆中分配具体空间。具体过程可以见下一部分。
数组的初始化过程可以分为两种:
(1) 静态初始化,手动给数组赋值
eg:int[] a = new int[]{1,2,3};
或者
int[] a = {1,2,3};
以上两种都属于静态初始化。
(2) 动态初始化,由系统给数组赋值,初始化的时候声明数组大小。
int[] a = new int[a]3;
a[0] = 1;
a[1] = 2;
a[2] = 3;
*数组下标从0开始。
需要说明的是,当一个数组被初始化以后,如果只声明了数组的大小,其实系统在内存中也是给它分配了具体的默认值的,数据类型如下:
基本数据类型中的整型数据(byte,short,int,long),默认值是0;
基本数据类型中的浮点型数据(float,double),默认值是0.0;
基本数据类型中的字符型数据(char),默认值是0对应的字符编码;
基本数据类型中的布尔型数据(boolean),默认值是false;
引用类型数据(数组,类和接口),默认值是null。
3.内存示意图
java中将内存分为两部分,一个是栈区(stack),一个是堆区(heap)。栈区主要存放基本数据类型和引用数据类型的引用变量(创建和销毁成本较低),堆区存放具体的对象(创建和销毁成本较高),栈区的引用指向堆区的具体对象,当堆区的一个对象没有任何引用变量指向它时,他就成了垃圾数据,java中的垃圾回收机制(gc)就会对这种数据进行处理。
我们从最简单的一个数组声明初始化的过程来进行分析。
Int[] a;
a = {1,2,3};
声明数组a的时候,会在栈区创建一个引用变量a,如图:
初始化完a以后,会在堆区分配空间存储这些数据,如图:
使用时,通过引用变量指向内存的实际对象,如图:
看了上面的图,大家对数组这种数据结构是不是已经有了一点了解了。
我们换一个场景,还是引用类型,但这次我们用类来进行操作:
一个Book类:
package com.ljw.ArrayTest;
/**
* Created by liujiawei on 2018/6/24.
*/
public class Book {
private String bookName;
private double bookPrice;
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public double getBookPrice() {
return bookPrice;
}
public void setBookPrice(double bookPrice) {
this.bookPrice = bookPrice;
}
}
测试类:
package com.ljw.ArrayTest;
/**
* Created by liujiawei on 2018/6/24.
*/
public class TestBook {
public static void main(String[] args) {
Book[] library = new Book[1];
Book book = new Book();
book.setBookName("书");
book.setBookPrice(100);
library[0] = book;
book.setBookName("很贵的书");
//?? 这个时候的library[0]的书名是还是书么?
}
}
可以看到我们声明一个Book类型的数组library,同时声明了一个Book类型的变量,通过动态初始化的方式给library进行了赋值,这时候修改了book的属性,liarbry中的数据会跟着发生变化么?
分析:
初始化library和book时:
将book赋值给library时:
可以看到,其实library中引用还是内存中book,看到这边,相信上面的问题应该大家都可以回答了吧。
两者指向的其实就是同一个对象,不管是操作book对象,还是操作library[0],效果都是一样的。
思考下:基本数据类型在内存中是怎样存储的?
上文说过,基本数据类型和引用类型变量都是存储在栈区,引用对象的数据存储在堆区。知道这一点以后,平时我们遇到的 == 和equals的区分,就很好理解了。
== 比较的是引用的地址是否相同,也就是说除非是同一个对象,否则他的地址都不相同。
equals比较是在堆中的内容,是对象本身的值。
4.二维数组理解
java中并没有二维数组这种数据结构,我们所说的多维数组本质上都是在一维数组的基础上扩展的。我们知道,数组的声明可以这样表示:
typename[] name = new typename[3];
这个typename[]就是引用数据类型,来看下二维数组的声明:
上面说过,二维数组其实就是一个特殊的一维数组,那么按照正常的理解来说的,他的形式应该就是 :
typename[][] = new typename[][3];
前面的typename[]就是正常数组中的typename,实际上这样子声明的二维数组编译器是不会通过的,原因在于二维数组中,第一个中括号中的数值才代表数组的大小,所以实际上二维数组声明的形式是这样:
typename [][] name = new typename[3][];
5.Arrays工具类操作
Arrays是java.utiil工具类下面提供的一个用来操作数组的一个类,这里只说明几个用的比较多的方法,其他的可以根据实际情况查阅api。(摘自疯狂java讲义)
需要注意的是:数组因为在初始化时长度就被固定,也就是说数组没有扩容,但是可以通过Arrays.copyOf(),复制一个新的长度的数组,变相的实现扩容的目的。
除此以外,利用Object中的clone()方法也可以实现对数组的克隆。
有理解不到位之处,请大家指导。