集合与数组的区别;
1:数组是固定长度的;集合可变长度的。
2:数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
3:数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。
在使用一个体系时,原则:参阅顶层内容。建立底层对象。
ArrayList底层代码研究
transient关键字:
java语言的关键字,变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。
ArrayList底层是一个Object数组,对于ArrayList而言,它实现List接口、底层使用数组保存所有元素,其操作基本上是对数组的操作。
LinkedList研究
LinkedList底层的数据结构是基于双向循环链表的,且头结点中不存放数据,既然是双向链表,那么必定存在一种数据结构——我们可以称之为节点,节点实例保存业务数据,前一个节点的位置信息和后一个节点位置信息。
|--ArrayList:底层的数据结构是数组,线程不同步,ArrayList替代了Vector,查询元素的速度非常快。
|--LinkedList:底层的数据结构是链表,线程不同步,增删元素的速度非常快。
|--Vector:底层的数据结构就是数组,线程同步的,Vector无论查询和增删都巨慢。
Set接口
Set接口中的方法和Collection中方法一致的。Set接口取出方式只有一种,迭代器。
HashSet底层源码研究
Hash底层是HashMap,
对于HashSet集合,判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法。
|--TreeSet:对Set集合中的元素的进行指定顺序的排序。不同步。TreeSet底层的数据结构就是二叉树。
用于对Set集合进行元素的指定顺序排序,排序需要依据元素自身具备的比较性。
如果元素不具备比较性,在运行时会发生ClassCastException异常。
所以需要元素实现Comparable接口,强制让元素具备比较性,复写compareTo方法。
依据compareTo方法的返回值,确定元素在TreeSet数据结构中的位置。
TreeSet方法保证元素唯一性的方式:就是参考比较方法的结果是否为0,如果return 0,视为两个对象重复,不存。
TreeSet集合排序有两种方式,Comparable和Comparator区别:
1:让元素自身具备比较性,需要元素对象实现Comparable接口,覆盖compareTo方法。
2:让集合自身具备比较性,需要定义一个实现了Comparator接口的比较器,并覆盖compare方法,并将该类对象作为实际参数传递给TreeSet集合的构造函数。
第二种方式较为灵活。
package com.inphase.collection;import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class ListDemo {
public static void main(String[] args) {
Set<Person> set = new TreeSet<Person>();
set.add(new Person("张三1" , 30));
set.add(new Person("李四2" , 24));
set.add(new Person("张三3" , 29));
set.add(new Person("张三4" , 28));
set.add(new Person("张三5" , 25));
Iterator< Person > iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
package com.inphase.collection;
public class Person implements Comparable<Person> {
private String name;
private int age;
public String getName() {
return name;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int compareTo(Person o) {
//按照年龄大小排序
int num = age > o.age ? 1 : age-o.age ;
return num;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
return super.equals(obj);
}
@Override
public String toString() {
// TODO Auto-generated method stub
return name+"...."+age;
}
}
Map集合
|--Hashtable:底层是哈希表数据结构,是线程同步的。不可以存储null键,null值。
|--HashMap:底层是哈希表数据结构,是线程不同步的。可以存储null键,null值。替代了Hashtable.
|--TreeMap:底层是二叉树结构,可以对map集合中的键进行指定顺序的排序。
HashMap底层就是一个数组结构(Entry<K,V>[] table),数组中的每一项又是一个链表。
transient Entry<K,V>[] table;
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;</span>
int hash;
/**
* Creates new entry.
*/
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
public final K getKey() {
return key;
}
public final V getValue() {
return value;
}
.............
}
当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。
从HashMap中get元素时,首先计算key的hashCode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。