目录
今天来学习一维数组,并深入底层理解一维数组。
1.一维数组含义:
一组数组的容器
2.数组作用:
存放数据,并且操作数据
3.数组的声明:
1.数据类型[] 数组名;
2.数据类型 数组名[];
4.数组的初始化
1.静态初始化:
我们来指定元素,系统自动分配空间长度
比如:
String[] names = new String[]{"张三","李四","王五","小红","小绿"};
String[] names;
names = new String[]{"张三","李四","王五","小红","小绿"};
String[] names = {"张三","李四","王五","小红","小绿"};
三种静态初始化最后的结果是一样的。
2.动态初始化:
我们来指定长度,系统会自动分配元素
在系统自动分配的时候,系统会自动把数组中元素置为空(null),我们来总结一下系统会自动默认分配的类型:
整数类型:0
浮点类型:0.0
字符类型:' '
布尔类型:false
引用类型:null
我们声明的数组就是引用类型,所以系统会自动把数组元素置为空
比如:
String[] names = new String[5]
//通过下标设置元素
names[0] = "张三";
names[1] = "李四";
names[2] = "王五";
names[3] = "小红";
names[4] = "小绿";
内存:
(主要以jdk1.7为例子)
步骤:
1.jvm会将这个类加入到方法区,存放字节码类文件
2.扫描整个程序,找到所有的字面值常量(数字,字符串等),和final修饰的变量
3.一旦调用方法,就会在栈里面开辟方法,用于存放改方法内的局部变量,一旦方法执行完毕,垃圾回收器(gc)会立刻回收
4.在堆里面开辟空间,存放new出来的对象,用于存放对象中数据
静态初始化内存:
就比如我们在main方法中声明一个数组,采用静态初始化的方法
1.首先jvm将字节码文件加载到方法区中
2.扫描程序中所有常量,将常量存入常量池
3.调用main方法,在栈中开辟空间,将name这个数组引用赋值给names
4.将常量池里的数据放入对应的区域
这样就完成了一个数组的初始化(静态初始化)
我们来看看动态初始化
在刚把names对象创建出来时,系统会自动把全部元素置为空,然后再将常量池中的数据赋值给元素。
注意:
1.数组是引用数据类型
2.new表示新建对象,会在堆内存开辟空间
3.数组一旦初始化后,长度不可改变(数组不可以扩容和删除)
4.数组初始化开辟的空间在内存中是连续的
5.数组的使用:
1.通过下标获取元素
String n = names[2];
System.out.println("通过下标获取元素:" + n);
2.获取数组中元素个数
int len = names.length;
System.out.println("获取数组中元素的个数:" + len);
3.遍历数组
for(int i = 0;i<names.length;i++){
System.out.println(names[i]);
}
4.增强for循环遍历数组
for(String item : names){//遍历names数组,依次取出元素赋值给item
System.out.println(element);
}
注意:
下标为负数或者大于等于长度会出现"数组下标越界异常"-ArrayIndexOutOfBoundsException
6.数组的复制
public class Test{
public static void main(String[] args){
//原数组
String[] names = {"张三","李四","王五"};
String[] newNames = names;
names[1] = "徐精华";
for(String element : newNames){
System.out.println(element);
}
}
}
这段代码就是将原数组赋值给新数组,但是我们会发现,我们改变新数组的元素,原数组的元素也会跟着改变,原因是
将原数组中的对象地址赋值给新数组这个引用,names和newNames这两个引用是指向的同一个数组对象
数组复制内存图![](https://i-blog.csdnimg.cn/blog_migrate/e72fdb30719ab3f544ca6f9a2f9168b5.png)
此时我们可以看见,两个数组的引用都是同一个数组,所以我们无论改变哪一个数组的元素,两个数组的元素都会跟着改变。
为了能够将数组完全复制出来且不受影响,所以我们采用这种方法,我们用动态初始化再声明一个数组,然后将原数组的元素赋值给新数组。
public class Test{
public static void main(String[] args){
//原数组
String[] names = {"麻生希","椎名空","水菜丽","爱田奈奈"};
//新数组
String[] newNames = new String[names.length];
//遍历原数组,将原数组中的数据依次迁移到新数组中
for(int i = 0;i<names.length;i++){
newNames[i] = names[i];
}
//遍历新数组
for(String element : newNames){
System.out.println(element);
}
}
}
我们来看看复制时候的内存图
可以看到,因为两个数组的引用不一样,现在修改就不会相互影响了。
7.数组的扩容
其实数组是不可以扩容的,所以我们只能换一种方式来,我们可以动态声明一个比较长的数组,然后把原来的数组的元素迁移过去,再将新数组的引用赋值给原来的数组,通过这样来达到扩容的目的。
public class Test08{
public static void main(String[] args){
//原数组
String[] names = {"张三","李四","王五"};
//创建新数组(新数组长度是原数组长度的1.5倍)
int capacity = names.length;
int newCapacity = capacity*2;
String[] newNames = new String[newCapacity];
//将原数组的数据迁移到新数组中
for(int i = 0;i<names.length;i++){
newNames[i] = names[i];
}
//将新数组赋值给原数组
names = newNames;
//遍历原数组
for(String element : names){
System.out.println(element);
}
}
}
8.数组的删除
因为数组的大小是不可以改变的,所以我们可以声明一个新数组,然后将除了删除的那个元素外,将其他元素迁移到新数组,以此达到删除的目的,但是还有一种方法,就是我们用覆盖的方法,将要删除的元素用后面的元素覆盖掉,相当于所有元素往前移动。
public class Test{
public static void main(String[] args){
//原数组
String[] names = {"张三","李四","王五"};
//数据的迁移
for(int i = 1;i<names.length-1;i++){
names[i] = names[i+1];
}
names[names.length-1] = null;
//遍历原数组
for(String element : names){
System.out.println(element);
}
}
}