JAVA 数组与集合

目录

 

数组

一维数组

 多维数组

 数组的enhance for loop

集合Collection

List

ArrayList

LinkedList

Set

HashSet

TreeSet


数组

数组也是一个对象,所以它被存放在堆(heap)中。

一维数组

数组的声明

int[] array;

这只是声明了一个数组的引用,只是在堆中建立起了一个可以用来指向一个整数数组的引用,并没有真正分配数组的内存。

真正创建对象数组要用new

数组的创建

array = new new int[4];

或直接   int[] array = {1,2,3,4,5}; 

数组的初始化

1. 基本数据类型数组

语句 int[] ints = new int[4]; 

执行完后,因为int类型数组初始化的缺省值为0,因此内存中现在就已经有了4个int(即0)

语句  char[] chars = new char[4]; 

char类型数组初始化的元素缺省值为‘\0’,是一个不可见字符。现在内存里面已经有4个char(即‘\0’)

语句   bool[] bools new bool[4]; 

bool类型数组的元素缺省值为false。现在内存里面已经有4个bool值(即false)

2. 对象类型数组

语句  String[] str = new String[4];

因为在string这种对象类型数组中存放的是一个对象的引用。所以在该语句执行完后,内存中一个String都没有。这一点与基本数据类型数组不同。

 多维数组

多维数组在java内存中的存放

多维数组在C/C++的内存中,都是以整行优先连续排列的(内存都是一维的)。

而在Java中,多维数组在内存中的存放如上图所示。内存不是连续的,每一维都指出来了。相当于是一维数组的一维数组。

多维数组的创建与声明

int[][] ints = new int[4][3];

或者

int[][] ints = new int[4][];                              //jagged array 锯齿数组

ints[0] = new int[4];

ints[1] = new int[3];

这里的第二种声明创建方法,就是先只创建了第一维的那个数组,然后再为每一维创建被指出来的第二维数组。

由此可见,在Java中,每一维数组的维数可以不一样。这种数组被称为jagged array(锯齿数组)。Java只支持这一种数组,只是这种数组也可以实现类似于regular array的每一维大小相等的特殊情况。而C/C++只支持regular array。

数组的初始化

int[][] ints = {{1,2,3}, {4,5}};

 数组的enhance for loop

一维数组

for(int i : ints){

      system.out.println(ints[i]);

}

多维数组 

for(int ii : ints){                            //这一维取出的仍是一个一维数组

      for(int i : ii){                               //所以还需要用 i 遍历这个一维数组 ii

             system.out.println(ints[i]);

      }

}

但是,数组有个很大的缺点:一旦创建大小就不能更改————解决方法:集合Collection

集合Collection

集合Collection是一个泛型接口:public interface Collection<E>,可通过E来指定数据类型。

Collection主要分为两大类:List,Set

数组是协变的,即:若A -> B,则List(A) -> List(B)    (A与B为父类与子类的关系)

而集合是不变的,即不存在上述父类与子类的List 间的关系。List(A) 与 List(B) 没有任何关系。

List

也是一个接口。有点像向量/序列:(x, y, z, ...)

每个元素都有自己的顺序,即都有position。因此,x和y可以同时为1,即(1, 1, 1, ...)是可以存在的。

ArrayList

import java.util.List;

import java.util.ArrayList;

 list的创建

List list = new ArrayList(); 

后面的括号中当然也可以填上数值,如1。但由于这里是一个 initial capacity,为初始容量,而List的大小可以动态更改,所以没有必要,一般不在后面写。

创建的时候,前面要写List而不写ArrayList(虽然当然也是对的)。这样会方便很多(同时有着父类List与子类ArrayList的功能)

如上这样写时,也会出现警告:原因是E没有给参数。若只希望这个List放Integer,则:

List<Integer> intList = new ArrayList<>();              //<>也可以省略 

并且如果这样的话,若传一个非Integer的给这个list,编译器会在编译阶段就报错,这是很方便与编程的。

注意,ArrayList长度动态更改的实质

ArrayList在底层实际上仍是使用数组来存取元素。只是在要超过数组capacity时,会同普通array一样复制原有元素到一个更大的新的数组中。只是它是自动干了这件事。

取list中的元素

list.get(2);

即获取类似于数组中下标为2的位的数值。

LinkedList

是用链表,即指针把集合中的各个元素串起来的。

ArrayList的好处:可以通过位置随机访问;而LInkedList需要一个指针一个指针移动着来查找。

ArrayList的缺点:插入元素时(数据结构);而LInkedList就会很简单。

建议以后都写为:

Person sp = new Student();                  //向上类型转换

而少写为  Student s = new Student(); 

这样写的好处:

若有: public f(Person p ){...},则此时也可以传入Student类对象sp,即 f(new Student())。

若要向下类型转换,则必须强制(可能会出错):Student s = (Student)p;  

Set

与数学上的集合类似,既不能有重复的元素。有两种类型的实现:HashSet 和 TreeSet。

HashSet

判断是否有重复元素的方法(不是遍历与每一个元素比较):

两个不同的对象经过hash函数之后,会算出两个散列值。不同对象的散列值可能相同(散列值有限),但散列值不同的对象一定不相同。

因此在添加元素时,若此元素算出的散列值与原有元素的都不相同,则可直接加入set;若相同,则只用将该元素与与其散列值相同的那些元素进行比较。(可以把散列值看作一个一个的桶,若桶为空,则可直接放入;若不为空,则与桶内已有的元素进行比较即可。)

hashCode()方法 —— 获取hash值,应与equals()方法同时进行重写,原因:

hash值不同的两个对象必须(一定)是不同的,所以不应该存在两个hashcode()结果不同的对象,经过equals()方法,反而是相同的。所以hashCode()方法应与equals()方法配套进行重写。

在equals()方法自动生成的代码中,有一个if语句:

public boolean equals(Person obj){

       ...

       if(getClass() != obj.getClass())

              return flase;

       ...

}

 而有时它并不是我们需要的,因为我们有时会需要将子类对象与父类对象相比。如Person类的p和Student类的s:p.equals(s),有时是需要的。

TreeSet

TreeSet是二叉树的实现,不允许放入null值,是自动排序的。

在放入新元素(add)的时候,会比较元素谁大谁小,才能往树中放,小的在左,大的在右。

TreeSet也是为了加速search的过程(add是要检查(search)是否有重复值),时间复杂度为对数结构。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章