1. 简介

  1. 数组是一种连续存储线性结构,元素类型相同,大小相等,数组是多维的,通过使用整型索引值来访问他们的元素,数组尺寸一旦创建就不能改变。
  2. 数组类型可以是任意数据类型,包括基本数据类型和引用类型。注意只能存放同一种数据类型(Object类型数组除外)。
  3. 数组在使用之前必须先声明,也就是要先定义后使用。

2. 优缺点

  1. 优点
  • 存取速度快
  1. 缺点
  • 事先必须知道数组的长度
  • 空间通常是有限制的
  • 需要大块连续的内存块
  • 插入 / 删除元素的效率很低

3. 数组声明

数组声明之后,仅仅是定义了一个数组引用,系统并没有为数组分配任何内存,因此现在还不能访问它的任何元素。
必须经过数组初始化后,才能使用数组的元素。

  1. 数据类型 [] 数组名称 = new 数据类型 [数组长度];

这里 [] 可以放在数组名称的前面,也可以放在数组名称的后面,我们推荐放在数组名称的前面,这样看上去 数据类型 [] 表示的很明显是一个数组类型,而放在数组名称后面,则不是那么直观。

动态初始化就是在定义数组时,只指定数组的长度,不为它赋值。在使用到的时候在给它添加元素。

  1. 数据类型 [] 数组名称 = {数组元素1,数组元素2,……};

这种方式声明数组的同时直接给定了数组的元素,数组的大小由给定的数组元素个数决定。

静态初始化就是在定义数组的同时给数组元素赋值。静态初始化使用一对大括号将初值括起来,大括号中元素的个数就是数组的长度。

  1. //声明数组1,声明一个长度为3,只能存放int类型的数据
  2. int [] myArray = new int[3];
  3. //声明数组2,声明一个数组元素为 1,2,3的int类型数组
  4. int [] myArray2 = {1,2,3};

4. 访问数组元素及给数组元素赋值

数组是存在下标索引的,通过下标可以获取指定位置的元素,数组小标是从0开始的,也就是说下标0对应的就是数组中第1个元素,可以很方便的对数组中的元素进行存取操作。

前面数组的声明第二种方式,我们在声明数组的同时,也进行了初始化赋值。

  1. //声明数组,声明一个长度为3,只能存放int类型的数据
  2. int [] myArray = new int[3];
  3. //给myArray第一个元素赋值1
  4. myArray[0] = 1;
  5. //访问myArray的第一个元素
  6. System.out.println(myArray[0]);

上面的myArray 数组,我们只能赋值三个元素,也就是下标从0到2,如果你访问 myArray[3] ,那么会报数组下标越界异常。

5. 数组遍历

数组有个 length 属性,是记录数组的长度的,我们可以利用length属性来遍历数组。

  1. //声明数组2,声明一个数组元素为 1,2,3的int类型数组
  2. int [] myArray2 = {1,2,3};
  3. for(int i = 0 ; i < myArray2.length ; i++){
  4. System.out.println(myArray2[i]);
  5. }

6. 用类封装数组实现数据结构

现在用类的思想封装一个数组,实现数据结构的4个基本功能。

ps:假设操作人是不会添加重复元素的,这里没有考虑重复元素,如果添加重复元素了,后面的查找,删除,修改等操作只会对第一次出现的元素有效。

  1. package com.ys.array;
  2. public class MyArray {
  3. //定义一个数组
  4. private int [] intArray;
  5. //定义数组的实际有效长度
  6. private int elems;
  7. //定义数组的最大长度
  8. private int length;
  9. //默认构造一个长度为50的数组
  10. public MyArray(){
  11. elems = 0;
  12. length = 50;
  13. intArray = new int[length];
  14. }
  15. //构造函数,初始化一个长度为length 的数组
  16. public MyArray(int length){
  17. elems = 0;
  18. this.length = length;
  19. intArray = new int[length];
  20. }
  21. //获取数组的有效长度
  22. public int getSize(){
  23. return elems;
  24. }
  25. /**
  26. * 遍历显示元素
  27. */
  28. public void display(){
  29. for(int i = 0 ; i < elems ; i++){
  30. System.out.print(intArray[i]+" ");
  31. }
  32. System.out.println();
  33. }
  34. /**
  35. * 添加元素
  36. * @param value,假设操作人是不会添加重复元素的,如果有重复元素对于后面的操作都会有影响。
  37. * @return添加成功返回true,添加的元素超过范围了返回false
  38. */
  39. public boolean add(int value){
  40. if(elems == length){
  41. return false;
  42. }else{
  43. intArray[elems] = value;
  44. elems++;
  45. }
  46. return true;
  47. }
  48. /**
  49. * 根据下标获取元素
  50. * @param i
  51. * @return查找下标值在数组下标有效范围内,返回下标所表示的元素
  52. * 查找下标超出数组下标有效值,提示访问下标越界
  53. */
  54. public int get(int i){
  55. if(i<0 || i>elems){
  56. System.out.println("访问下标越界");
  57. }
  58. return intArray[i];
  59. }
  60. /**
  61. * 查找元素
  62. * @param searchValue
  63. * @return查找的元素如果存在则返回下标值,如果不存在,返回 -1
  64. */
  65. public int find(int searchValue){
  66. int i ;
  67. for(i = 0 ; i < elems ;i++){
  68. if(intArray[i] == searchValue){
  69. break;
  70. }
  71. }
  72. if(i == elems){
  73. return -1;
  74. }
  75. return i;
  76. }
  77. /**
  78. * 删除元素
  79. * @param value
  80. * @return如果要删除的值不存在,直接返回 false;否则返回true,删除成功
  81. */
  82. public boolean delete(int value){
  83. int k = find(value);
  84. if(k == -1){
  85. return false;
  86. }else{
  87. if(k == elems-1/*?*/){
  88. elems--;
  89. }else{
  90. for(int i = k; i< elems-1 ; i++){
  91. intArray[i] = intArray[i+1];
  92. }
  93. elems--;
  94. }
  95. return true;
  96. }
  97. }
  98. /**
  99. * 修改数据
  100. * @param oldValue原值
  101. * @param newValue新值
  102. * @return修改成功返回true,修改失败返回false
  103. */
  104. public boolean modify(int oldValue,int newValue){
  105. int i = find(oldValue);
  106. if(i == -1){
  107. System.out.println("需要修改的数据不存在");
  108. return false;
  109. }else{
  110. intArray[i] = newValue;
  111. return true;
  112. }
  113. }
  114. }
  1. //测试
  2. package com.ys.test;
  3. import com.ys.array.MyArray;
  4. public class MyArrayTest {
  5. public static void main(String[] args) {
  6. //创建自定义封装数组结构,数组大小为4
  7. MyArray array = new MyArray(4);
  8. //添加4个元素分别是1,2,3,4
  9. array.add(1);
  10. array.add(2);
  11. array.add(3);
  12. array.add(4);
  13. //显示数组元素
  14. array.display();
  15. //根据下标为0的元素
  16. int i = array.get(0);
  17. System.out.println(i);
  18. //删除4的元素
  19. array.delete(4);
  20. //将元素3修改为33
  21. array.modify(3, 33);
  22. array.display();
  23. }
  24. }

7. 分析局限性

① 插入快,对于无序数组,上面我们实现的数组就是无序的,即元素没有按照从大到小或者某个特定的顺序排列,只是按照插入的顺序排列。无序数组增加一个元素很简单,只需要在数组末尾添加元素即可,但是有序数组却不一定了,它需要在指定的位置插入。

② 查找慢,当然如果根据下标来查找是很快的。但是通常我们都是根据元素值来查找,给定一个元素值,对于无序数组,我们需要从数组第一个元素开始遍历,直到找到那个元素。有序数组通过特定的算法查找的速度会比无需数组快,后面我们会讲各种排序算法。

③ 删除慢,根据元素值删除,我们要先找到该元素所处的位置,然后将元素后面的值整体向前面移动一个位置。也需要比较多的时间。

④ 数组一旦创建后,大小就固定了,不能动态扩展数组的元素个数。如果初始化你给一个很大的数组大小,那会白白浪费内存空间,如果给小了,后面数据个数增加了又添加不进去了。

很显然,数组虽然插入快,但是查找和删除都比较慢,而且扩展性差,所以我们一般不会用数组来存储数据。


1.1 collection 和 collections

  • collection :集合类的上层接口,子接口主要有list ,set,queue
  • collections:提供对集合进行搜索,排序,替换和线程安全化等操作的工具类。
  • ArrayList,LinkedList,Vector
  • ArrayList:动态数组;基于数组实现;
  • LinkedList:有序数组;基于双向链表实现;
  • vector:对象容器,可放入不同类的对象(基于数组实现);

1.2 LinkedHashMap ,TreeMap ,TreeSet

  • LinkedHashMap:顺序存取HashMap(基于数组和双向链表实现);
  • TreeMap:内部排序(基于黑色树实现);
  • TreeSet:有序的set集合(基于二叉树);