黑马程序员-集合
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
概念:
java中的集合也就是容器,容器就是用来存储对象用的,因此根据存储的特性上可以分为单列集合(Collection)和双列集合(Map)。
并且每一种容器都有自己的内部数据结构,所以我们会根据需要选择相应的容器。
集合框架结构:
单列集合:
1.List:元素可以重复,且有顺序有角标(索引),怎么添加进去,就怎么取出来。(list的contains方法其实就是调用元素的equals方法去判断的)
1-1 Vector:内部是数组数据结构,并且是同步的。(底层数组以100%增长)
1-2 ArrayList:内部是数组数据结构,不是同步的,替代了vector。与LinkedList对比查询元素速度快,因为数组内存空间是连续的。(底层数组以50%增长)
1-3 LinkedList:内部是链表数据结构,不是同步的,增删元素速度快,查询慢因为链表结构内存空间是不连续的。
2.Set:元素不能重复,没有顺序。
2-1 HashSet:内部是哈希表结构,不同步。(在添加元素时,先调用hashcode方法,如果hashcode方法返回值相同继续判断equals方法判断内容是否相同以保证元素的唯一)
2-2 内部是二叉树结构,不同步。它有两种存放元素方式:
(1).按照元素的自然顺序。(实现Comparable节后,覆盖compareTo方法)
(2).给TreeSet集合指定比较器。(实现Comparator接口,实现compare方法)
注:这两种方式都是按照比较后的返回值进行确定位置的,正数就大,负数小,零表示这两个元素相同。
附:二叉树的节点分别存了三个要素,左边、 右边、父元素。在读取时是先读取左边元素在读取右边,最后读取父元素。
二叉树的 存放也是按照两元素比较后的值来确定的,为负时放左边,正时放右边,为零时不存。
其次二叉树在存放元素时都会将先前添加的元素进行折半,然后在确定下一个将添加的元素的位置这样来提高效率的。
LinkedList和ArrayList比较:
//ListIterator 是list特有的列表迭代器,该迭代器可以向后和向前遍历,还可以在迭代的同时对集合中的元素进行增删改查。
public class CollectionDemo {
/**
* @param args
*/
public static void main(String[] args) {
List<String> collection= new ArrayList<String>();
collection.add("abc1");
collection.add("abc2");
collection.add("abc3");
//Iterator<String> it=collection.iterator();
ListIterator<String> it=collection.listIterator();
while(it.hasNext()){
Object element=it.next();
if(element.equals("abc2")){
// collection.add("abc4");//在迭代器迭代过程中,用集合的方法对元素进行了操作,此时迭代器并不知道刚刚加入的元素,所以抛出java.util.ConcurrentModificationException。
//解决的办法是用列表迭代器同一对集合的元素进行迭代、操作。
it.add("abc4");
}else {
System.out.println("next:"+element);
}
}
System.out.println(collection);
SpeedTest();//选择容器时平凡增删数据用LinkedList,查找用ArrayList
}
//测试linkedlist和arraylist增删的速度
public static void SpeedTest(){
List<String> arraylList=new ArrayList<String>();
List<String> linkedList=new LinkedList<String>();
for(int i=0;i<1000000;i++){
linkedList.add("abc"+i);
arraylList.add("abc"+i);
}
long startTime=System.currentTimeMillis();
for(int i=0;i<1000;i++){
linkedList.add(i, "aaa");
}
long endTime=System.currentTimeMillis();
System.out.println("LinkedList增加元素用时:"+(endTime-startTime)+" ms");
startTime=System.currentTimeMillis();
for(int i=0;i<1000;i++){
arraylList.add(i, "aaa");
}
endTime=System.currentTimeMillis();
System.out.println("ArrayList增加元素用时:"+(endTime-startTime)+" ms");
}
}
运行结果:
next:abc1
next:abc3
[abc1, abc2, abc4, abc3]
LinkedList增加元素用时:0 ms
ArrayList增加元素用时:2531 ms
因此证明在进行频繁增删操作时我们英应该选择LinkedList。
HashSet集合:
package cn.jiava.basic.collection;
import java.util.HashSet;
import java.util.Iterator;
//Set集合演示
public class SetDemo {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
HashSet set=new HashSet();
set.add("aaa");
set.add("bbb");
set.add("ccc");
set.add("ccc");
set.add("ddd");
//我们应该考虑最小内存开销,保证循环结束后迭代器被释放。
for( Iterator it=set.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
运行结果:
aaa
ddd
ccc
bbb
得出HashSet集合内部是哈希表,在存入对象时会先调用hashCode方法算哈希值,如果哈希值相同,则会调用对象的eqauls方法继续判断,如果返回true则认为对象重复,则不存入。同时存入的对象元素都是无序的。
LinkedHashSet:
<span style="font-size:14px;"><strong>package cn.jiava.basic.collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
//Set集合演示
public class SetDemo {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
//LinkedHashSet 集合既可以保证元素的唯一,也可以保证元素的存入和取出是有序的。
LinkedHashSet set=new LinkedHashSet();
set.add("aaa");
set.add("bbb");
set.add("ccc");
set.add("ccc");
set.add("ddd");
//我们应该考虑最小内存开销,保证循环结束后迭代器被释放。
for( Iterator it=set.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
运行结果:
aaa
bbb
ccc
ddd
TreeSet集合:
//如果TreeSet容器没有比较器,那么存入的对象具有自然顺序,否则报错。
public class Person implements Comparable{
private int age;
private String name;
public Person() {
super();
}
public Person(String name,int age ) {
super();
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//在TreeSet容器没有比较器时,会调用此方法进行比较再存入容器。
//在这里按照人的年龄进行比较
@Override
public int compareTo(Object o) {
if(!(o instanceof Person)){
throw new ClassCastException("类型不合法");
}
Person p=(Person) o;
int temp=this.age-p.age;
return temp==0?this.name.compareTo(p.name):temp;
}
}
/TreeSet集合存入元素时根据元素自然顺序存入
public class TreeSetDemo {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
TreeSet ts=new TreeSet();
ts.add(new Person("zhangsan",22));
ts.add(new Person("lishi",21));
ts.add(new Person("wangwu",23));
ts.add(new Person("wbngwu",23));//如果年龄相同,则按次要条件年龄进行比较存入
ts.add(new Person("zhaoliu",20));
Iterator it=ts.iterator();
while(it.hasNext()){
Person person=(Person) it.next();
System.out.println(person.getName()+":::"+person.getAge());
}
}
}
<p>
<span style="font-size:14px;">运行结果:</span>
</p>
<p>
<span style="font-size:14px;">zhaoliu:::20
lishi:::21
zhangsan:::22
wangwu:::23
wbngwu:::23</span>
</p>
<p>
<span style="font-size:14px;"></span>
</p>
<pre class="java" name="code">//TreeSet还可以指定比较器,如果有比较器的时候会覆盖存入对象的自然顺序。
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;
}
/*实现元素怎么存入怎么取出(二叉树原理)
* public int compare(Object o1, Object o2) {
return 1;
}*/
}
public class TreeSetDemo {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
TreeSet ts=new TreeSet(new ComparatorByName());//指定容器的比较器
ts.add(new Person("zhangsan",22));
ts.add(new Person("lishi",21));
ts.add(new Person("wangwu",24));
ts.add(new Person("wangwu",23));//如果年龄相同,则按次要条件年龄进行比较存入
ts.add(new Person("zhaoliu",20));
Iterator it=ts.iterator();
while(it.hasNext()){
Person person=(Person) it.next();
System.out.println(person.getName()+":::"+person.getAge());
}
}
}
运行结果:
lishi:::21
wangwu:::23
wangwu:::24
zhangsan:::22
zhaoliu:::20
从结果看出,当TreeSet传入自己的比较器后,尽管存入的对象有自己的自然顺序,但会被容器的比较器覆盖。
双列集合:
1.HashTable: 内部是哈希表结构,是同步的,不允许null作为键和值。
2.HashMap: 内部是哈希表结构,不同步的,允许null作为键和值。(HashSet内部就是通过HashMap实现的)
3.TreeMap:内部是二叉树结构的,不同步的,可以对集合中建进行排序。(TreeSet内部通过TreeMap实现)
HashSet集合:
//HashMap键重复被覆盖
public class HashMapDemo {
public static void main(String[] args) {
HashMap<Person, String> hm=new HashMap<Person, String>();
hm.put(new Person("zhangsan",22), "北京");
hm.put(new Person("lishi",20), "深圳");
hm.put(new Person("wangwu",21), "上海");
hm.put(new Person("zhaoliu",25), "天津");
hm.put(new Person("wangwu",21), "重庆");//会判断键的哈希值和equals方法是否相同,相同则覆盖。
//Map.Entry为内部类,通过该内部类的getKey和getValue方法可获得键和值。
for(Map.Entry<Person, String> me:hm.entrySet()){
System.out.println(me.getKey().getName()+":::"+me.getKey().getAge()+"..."+me.getValue());
}
}
}
TreeMap集合:
//TreeMap和TreeSet存入元素一样,根据自然顺序和集合的比较器进行存入。
public class TreeMapDemo {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
TreeMap<Person, String> hm=new TreeMap<Person, String>(new ComparatorByName());//传入集合比较器
hm.put(new Person("zhangsan",22), "北京");
hm.put(new Person("lishi",20), "深圳");
hm.put(new Person("wangwu",21), "上海");
hm.put(new Person("zhaoliu",25), "天津");
hm.put(new Person("wangwu",21), "重庆");
//Map.Entry为内部类,通过该内部类的getKey和getValue方法可获得键和值。
for(Map.Entry<Person, String> me:hm.entrySet()){
System.out.println(me.getKey().getName()+":::"+me.getKey().getAge()+"..."+me.getValue());
}
}
}
运行结果:
lishi:::20...深圳
wangwu:::21...重庆
zhangsan:::22...北京
zhaoliu:::25...天津
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------