最近在重温基础,core Java 卷1结合java编程思想,将数组知识点总结如下:
特性
数组是一种引用类型,存储同一种数据类型的集合容器.
存储时数组元素存储在堆内存(heap)中,数组的引用变量存储在栈内存中(stack)中。
优点:随机访问效率高、类型检查严格、可以保存基本类型
1、数组是存储和随机访问效率最高的存储方式,数组就是一个简单的线性序列,使得元素访问非常快速
2、因为数组只能保存特定类型的数据,编译期就可以避免数据或插入时弄错类型。
但也损失了一些特性。
3、数组是唯一一个可以保存基本类型的容器
数组的特点:
1. 只能存储同一种数据类型的数据。
2. 一旦初始化,长度固定。 如果想要扩展就只能创建一个新的数组将原有数组的值引入新的数组中(ArrayList就是这样保持弹性的,所以使得ArryList比数组效率要低)
3. 数组中的元素与元素之间的内存地址是连续的。
注意: Object类型的数组可以存储任意类型的数据。
声明及创建(初始化)
String[] a;声明数组;声明数组仅仅是在内存中开辟出一块区域,里面没有任何东西,相当于只在堆内存中开辟了一块区域放数组,但是栈内存中没有对应的引用。
(当一个堆内存对象没有任何引用变量指向它时,系统的垃圾回收器才会在合适的时候回收它)
扩展:栈内存和堆内存
《1》栈内存
当一个方法执行时,每个方法都会建立自己的内存栈,
在这方法内定义的变量将会逐个放入这块栈内存里,
随着方法的执行结束,这个方法的内存栈也将自然销毁。
所有在方法中定义的局部变量都是存放在栈内存中的;
《2》堆内存
在程序中创建一个对象时,这个对象将被保存到运行时数据区中,
以便反复利用(因为对象的创建成本通常较大),
这个运行时数据区就是堆内存。
堆内存中的对象不会随方法的结束而销毁,
即使方法结束后,这个对象还可能被另一个引用变量所引用(在方法的参数传递时很常见),则这个对象依然不会被销毁。只有当一个对象没有任何引用变量指向它时,系统的垃圾回收器才会在合适的时候回收它。
String[] a=new String[];创建数组
数组的默认初始化,基本类型是 0 ,布尔类型是 false,引用类型为null,所以上面数组初始化后都为null。
获得数组长度 用s.length属性(注意:不是方法)来获取
ps:String底层都是用char数组来实现的(后续String)研究;
ArrayList底层也是用数组实现的
一些常用方法
- l for循环遍历
for each循环语句会遍历数组中每个元素,不需使用下标。
使用传统for循环:不希望遍历集合中的每个元素或者在循环内部需要使用下标值的时候。
- l 数组显示:Arrays.toString(数组名称):基本类型和string返回一个包含数组元素的字符串如"[2,3,5,7,8]",其他引用类型输出地址[core_java.Bean@15db9742,core_java.Bean@15db9742]
- l 在java中允许数组长度为0,所以判断时一般用if(s!=null&&s.length>0)
- l 数组拷贝:
方式1、int[] i=新的数组名称:此时这两个变量引用同一个数组
方式2、Arrays.copyOf(原始数组名,新的长度):如果新的长度>老长度,后面填0,false,null,如果新长度<老长度截取新长度
扩展:Arrays.copyOf()与system.arrayscopy的区别:
1、copyOf底层是用arraysCopy实现的,
2、copyOf只能从头开始复制,arraysCopy可以自定义开始复制的位置。
3、copyOf自动创件一个新的数组,arraysCopy需要自己创建数组,
4、Arrays.copyOf可以用来扩容数组,system.arrayscopy可以将本数组中不同位置的数据复制到本数组其他位置。
5、copyOf方法的组最后一个参数是新数组的长度 可以大于原数组(如果想截取数组某一段长度 可以用copyOf(数组,开始长度,结束长度)),system.arraysCopy最后一个参数是要复制的长度,长度最长不能超过新数组的长度。
Arrays.copyOf():方法说明
1、首先生成一个新的数组长度等于第二个参数
2、然后调用System.arrayscopy()方法拷贝原数组的内容到新数组中。
相当于调用了一次System.arrayscopy(old[],0,new[],0,length);
3、可以用来扩展数组,例如
String[] s1=new String[]{"1","2"};
//扩展数组
s1=Arrays.copyOf(s1,5); -------->s1变为[1, 2, null, null, null]
System.arrayscopy(old[],old起始位置,new[],new起始位置,复制长度):方法说明
1、此方法是native的,说明底层是用c++或c实现的。
2、需要自己先new一个数组出来,再将原数组值复制进去
3、可以自己复制自己的值到自己数组内
int[] fun ={0,1,2,3,4,5,6};
System.arraycopy(fun,0,fun,3,3);则结果为:{0,1,2,0,1,2,6};
- l 数组排序:
Arrays.sort: int a[] =new int[2000];……Arrays.sort(a);
Arrays.sort()jdk7以前对基本类型采用调优的快速排序,对对象类型采用了改进的归并排序,jdk7以后修改了排序策略:如果JVM启动参数配置了-Djava.util.Arrays.useLegacyMergeSort=true 那么就会执行原来的排序策略(优化的归并排序)
如果不配置,那么采用的是TimSort
public static voidsort(Object[] a) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a);
else
ComparableTimSort.sort(a, 0,a.length, null, 0, 0);
}
/** To be removed in a future release. */
private staticvoid legacyMergeSort(Object[] a) {
Object[] aux = a.clone();
mergeSort(aux, a, 0, a.length, 0);
}
原始的排序流程是采用了轻量级优化的归并排序,保证时间复杂度是n(logn),并且保证排序是稳定的,(快排虽然在某些时候效率上高于归并,但是是不稳定的并且最坏的情况下时间复杂度是o(n^2))。
具体实现这个作者写的非常好:http://www.cnblogs.com/gw811/archive/2012/10/04/2711746.html
快排对大多数数据集合来说都是高效的
扩展:快速排序、归并排序及各种排序算法。后续会更新<排序算法学习>
- l main函数的参数String[] args作用
应用方法:
在命令行中输入 java message hello world则程序红args[0]="hello"args[1]="world"
- l 斐波那契数列
0, n=1
斐波那契数列定义如下:f(n)= 1, n=2
f(n-1)+f(n-2), n>2
- l 多维数组,底层其实没有多维,只是数组的数组,第一维中每一个元素又是一个数组,保存的是一个数组的引用
- l 多维数组打印可以用Arrays.deepToString(数组名),底层调用递归方式一层层判断是否为数组,不是数组打印,是数组递归