JAVA入门

来源:互联网 发布:手机淘宝怎么秒杀东西 编辑:程序博客网 时间:2024/06/03 15:32

一、数组与集合

数组:可以存储基本数据类型,也可以存储对象类型,但是数组长度固定,不适合在对象数量未知的情况下使用。
集合:只能存储对象类型,长度可变,在程序中广泛使用(部分集合类内部实现其实就是使用数组)。

二、JAVA中的集合

这里写图片描述
通过上图可以发现整个体系中有三个顶级接口Collection,Map,Iterator,接下来依次讲解。


Collection

最基本的集合接口,用于存放一组对象,而每一个对象则称之为Collection的元素。JAVA SDK并没有提供继承自Collection的类,而是实现几个接口,其中最常用的有List和Set。

所有实现Collection的类都必须提供两个标准的构造函数:

  • 无参数的构造函数,用于构造一个空的Collection。
  • 参数为Collection的构造函数,用于创建一个新的Collection,而这个新的Collection将拥有与原Collection同样的元素。

Collection定义了很多方法,常用的有

int size()                        // 获取集合中元素的数量boolean isEmpty()                 // 判断集合中是否有元素boolean contains(Object o)        // 判断集合中是否有指定元素Iterator<E> iterator()            // 使用Iterator遍历集合Object[] toArray()                // 将集合转换成数组boolean add(E e)                  // 新增一个元素boolean remove(Object o)          // 删除指定元素void clear()                      // 清空集合中的元素

Set

表示数学意义上的集合概念,Set中不包含重复的元素,即Set中不存两个这样的元素e1和e2,使得e1.equals(e2)为true。

HashSet

最常用的Set实现,看名字就可以猜到会使用hashCode方法,虽然大多数系统类已经覆盖了Object类缺省的实现,但自定义的类,别忘记重写hashCode方法。

内部使用HashMap实现,为优化 HashSet 空间的使用,您可以调优初始容量和负载因子。

使用示例:

public static void main(String args[]) {    Set set = new HashSet();    set.add("Bernadine");    set.add("Elizabeth");    set.add("Gene");    set.add("Elizabeth");    set.add("Clara");    System.out.println(set);}

输出结果:

[Gene, Clara, Bernadine, Elizabeth]

根据输出可以看出,虽然Elizabeth字符串插入两次,但Set中实际上只有一个。

TreeSet

HashSet是无序的,而TreeSet是有序的。为了能够进行,添加到TreeSet中的元素必须是可排序的(实现了Comparable接口)

内部使用TreeMap实现

使用示例

public static void main(String args[]) {    Set set = new HashSet();    set.add("Bernadine");    set.add("Elizabeth");    set.add("Gene");    set.add("Elizabeth");    set.add("Clara");    System.out.println(set);    Set sortedSet = new TreeSet(set);    System.out.println(sortedSet);}

输出结果:

[Gene, Clara, Bernadine, Elizabeth][Bernadine, Clara, Elizabeth, Gene]

可以看出放进TreeSet中的元素自动进行的排序

List

允许重复项的有序集合,List关注的是索引,拥有一系列和索引相关的方法

void add(int index, Object element) boolean addAll(int index, Collection collection) Object get(int index) int indexOf(Object element) int lastIndexOf(Object element) Object remove(int index) Object set(int index, Object element)

ArrayList

内部使用数组实现,所以她拥有数组的优点,读取元素速度快,但增删元素时,需要对整个数组进行复制,效率低。

为了实现动态增长,ArrayList默认创建10个长度的数组,然后每次新增元素时,判断数组容量,当需要添加长度时,则新增当前数组长度一半的长度。

使用示例:

public static void main(String args[]) {    List<String> list = new ArrayList();    list.add("Bernadine");    list.add("Elizabeth");    list.add("Gene");    list.add("Elizabeth");    list.add("Clara");    for (String str : list) {        System.out.print(str + ",");    }}

输出结果:

Bernadine,Elizabeth,Gene,Elizabeth,Clara,

LinkedList

内部使用双向链表实现,所以增删元素效率高,但取元素时,必须从链表按顺序一个一个查找,效率低。

使用方法跟ArrayList差不多,只是内部实现方法不一样,可以在不同的场景下选择使用。

Vector

实现同ArrayList,但是是线程同步的,效率很低,实际开发中较少使用。


Map

Map接口也是集合类的顶级接口,但Map并没有继承Collection,而是自成一系,使用Key-Value(键值对)方式实现对对象的存放。

常用方法

Object put(Object key, Object value)    // 新增一个键值对Object remove(Object key)               // 根据Key删除一个键值对void putAll(Map mapping)                // 复制一个Map的内容至当前Mapvoid clear()                            // 清空一个MapObject get(Object key)                  // 根据Key获取值boolean containsKey(Object key)         // 判断Key是否存在boolean containsValue(Object value)     // 判断值是否存在int size()                              // 获取Map元素数量boolean isEmpty()                       // 判断Map是否有元素public Set keySet()                     // 获取Key集合public Collection values()              // 获取值集合public Set entrySet()                   // 获取Key-Value集合

HashMap

最常用的Map,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的,因为键对象不可以重复,所以HashMap最多只允许一条记录的键为Null,允许多条记录的值为Null,是非同步的。

内部实现使用Hash表数据结构,可以简单地理解为链表的数组,同时拥有链表插入删除元素效率高及数组寻址效率高的优点,并尽量去除链表寻址慢及数组插入删除元素效率低的缺点,使用方便,同时也不占用太多空间。结构如下图所示:

这里写图片描述

put

// 存储时:int hash = key.hashCode(); // 这个hashCode方法这里不详述,只要理解每个key的hash是一个固定的int值int index = hash % Entry[].length;Entry[index] = value;

但如果两个不同的Key返回的hash是一样的时候,Entry[index]将会被覆盖,这时HashMap使用了另一种策略。

比如:

第一个键值对A进来,通过计算其key的hash得到的index=0,记做:Entry[0] = A。
一会后又进来一个键值对B,通过计算其index也等于0,现在怎么办?HashMap会这样做:B.next = A,Entry[0] = B。
如果又进来C,index也等于0,那么C.next = B,Entry[0] = C;
这样我们发现index=0的地方其实存取了A,B,C三个键值对,他们通过next这个属性链接在一起。也就是说数组中存储的是最后插入的元素

get

// 取值时:int hash = key.hashCode();int index = hash % Entry[].length;return Entry[index];

首先根据Key的hashCode方法得到Key的hash值,获取数组下标,然后根据Key的equals方法,在链表上顺序判断哪一个才是真正相等的。

null key的存取

HashMap是允许Key为null的,但如果是null,就不能使用上面说的put/get方法的策略了,因为null不会有hash值。
所以JVM将null key总是存放为数组的第一个位置

遍历

KeySet()

Map map = new HashMap();map.put("key1","lisi1");map.put("key2","lisi2");map.put("key3","lisi3");map.put("key4","lisi4");  //先获取map集合的所有键的set集合,keyset()Iterator it = map.keySet().iterator(); //获取迭代器while(it.hasNext()){    Object key = it.next();    System.out.println(map.get(key));}

entrySet()

Map map = new HashMap();map.put("key1","lisi1");map.put("key2","lisi2");map.put("key3","lisi3");map.put("key4","lisi4");//将map集合中的映射关系取出,存入到set集合Iterator it = map.entrySet().iterator();while(it.hasNext()){   Entry e =(Entry) it.next();   System.out.println("键"+e.getKey () + "的值为" + e.getValue());}

推荐使用entrySet()方法,效率更高

TreeMap

TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序(自然顺序),也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。不允许key值为空,非同步的。

LinkedHashMap

LinkedHashMap保存了记录的插入顺序,在用Iteraor遍历LinkedHashMap时,先得到的记录肯定是先插入的,在遍历的时候会比HashMap慢,有HashMap的全部特性。

Hashtable

Hashtable与HashMap类似,是HashMap的线程安全版,它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢,它继承自Dictionary类,不同的是它不允许记录的键或者值为null,同时效率较低

ConcurrentHashMap

线程安全,并且锁分离。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。


Iterator

迭代器,Collection类实现了Iterator接口,所以所有的集合类都拥有了使用Iterator遍历集合的能力。

使用方法:

Iterator it = arr.iterator();while(it.hasNext()){    object o =it.next();     ...}
0 0
原创粉丝点击