集合框架结构图
Vector集合:
import java.util.Enumeration;
import java.util.Iterator;import java.util.Vector;
public class VectorDemo {
/**
* @param args
*/
public static void main(String[] args) {
Vector v = new Vector();
v.addElement("abc1");
v.addElement("abc2");
v.addElement("abc3");
v.addElement("abc4");
Enumeration en = v.elements();//枚举,现在没人用了 都用Iterator。
while(en.hasMoreElements()){
System.out.println("nextelment:"+en.nextElement());
}
Iterator it = v.iterator();
while(it.hasNext()){
System.out.println("next:"+it.next());
}
}
}
linkedList集合:
import java.util.Iterator;
import java.util.LinkedList;
public class LinkedListDemo {
/**
* @param args
*/
public static void main(String[] args) {
LinkedList link = new LinkedList();
link.addFirst("abc1");
link.addFirst("abc2");
link.addFirst("abc3");
link.addFirst("abc4");
// System.out.println(link);
// System.out.println(link.getFirst());//获取第一个但不删除。
// System.out.println(link.getFirst());
// System.out.println(link.removeFirst());//获取元素但是会删除。
// System.out.println(link.removeFirst());
while(!link.isEmpty()){
System.out.println(link.removeLast());
}
System.out.println(link);
// Iterator it = link.iterator();
// while(it.hasNext()){
// System.out.println(it.next());
// }
}
}
likedList面试练习:
import java.util.ArrayList;
/*
* 请使用LinkedList来模拟一个堆栈或者队列数据结构。
import java.util.LinkedList;
public class DuiLie {
private LinkedList link;
public DuiLie() {
link = new LinkedList();
}
/**
* 队列的添加元素的功能。
*/
public void myAdd(Object obj) {
link.addLast(obj);
}
public Object myGet() {
return link.removeFirst(); //先进先出。
}
public boolean isNull() {
return link.isEmpty();
}
}
*
* 堆栈:先进后出 First In Last Out FILO
*
* 队列:先进先出 First In First Out FIFO
*
* 我们应该描述这样一个容器,给使用提供一个容器对象完成这两种结构中的一种。
*/
public class LinkedTest {
/**
* @param args
*/
public static void main(String[] args) {
DuiLie dl = new DuiLie();
dl.myAdd("abc1");
dl.myAdd("abc2");
dl.myAdd("abc3");
dl.myAdd("abc4");
while(!dl.isNull()){
System.out.println(dl.myGet());
}
}
}
LinkedList:
addFirst();
addLast():
jdk1.6
offerFirst();
offetLast();
getFirst();.//获取但不移除,如果链表为空,抛出NoSuchElementException.
getLast();
jdk1.6
peekFirst();//获取但不移除,如果链表为空,返回null.
peekLast():
removeFirst();//获取并移除,如果链表为空,抛出NoSuchElementException.
removeLast();
jdk1.6
pollFirst();//获取并移除,如果链表为空,返回null.
pollLast();
ArrayList:
import java.util.ArrayList;
import java.util.Iterator;
import cn.itcast.p.bean.Person;
public class ArrayListTest {
/**
* @param args
*/
public static void main(String[] args) {
Person p1 = new Person("lisi1",21);
ArrayList al = new ArrayList();
al.add(p1);
al.add(new Person("lisi2",22));
al.add(new Person("lisi3",23));
al.add(new Person("lisi4",24));
Iterator it = al.iterator();
while(it.hasNext()){
// System.out.println(((Person) it.next()).getName()+"::"+((Person) it.next()).getAge()); 光标会往下移,同义一次循环内不能用两次it.next();
Person p = (Person) it.next(); //自定义对象涉及到强转,(因为add涉及接受所有对象,object类型的,所有的对象都被提升为Object类型了)
System.out.println(p.getName()+"--"+p.getAge());
}
// al.add(5);//al.add(new Integer(5)); 、//在1.4之前不可以,因为add只能接收对象,只能写a1.add(new Integer(5));在1.5版本以后可以的,因为自动装箱,
什么时候出现自动装箱:基本数据类型值赋值给了引用数据类型,
什么时候拆箱啊:当基本数据类型和引用数据变量做运算的时候是拆箱。
}
集合里面存的都是对象引,迭代器取对象也是通过引用:
}
拆箱:
HashSet:无序,只有一种取出方式。Iterator。
import java.util.HashSet;
import java.util.Iterator;
public class HashSetDemo {
/**
* @param args
*/
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add("hehe");
// hs.add("heihei");
hs.add("hahah");
hs.add("xixii");
hs.add("hehe");//无序保证不重复,唯一 添加不进去。
Iterator it = hs.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
哈希表(里面还是数组)
Set:元素不可以重复,是无序。
Set接口中的方法和Collection一致。
|--HashSet: 内部数据结构是哈希表 ,是不同步的。
如何保证该集合的元素唯一性呢?
是通过对象的hashCode和equals方法来完成对象唯一性的。
如果对象的hashCode值不同,那么不用判断equals方法,就直接存储到哈希表中。
如果对象的hashCode值相同,那么要再次判断对象的equals方法是否为true。
如果为true,视为相同元素,不存。如果为false,那么视为不同元素,就进行存储。
记住:如果元素要存储到HashSet集合中,必须覆盖hashCode方法和equals方法。
一般情况下,如果定义的类会产生很多对象,比如人,学生,书,通常都需要覆盖equals,hashCode方法。
建立对象判断是否相同的依据。
if(this.hashCode()== obj.hashCode() && this.equals(obj))
自定义,hashcode方法和equals方法,重新复写。如图:
哈希表确定元素是否相同
1,判断的是两个元素的哈希值是否相同。
如果相同,在判断两个对象的内容是否相同。
2,判断哈希值相同,其实判断的是对象的hashCode的方法。判断内容相同,用的是equals方法。
注意:如果哈希值不同,是不需要判断equals。
import java.util.HashSet;
import java.util.Iterator;
import cn.itcast.p.bean.Person;
/*
* 往hashSet集合中存储Person对象。如果姓名和年龄相同,视为同一个人。视为相同元素。
*/
public class HashSetTest {
/**
* @param args
*/
public static void main(String[] args) {
HashSet hs = new HashSet();
/*
* HashSet集合数据结构是哈希表,所以存储元素的时候,
* 使用的元素的hashCode方法来确定位置,如果位置相同,在通过元素的equals来确定是否相同。
*
*/
hs.add(new Person("lisi4",24));
hs.add(new Person("lisi7",27));
hs.add(new Person("lisi1",21));
hs.add(new Person("lisi9",29));
hs.add(new Person("lisi7",27));
Iterator it = hs.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println(p);
// System.out.println(p.getName()+"...."+p.getAge());
}
}
}
import java.util.HashSet;
import java.util.Iterator;
import cn.itcast.p.bean.Person;
/*
* 往hashSet集合中存储Person对象。如果姓名和年龄相同,视为同一个人。视为相同元素。
*/
public class HashSetTest {
/**
* @param args
*/
public static void main(String[] args) {
HashSet hs = new HashSet();
/*
* HashSet集合数据结构是哈希表,所以存储元素的时候,
* 使用的元素的hashCode方法来确定位置,如果位置相同,在通过元素的equals来确定是否相同。
*
*/
hs.add(new Person("lisi4",24));
hs.add(new Person("lisi7",27));
hs.add(new Person("lisi1",21));
hs.add(new Person("lisi9",29));
hs.add(new Person("lisi7",27));
Iterator it = hs.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println(p);
// System.out.println(p.getName()+"...."+p.getAge());
}
}
}
ArrayList自定义存储对象://只用equals就可以,而HashSet用 hashcode和equals。
import java.util.ArrayList;
import java.util.Iterator;
import cn.itcast.p.bean.Person;
/*
* 定义功能去除ArrayList中的重复元素。
*/
public class ArrayListTest2 {
/**
* @param args
*/
public static void main(String[] args) {
// demo();
// singleDemo();
ArrayList al = new ArrayList();
al.add(new Person("lisi1",21));
al.add(new Person("lisi2",22));
al.add(new Person("lisi3",23));
al.add(new Person("lisi4",24));
al.add(new Person("lisi2",22));
al.add(new Person("lisi3",23));
System.out.println(al);
al = getSingleElement(al);
System.out.println(al.remove(new Person("lisi2",22))); //reove这个删除一个元素,底层也是利用的equals。无论是删除一个元素还是包含这个元素,就是判断是否和
//该容器相同的元素,就要判断该容器判断包含元素相同的依据。对于Arraylist这样的集合判断equals(判断对象内容相同,不管地址)判断HashSet这样的容器
//就要判断Hashcode(地址值)和equals(对象内容)。所以想自定义的时候就要覆写Hashcode和equals方法
System.out.println(al);
}
/**
*
*/
public static void singleDemo() {
ArrayList al = new ArrayList();
al.add("abc1");
al.add("abc2");
al.add("abc2");
al.add("abc1");
al.add("abc");
System.out.println(al);
al = getSingleElement(al);
System.out.println(al);
}
public static ArrayList getSingleElement(ArrayList al) {
//1,定义一个临时容器。
ArrayList temp = new ArrayList();
//2,迭代al集合。
Iterator it = al.iterator();
while(it.hasNext()){
Object obj = it.next();
//3,判断被迭代到的元素是否在临时容器存在。
if(!temp.contains(obj)){
temp.add(obj);
}
}
return temp;
}
/**
*
*/
public static void demo() {
// al.add(5);//al.add(new Integer(5));
}
}
TreeSet:
|--TreeSet:可以对Set集合中的元素进行排序(使用元素自然顺序进行排序)。是不同步的。
判断元素唯一性的方式:就是根据比较方法的返回结果是否是0,是0,就是相同元素,不存。
TreeSet对元素进行排序的方式一:
让元素自身具备比较功能,元素需要实现Comparable接口。覆盖compareTo方法。
如果不要按照对象中具备的自然顺序进行排序。如果对象中不具备自然顺序。怎么办?
可以使用TreeSet集合第二种排序方式二:
让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法。
将该类对象作为参数传递给TreeSet集合的构造函数。
底层是:二叉树排序结构。
自然排序:
还有可以继承compare接口,覆写其中的compareto方法,进行自然排序,
也可以用comparator(比较器)继承这个接口并覆写其中的compare(o1,o2)方法。然后传进treeset对象中。
import java.util.TreeSet;
import cn.itcast.p.bean.Person;
import cn.itcast.p5.comparator.ComparatorByName;
public class TreeSetDemo {
/**
* @param args
*/
public static void main(String[] args) {
TreeSet ts = new TreeSet(new ComparatorByName());
/*
* 以Person对象年龄进行从小到大的排序。
*
*/
ts.add(new Person("zhangsan",28));
ts.add(new Person("lisi",21));
ts.add(new Person("zhouqi",29));
ts.add(new Person("zhaoliu",25));
ts.add(new Person("wangu",24));
Iterator it = ts.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
/**
*
*/
public static void demo1() {
TreeSet ts = new TreeSet();
ts.add("abc");
ts.add("zaa");
ts.add("aa");
ts.add("nba");
ts.add("cba");
Iterator it = ts.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
另一个包中的类定义的比较器类。
import java.util.Comparator;
import cn.itcast.p.bean.Person;
/**
* 创建了一个根据Person类的name进行排序的比较器。
*/
public class ComparatorByName implements Comparator {
@Override
public int compare(Object o1, Object o2) {
Person p1 = (Person)o1;
Person p2 = (Person)o2;
int temp = p1.getName().compareTo(p2.getName());
return temp==0?p1.getAge()-p2.getAge(): temp;
// return 1;//有序。
}
}
一般情况下,我们用的最多的是HashMap,在Map 中插入、删除和定位元素,HashMap 是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。如果需要输出的顺序和输入的相同,那么用LinkedHashMap 可以实现,它还可以按读取顺序来排列.
HashMap是一个最常用的Map,它根据键的hashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。HashMap最多只允许一条记录的键为NULL,允许多条记录的值为NULL。
HashMap不支持线程同步,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致性。如果需要同步,可以用Collections的synchronizedMap方法使HashMap具有同步的能力。
Hashtable与HashMap类似,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtable在写入时会比较慢。
LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的。
在遍历的时候会比HashMap慢TreeMap能够把它保存的记录根据键排序,默认是按升序排序,也可以指定排序的比较器。当用Iterator遍历TreeMap时,得到的记录是排过序的。
HashMap,LinkedHashMap,TreeMap的区别
Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复
HashMap
HashMap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。遍历时,取得数据的顺序是完全随机的。
HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null。
HashMap不支持线程的同步(即任一时刻可以有多个线程同时写HashMap),可能会导致数据的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力,或者使用ConcurrentHashMap。
Hashtable与 HashMap类似,它继承自Dictionary类。不同的是:它不允许记录的键或者值为空;它支持线程的同步(即任一时刻只有一个线程能写Hashtable),因此也导致了 Hashtable在写入时会比较慢。
LinkedHashMap
LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的。也可以在构造时带参数,按照应用次数排序。
在遍历的时候会比HashMap慢,不过有种情况例外:当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢。因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
TreeMap
TreeMap实现SortMap接口,能够把它保存的记录根据键排序。
默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。
三种类型分别在什么时候使用
1、一般情况下,我们用的最多的是HashMap。HashMap里面存入的键值对在取出的时候是随机的,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。
2、TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。
3、LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。
其他
1. HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的,只不过Set用的只是Map的key
2. Map的key和Set都有一个共同的特性就是集合的唯一性.TreeMap更是多了一个排序的功能.
3. hashCode和equal()是HashMap用的, 因为无需排序所以只需要关注定位和唯一性即可.
a. hashCode是用来计算hash值的,hash值是用来确定hash表索引的.
b. hash表中的一个索引处存放的是一张链表, 所以还要通过equal方法循环比较链上的每一个对象才可以真正定位到键值对应的Entry.
c. put时,如果hash表中没定位到,就在链表前加一个Entry,如果定位到了,则更换Entry中的value,并返回旧value
4. 由于TreeMap需要排序,所以需要一个Comparator为键值进行大小比较.当然也是用Comparator定位的.
a. Comparator可以在创建TreeMap时指定
b. 如果创建时没有确定,那么就会使用key.compareTo()方法,这就要求key必须实现Comparable接口.
c. TreeMap是使用Tree数据结构实现的,所以使用compare接口就可以完成定位了.
注意:
1、Collection没有get()方法来取得某个元素。只能通过iterator()遍历元素。
2、Set和Collection拥有一模一样的接口。
3、List,可以通过get()方法来一次取出一个元素。使用数字来选择一堆对象中的一个,get(0)...。(add/get)
4、一般使用ArrayList。用LinkedList构造堆栈stack、队列queue。
5、Map用 put(k,v) / get(k),还可以使用containsKey()/containsValue()来检查其中是否含有某个key/value。
HashMap会利用对象的hashCode来快速找到key。哈希码就是将对象的信息经过一些转变形成一个独一无二的int值,这个值存储在一个array中。我们都知道所有存储结构中,array查找速度是最快的。所以,可以加速查找。 发生碰撞时,让array指向多个values。即,数组每个位置上又生成一个梿表。
6、Map中元素,可以将key序列、value序列单独抽取出来。
使用keySet()抽取key序列,将map中的所有keys生成一个Set。
使用values()抽取value序列,将map中的所有values生成一个Collection。
为什么一个生成Set,一个生成Collection?那是因为,key总是独一无二的,value允许重复。
HashSet,TreeSet和LinkedHashSet的区别
Set接口
Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false。
Set判断两个对象相同不是使用==运算符,而是根据equals方法。也就是说,只要两个对象用equals方法比较返回true,Set就不 会接受这两个对象。
HashSet
HashSet有以下特点
不能保证元素的排列顺序,顺序有可能发生变化
不是同步的
集合元素可以是null,但只能放入一个null
当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。
简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相 等
注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对 象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。
LinkedHashSet
LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。
TreeSet类
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0
自然排序
自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。
obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是 负数,则表明obj1小于obj2。
如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0
定制排序
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法