Java中数组和集合容器的剖析

java中常用的存储容器就是数组的集合,每种容器存储的形式和结构又有所不同。

数组,是最基础的容器,在创建数组的时候有三种方式分别如下:

int[] arr = new int[5];

int[] arr = new String[]{1,2,3,4,5};

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

从上面的三种方式可以看出,在定义数组的时候有个共同的特点就是能够直接看出数组的长度,这也是数组的一大特点,就是定义的时候指定长度,同时数组一旦定义完成后长度就不可以变化,这也是数组在后期开发中较集合使用较少的原因,因为在实际开发中容器存储数据的长度存在较大的不确定性。在定义数组的方式中还可以看出定义数组的时候需要指定数组的类型,也就是数组内能够存储的数据类型,这样数组定义后,能够存储的数据类型就不能再变化,存在一定的局限性。

数组的内存存储:

接下来看看集合,集合是在开发较为常用的容器,先来看看集合的分类。

集合分类两个大类,分别是Collection集合和Map集合,Collection是使用单值的存储,而Map集合是使用键值对的形式存储,下面看看集合具体实现类的储存结构和特点。

Collection集合的共同特点:

1、存储的元素可以是不同的类型

2、集合的长度是变化的,不固定

3、都可以使用迭代器Iterator对集合中的元素进行遍历

ArrayList集合:在底层使用的数组结构进行存储,数组中存储的元素可以为null,且可以存多个重复的元素,存储的时候是按存储的先后顺序进行排序,每一元素都对应一个脚标值,在操作其中元素的时候可以通过脚标完成,在查询的时候,指定脚标,直接拿到指定的元素,无需遍历集合,因此在查询的时候效率高,增删效率低,因为在增删的过程中涉及集合元素的遍历。

LinkedList集合:在底层使用的是链表结构,有头有尾,也存在脚标,可以通过脚标操作,查询的效率较低,从源码分析上可知,首先判断脚标在中间位置的左侧还是右侧,然后对集合的一侧进行遍历,查询元素,在增删时直接操作指定的节点,无需遍历,效率提高。

ArrayList和LinkedList的比较示图:

ArrayList增加元素:

LinkedList添加元素:

Set集合:存储数据和List集合存在差距,List集合中可以存储重复的元素,而Set集合中不能存储重复的数据,List集合中存储的数据是有序的有脚标的,而Set集合中是无序的没有脚标的,不能通过脚标来操作集合中的元素

HashSet集合:在底层存储是使用的哈希表结构,存储的数据可以是null,由于唯一,因此只能存储一个,HashSet集合是如何保证元素唯一的呢?

HashSet底层使用了数组和哈希算法,在存储数据的时候会经过多次比较才能实现

具体实现:

1、先对存储的元素进行哈希算法得到一个哈希值

2、会使用这个计算得到的哈希值到存储数据的结构中找对应的位置,当该位置没有元素就直接添加进去

3、如果该位置已存在元素,会使用equals方法进行比较两个元素

4、如果再相等新添加的元素就不会被添加到集合,如果不相等就会重新计算添加元素的哈希值,然后进行添加

TreeSet集合:在底层使用了二叉树的存储结构,在保证存储数据不重复的机制上和HashSet是完全不同的

具体实现:

方式一:采用默认的比较器Comparable,这个时候需要存储的对象对应的类实现Comparable接口,并重新compareTo方法,在该方法中书写具体保证元素唯一的实现代码,若不实现和重写在存储元素的时候会出现异常

方式二:采用自定的比较器Comparator,此时具体的存储对象无需实现Comparator接口,可以另外自定义一个类,该类实现Comparator接口,并重写compare方法,在创建TreeSet集合的时候,将自定义类的对象作为参数传递给TreeSet集合的构造方法。但是该方式会多需要写一个类,较为麻烦,实现方式不友好,这个时候就可以考虑使用匿名内部类了。

两种实现方式会不会冲突呢,这个可能对初学者存在疑问,java既然这样设计,当然不会存在冲突的,看过源码的都会对这个比较机制的设计巧妙赞不绝口。

在创建TreeSet集合的时候,可以使用无参的构造方法也可以使用有参的构造方法(参数是比较器),在TreeSet中设置了一个用于保存比较器的变量(comparator),在存储元素的时候会调用一个比较的方法,该方法中对comparator进行判断,若comparator不为空,表示使用构造方法传入了比较器,就使用传入的比较器进行元素的唯一性比较,反之,就使用默认的比较器进行元素的唯一性比较。

Map集合:Map集合存储元素使用键值对的形式,键是唯一的,而值可以不唯一,键和值都可以为null,一个键只能对应一个值,但是一个值可以对应多个键,键值对在Map集合中是作为对象处理的,将一个键值对看做一个对象,Map集合中存储的是多个键值对对象。Map集合在遍历元素的时候没有类似于Collection集合的迭代器,而是使用keySet方法或者entrySet方法先转为Set集合,然后使用迭代器进行遍历。

HashMap集合:HashMap采用的也是哈希表机构,在保证键唯一性的操作上和HashSet相同。

TreeMap集合:TreeMap采用的是二叉树结构,在保证键的唯一性的操作上和TreeSet相同。

补充:

1、数组存储的元素可以是对象,也可以是基本数据类型,而集合只能存储对象

2、Collection集合都可以使用Iterator迭代器进行迭代,List集合也有它特有的迭代器ListIterator,该迭代器值适用于List集合,Collection下的其他集合不能使用

3、在开发的过程中使用ArrayList、HashSet、HashMap集合的较为普遍,其他的集合使用较少

4、LinkedList的API中有addFirst、removeFirst、addLast、removeLast四个特有的方法,因此可以使用该集合模拟栈和队列结构

时间: 2024-10-09 10:32:42

Java中数组和集合容器的剖析的相关文章

java中数组、集合、字符串之间的转换,以及用加强for循环遍历

java中数组.集合.字符串之间的转换,以及用加强for循环遍历: 1 @Test 2 public void testDemo5() { 3 ArrayList<String> list = new ArrayList<String>(); 4 list.add("甲乙1"); 5 list.add("甲乙2"); 6 list.add("甲乙3"); 7 list.add("甲乙4"); 8 //

java中数组,列表,集合的基本用法

import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class shuzu { public static void main(String[] args){ //数组 array(); //列表 list(); //集合 map(); } public static void array(){ int[] a=new int[]{0,1

Java中数组的特性

转载:http://blog.csdn.net/zhangjg_blog/article/details/16116613 数组是基本上所有语言都会有的一种数据类型,它表示一组相同类型的数据的集合,具有固定的长度,并且在内存中占据连续的空间.在C,C++等语言中,数组的定义简洁清晰,而在Java中确有一些会让人迷惑的特性.本文就尝试分析这些特性. Java中的数组是对象吗? Java和C++都是面向对象的语言.在使用这些语言的时候,我们可以直接使用标准的类库,也可以使用组合和继承等面向对象的特性

将java中数组转换为ArrayList的方法实例(包括ArrayList转数组)

方法一:使用Arrays.asList()方法 1 2 String[] asset = {"equity", "stocks", "gold", "foreign exchange","fixed income", "futures", "options"}; List<String> assetList = Arrays.asList(asset);

java中数组有没有length()方法?string没有lenght()方法?

java中数组有没有length()方法,求数组的长度可以使用数组的length属性. int[] arr={1,2,3,4,5}; int length=arr.length;//求数组的长度 ---------------------------------------------------------------------------------------- String 有length()方法,用来求字符串的长度 String  str="Hello"; int leng

Java 中数组的内存分配

Java 中数组的内存分配 1.Java 程序在运行时,需要在内存中分配空间.为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据和内存管理方式. 2.数组基本概念 数组是存储同一种数据类型多个元素的容器. 数组既可以存储基本数据类型,也可以存储引用数据类型. 格式:数据类型[] 数组名 ; int[] arr; 数组的初始化方式: 动态初始化 : 初始化时只指定数组长度,由系统为数组分配初始值. 格式:数据类型[] 数组名 = new 数据类型[数组长度]; 数组长

在java 中,数组与 List&lt;T&gt; 类型的相互转换

在java中,数组与List<T> 之前进行互相转换,转换方法可总结为以下几种: 一. 将 数组转换成List<T> 1. 使用 Collections 的addAll 方法 String[] myStr = {"1","2","4","9","7"}; List<String> listStr = new ArrayList<String>(); Colle

C++ 的向量结构结合了Java中数组和向量两者的优点

C++ 的向量结构结合了Java中数组和向量两者的优点.一个C++ 的向量可以方便的被访问,其容量又可以动态的增长.如果 T 是任意类型,则 vector<T> 是一个元素为 T 类型的动态数组.下面的语句 vector<int> a; 产生一个初始为空的向量.而语句 vector<int> a(100); 生成一个初始有100个元素的向量.你可以使用push_back 函数来添加元素: a.push_back(n); 调用 a.pop_back() 从a中取出最后一个

Java中数组的初始化方式

Java中数组的初始化方式    初始化方式有两种: 1.静态初始化:初始化时由程序猿显式指定每一个数组元素的初始值,由系统指定数组长度 2.动态初始化:初始化时由程序猿仅仅指定数组长度,由系统为数组元素分配初始值