您的位置:首页 > 职场人生

黑马程序员 笔记(十三)——集合框架

2013-04-02 11:19 232 查看
------- android培训java培训、期待与您交流! ----------

集合类 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式.在很多情况下,我们不知道在程序中需要创建多少个对象,这时就不能依靠定义引用对象的变量来持有每一个对象。存储对象的容器就能帮我们解决这样的问题,而集合便是这样的容器。数组和集合类同是容器,有何不同数组:存储对象,但长度是固定的,存储基本数据类型。
集合:存储对象,但长度是可变,存储对象。
集合的特点:集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
集合中存贮的是对象的地址。
集合框架概述Java中集合类定义主要是在java.util.*包下面。
集合的框架体系:


为什么需要这么多容器?因为每一个容器对数据的存贮方式都有不同,这种存贮方式称为:数据结构
Collection: 根接口(共性方法)(List:Set:)
增:add()方法的参数是Object,以便于接收任意类型的对象boolean add(E e):向容器中添加对象
addAll(Collcetion<? extends E> c):将指定 collection 中的所有元素都添加到此 collection 中

删void clear():移除此 collection 中的所有元素
boolean remove(Object o):从此 collection 中移除指定元素的单个实例,如果存在的话返回true
boolean removeAll(Collcetion<?> c)将集合中相同的部分去掉。

判断boolean contains(Object o):判断是否包含某一个对象
boolean containsAll(Collcetion<?> c):如果此 collection 包含指定 collection 中的所有元素,则返回true。

boolean equals(Object o):比较此 collection 与指定对象是否相等。

boolean isEmpty():判断容器中是否有对象。


查迭代器:取出集合内部元素的一个接口,该接口的子类定义在集合的内部。这样就可以直接访问集合内部的元素。因为每一个容器的数据结构不同,所以取出动作的实现细节也不同,但是都有共性内容(判断和取出)。因此将其共性抽取。以后任何集合只要在内部实现Iterator接口,就可以将其元素取出。
iterater iterater()

代码示例:
import java.util.*;
class CollectionDemo
{
public static void main(String[] args)
{
ArrayList a1 = new ArrayList();
ArrayList a2 = new ArrayList();

//添加元素(对象)	运用  add(Object obj)

a1.add("Where");
a1.add("there");
a1.add("is");

a2.add("I");
a2.add("Love");
a2.add("You");

a1.addAll(a2);

//获取个数,集合的长度
sop("a1的Size:"+a1.size()+"\n");

//删除元素
sop(a1.remove("You")+"\n");	//返回值为布尔型
sop(a1+"\n");

//取交集
sop(a2.retainAll(a1));//返回的结果是布尔型,表示是否有交集
sop("a1和a2的交集是:"+a2+"\n");//a1里现在是a1与a2的交集

//取出元素
//通过Iterator取出集合内的元素。
for (Iterator it=a1.iterator();it.hasNext() ; )
{
sop(it.next()+"\t");
}
}

public static void sop(Object o)
{
System.out.print(o);
}
}


List:(Collection的子类之一)

特点:元素是有序的,元素可以重复,因为该集合体系中有索引
常见子类对象:

ArrrayList:底层的数据结构使用的是数组结构

特点:查询速度很快,因为有索引(角标),但增删速度稍慢。是线程不同步的。

LinkedList:底层使用的是链表的结构

特点:增删速度很快,但查询速度稍慢,因为每一个元素都链接到前一元素

Vector:底层是数组结构,线程同步,被ArrayList代替。

List中的特有方法:(凡事可以操作角标的方法都是该体系的特有方法)



void add(index,E e):在指定位置添加对象
void add(index,Collection);在指定位置插入一个集合



E remove(index):删除指定位置上的元素



set(index,element):修改指定位置上的元素



E get(index):获取指定位置的元素。
通过迭代器Iterator进行取出:取出所有的元素。

迭代器是取出元素的方式。把取出方式定义在集合的内部,这样取出方式就可以直接访问集合的内的元素。
因为每一个容器的数据结构有所不同,所以取出的动作也不一样。但是都有共性的内容,判断和取出。因此就把这些共性的方法抽取出来,形成Iterator接口。

int indexOf(Object o):获取该对象在容器中的位置。
List subList(int fromIndex, int toIndex)获取指定到指定结束位置的对象。
列表迭代器:ListIterator是Iterator的子接口

在迭代时,不可以通过集合对象的方法操作集合中的元素。因为会发生ConcurrentModificationException异常,所以在迭代时,只能用迭代器的方法操作元素,可是Iterator方法是有限的。只能对元素进行判断,取出,删除的操作,如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。该接口只能通过List集合的listIterator方法获取

LinkedList:(链接列表)

特有方法:

void addFirst(E e)
void addLast(E e)
E get First()//get方法获取元素,但是不删除元素。当集合为空时,则抛出没有这个元素的异常。
E getLast()
E remove()//remove方法获取元素,并且删除该元素。当集合为空时,则抛出没有这个元素的异常
E remove(int index)
E removeFirst()
E removeLast()
在JDK1.6中出现了替代方法

offerFirst() 替代void add方法
offerLast()
peekFirst()替代get方法
peekList()
pollFirst()替代remove方法
pollLast()

LinkedList示例:

/*
使用LinkedList模拟一个堆栈或者队列数据结构。

堆栈:先进后出  如同一个杯子。
队列:先进先出 First in First out  FIFO 如同一个水管。
*/

import java.util.*;
class DuiLie
{
private LinkedList link;

DuiLie()
{
link = new LinkedList();
}

public void myAdd(Object obj)
{
link.addFirst(obj);
}
public Object myGet()
{
return link.removeFirst();
}
public boolean isNull()
{
return link.isEmpty();
}
}

class  LinkedListTest
{
public static void main(String[] args)
{
DuiLie dl = new DuiLie();
dl.myAdd("java01");
dl.myAdd("java02");
dl.myAdd("java03");
dl.myAdd("java04");

while(!dl.isNull())
{
System.out.println(dl.myGet());
}
}
}


Vector方法中的特殊方法(枚举)

Enumeration elements()就是vector特有的取值方式(枚举)。相当与迭代器。

Enumeration elements()中的方法:

boolean hasMoreElements()
E nextElements()

由于枚举的名称以及方法的名称都过长,所以被迭代器取代了.

Set

特点:没有索引,元素不可重复,存入和取出的顺序不一定一致。
功能:和ArrayList

常见子类:

hashSet():底层数据结构是哈希表。
TreeSet():底层的数据结构是二叉树。可以对Set集合中的元素进行排序(默认按ASCII编码)。

hashSet()

hashSet如何保证元素的唯一性?

通过调用元素的hashCode()方法和equals()方法来完成。如果元素的hashCode值相同,就接着判断equals()方法。如果都相同,则不会把重复的元素存进集合。(只有在hashCode的值相同的时候才会调用equasl方法进行比较。)
在尽力hashSet集合时,一般都要复写hashCode()和equals()方法,建立自己特有的比较方式,来提高工作效率。并且在复写hashCode()方法时,得保证hash值的唯一性。

对于判断元素是否存在以及删除等操作,依赖的方法是元素的hashCode()和equals()方法。

TreeSet()

可以对Set集合中的元素进行排序(默认是按字母的ASCII码的顺序)。

原理:当每次存进一个元素的时候,该集合对象就会自动调用该元素的compareTo()方法,将这个元素与已有的元素进行比较。通过返回的值将元素通过二叉树的结构进行存放。
TreeSet的排序

TreeSet排序的第一种方式:让元素自身具备比较性,元素需要实现Comparable接口,覆盖compareTo方法。也种方式也成为元素的自然顺序,或者叫做默认顺序。
示例:
class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();

ts.add(new Student("lisi02",22));
ts.add(new Student("lisi007",20));
ts.add(new Student("lisi09",19));
ts.add(new Student("lisi08",19));

Iterator it = ts.iterator();
while(it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}

class Student implements Comparable//该接口强制让学生具备比较性。
{
private String name;
private int age;

Student(String name,int age)
{
this.name = name;
this.age = age;
}

public int compareTo(Object obj)//覆盖compareTo方法,建立自己的比较方式。
{

if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s = (Student)obj;

System.out.println(this.name+"....compareto....."+s.name);
if(this.age>s.age)
return 1;
if(this.age==s.age)
{
return this.name.compareTo(s.name);
}
return -1;
}

public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}


TreeSet的第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性,在集合初始化时,就有了比较方式。当两种排序都存在时,以比较器为主。比较器的建立 定义一个类,实现Comparator接口,覆盖compare方法。

示例:
class Student implements Comparable//该接口强制让学生具备比较性。
{
private String name;
private int age;

Student(String name,int age)
{
this.name = name;
this.age = age;
}

public int compareTo(Object obj)
{
if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s = (Student)obj;

if(this.age>s.age)
return 1;
if(this.age==s.age)
{
return this.name.compareTo(s.name);
}
return -1;
}

public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
class TreeSetDemo2
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();

ts.add(new Student("lisi02",22));
ts.add(new Student("lisi02",21));
ts.add(new Student("lisi007",20));
ts.add(new Student("lisi09",19));
ts.add(new Student("lisi06",18));
ts.add(new Student("lisi06",18));
ts.add(new Student("lisi007",29));

Iterator it = ts.iterator();
while(it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}

class MyCompare implements Comparator	//定义比较器  实现Compare接口
{
public int compare(Object o1,Object o2)
{
Student s1 = (Student)o1;
Student s2 = (Student)o2;

int num = s1.getName().compareTo(s2.getName());
if(num==0)
{
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
}
return num;
}
}


TreeSet排序的另外一种方式:在构造集合的时候向集合中传入一个“比较器实体”。

应用场合:当元素自身不具备比较性时,或者具备的比较性不是所需要的。
比较器的定义:定义一个类实现Comparator接口,覆盖其中的compare()方法。compare()方法中定义的是比较的内容。
当集合中的元素和集合都有比较的功能的时候,输出的结果是按照集合的比较方式排序的。
示例:

import java.util.*;	//导入包
class Student implements Comparable	//定义学生类,并且让其具有比较性
{
private int age;
private String name;
private String id;

Student(String name,int age,String id)
{
this.name = name;
this.age = age;
this.id = id;
}

public int compareTo(Object obj)
{
if (!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
else
{
System.out.println(this.getName()+"       "+this.getAge());
Student s = (Student) obj;
if(this.age != s.age)
return this.age - s.age;
else if(this.name != s.name)
return this.name.compareTo(s.name);
return this.id.compareTo(s.id);
}

}

public String getName()
{
return(this.name);
}

public int getAge()
{
return(this.age);
}

public String getId()
{
return(this.id);
}
}

class MyCompartor implements Comparator	//定义一个比较器
{
public int compare(Object obj1,Object obj2)
{
if (!(obj1 instanceof Student)&&(obj2 instanceof Student))
throw new RuntimeException(obj1+"and"+obj2+"中有对象不是学生类");
else
{
Student stu1 = (Student) obj1;
Student stu2 = (Student) obj2;

int num1 = new Integer(stu1.getName().length()).compareTo(new Integer(stu2.getName().length()));
if (num1 == 0)
{
int num2 = new Integer(stu1.getAge()).compareTo(new Integer(stu2.getAge()));
if(num2 == 0)
{
return new String(stu1.getId()).compareTo(new String(stu2.getId()));
}
return num2;
}
return num1;
}
}
}
class MyTreeSet
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet(new MyCompartor());
ts.add(new Student("Zhang,Honemi",23,"520"));
ts.add(new Student("Zhang,Honemi",22,"520"));
ts.add(new Student("Zhang,Honemi",25,"520"));
ts.add(new Student("Zhang,Honemi",23,"521"));
ts.add(new Student("Zhang,Honemix",23,"520"));

for (Iterator it = ts.iterator();it.hasNext() ; )
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"……"+stu.getAge()+"……"+stu.getId());
}
}
}


Map接口极其子类
Map接口(Map(Key,Value))是实现键-值映射数据结构的一个框架,可以用于存储通过键-值引用的对象。映射与集合有明显的区别,映射中的每个对象都是成对存在的。映射中存贮的每个对象都是通过一个键(key)对象来获取值(value)对象,键值的作用相当于数组中的索引,每一个键值都是唯一的(一个值只能对应一个键),可以利用键值来存贮数据结构中指定位置上的数据。这种存取不由键对象本身决定,而是通过一种散列技术进行处理,从而产生一个被称做散列码的整数值。散列码通常是一个偏置量,它相当于分派给映射的存贮去的起始位置。理想情况下,通过散列技术得到的散列码应该是在给定范围内均匀分布的整数值,并且每个键对象都应该得到不同的散列码。

Map接口中定义的常用方法

添加



V put(K key,Value v):向指定集合中添加指定的键-值映射关系。返回该键值之前对应的Value值。
void putAll(Map<? extends K,? extends V> m ):从指定映射中将所有映射关系复制到此映射中

删除

void clear():移除集合中的所有的映射关系。
V remove(Object key):如果存在指定的键对象,则移除该键对象的映射关系,并返回与该键对应的Value的值。

判断

boolean containsKey(Object key):如果存在指定的键的映射关系,则返回true,否则返回false
boolean containsValue(Object Value):如果存在指定值的映射关系,则返回true,否则返回false
boolean equals(Object o)用来查看指定的对象与该对象是否为同一个对象,是同一个对象返回true,否则返回false
boolean isEmpty():判断该集合是否存在键-值映射。如果不存在,返回true

获取

V get(Object key):如果存在指定的键对象,则返回与该键对象对应的值对象,否则返回null
int hashCode():返回此映射的哈希码值
int size():获得该集合中键-值映射关系的个数。
Collection<V> values():返回此映射中包含的值的Collection视图。
entrySet()
keySet()

常见方法演示

import java.util.*;
class MyMap
{
public static void main(String[] args)
{
Map<String,String> mymap = new HashMap<String,String>();//定义一个Map集合
//向集合中添加元素
/*
1.通过put方法存元素的时候,返回值是该键之前对应的值
2.在HashMap中null可以当作键值或者Value值存在。
*/
sop(mymap.put("01","Zhanghongmei"));
sop(mymap.put("01","Zhanghongmei1"));
mymap.put("02","ZHM");
mymap.put("03","meimei");
mymap.put("04",null);
mymap.put(null,"MM");

//判断集合中是否存在指定键或者指定值
sop("mymap是否存在键值03:"+mymap.containsKey("03"));
sop("mymap是否存在值ZHM:"+mymap.containsValue("ZHM"));
sop("mymapz中是否存在键值003:"+mymap.containsKey("003"));
sop("mymap中是否存在值ZHMx:"+mymap.containsValue("ZHMx"));

//通过values方法,把集合中value值,取出。并存储在一个Collection集合中,返回该集合。
sop("mymap中所有的值是:"+mymap.values());
}

public static<E> void sop(E e)
{
System.out.println(e);
}
}
/*
运行结果
===================================
null
Zhanghongmei
mymap是否存在键值03:true
mymap是否存在值ZHM:true
mymapz中是否存在键值003:false
mymap中是否存在值ZHMx:false
mymap中所有的值是:[MM, null, Zhanghongmei1, ZHM, meimei]
===================================
*/


Map集合的两种取出方式:

keySet():

思想:将Map集合中所有的键存入Set集合,再通过Set集合的迭代器,取出所有的键值,最后通过get(Object key)方法取出所有的Value值。
代码示例:
import java.util.*;
class MyMap1
{
public static void main(String[] args)
{
Map<String,String> mymap = new HashMap<String,String>();

//存入元素
mymap.put("01","Zhang");
mymap.put("02","Hong");
mymap.put("03","Mei");

//通过keySet方法取出键值
Set<String> se = mymap.keySet();

//获取Set集合的迭代器
for(Iterator<String> it = se.iterator();it.hasNext();)
{
String key = it.next();

//通过Map集合的get方法取出对应的value的值
String value = mymap.get(key);

sop(key+"="+value);
}
}

public static<E> void sop(E e)
{
System.out.println(e);
}
}
/*
运行结果
==============================
01=Zhang
02=Hong
03=Mei
==============================
*/


Set<Map.Entry<k,v>> entrySet():

Map.Entry是一个接口里面有5个方法。

boolean equals(Object o) :比较指定对象与此项的相等性。

K getKey() :返回与此项对应的键。

V getValue() :返回与此项对应的值

int hashCode() :返回此映射项的哈希码值

V setValue(V value) :用指定的值替换与此项对应的值。

思想:将集合的通过调用entrySet()方法,将该集合内的所有元素的映射关系取出,并存进一个Set集合中,并返回这个集合。通过迭代器依次取出这种关系Map.Entry,然后调用Map.Entry里面的方法可以取出key值和value值,还可以替换value值。
代码示例:
import java.util.*;
class MyMap2
{
public static void main(String[] args)
{
//建立一个Map集合
Map<String,String> mymap = new HashMap<String,String>();

//向Map集合中添加元素
mymap.put("02","-zhangsan2");
mymap.put("03","-zhangsan3");
mymap.put("01","-zhangsan1");
mymap.put("04","-zhangsan4");

//将Map集合中的关系通过entrySet方法取出,存放在Set集合中
Set<Map.Entry<String,String>> se = mymap.entrySet();

//通过迭代器一次取出这种关系
for (Iterator<Map.Entry<String,String>> it = se.iterator();it.hasNext() ; )
{
Map.Entry<String,String> re = it.next();

//通过Map.Entry的方法取出key和value值
String key = re.getKey();
String value = re.getValue();
sop(key+"="+value);
}
}

public static<E> void sop(E e)
{
System.out.println(e);
}
}
/*
运行结果
==================================
04=-zhangsan4
01=-zhangsan1
02=-zhangsan2
03=-zhangsan3
==================================
*/


Map接口的实现子类

Hashtable

特点:

此类实现一个哈希表,底层是哈希表数据接口该哈希表将键映射到相应的值。任何非
null
对象都可以用作键或值。
为了成功地在哈希表中存储和获取对象,用作键的对象必须实现
hashCode
方法和
equals
方法。
出现在1.0版本,线程是同步的。

HashMap

特点:

底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。除了非同步和允许使用 null 之外,HashMap 类与Hashtable 大致相同。

TreeMap

特点:

底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。

和Set很像,Set底层就是使用了Map集合。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: