您的位置:首页 > 编程语言 > Java开发

java基础_09_集合

2014-03-23 14:43 267 查看
集合
用于存储对象(对象的引用地址)

集合的结构图



Collection
|--List:元素是有序的,按存入次序依次存放,元素可以重复。因为该集合体系有索引。
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快,但是增删稍慢。线程不同步。
|--LinkedList:底层使用的是链表数据结构。特点:增删速度很快,但查询稍慢
|--vector:底层是数组数据结构。线程同步。被ArrayList替代了。

|--Set:元素是无序的,按指定排序方法存放,元素不可以重复
|--HashSet:底层数据结构是哈希表
|--TreeSet:底层数据结构是二叉树,可以对Set集合中的元素进行排序。
保证元素唯一性的依据:compareTo方法return0;

Set集合的功能和Collection是一致的,其实,Set底层就是使用了Map集合。

Map
|--Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。JDK1.0效率低
|--HashMap:底层是哈希表数据结构,允许使用null值和null键,该集合是不同步的。将hashtable替代,jdk1.2效率高
|--TreeMap:底层是二叉树数据结构。线程不同步。可以用于给Map集合中的键进行排序。

Collection接口
集合的根接口。
1,add方法参数类型是Objext以便于接收任意类型对象
2,集合中存储的都是对象的引用(地址)
3,集合转数组。
例:Strings=newString[集合.size()];
为什么要将集合变数组?
为了限定对元素的操作,(不需要进行增删了,只能查就行)
注:Arrays类中有大量操作数组的静态方法。

Collections类
此类完全由在collection上进行操作或返回collection的静态方法组成.
常用方法:
sort(List<T>list)根据元素的自然顺序对指定列表按升序进行排
swap(List<?>list,inti,intj)在指定列表的指定位置处交换元素
shuffle(List<?>list)对集合元素随机排序
reverse(List<?>list)反转指定列表中元素的顺序
reverseOrder()返回一个比较器,它强行逆转实现Comparable接口的对collection的自然顺序。
reverseOrder(Comparator<T>cmp)返回一个比较器,它强行逆转指定比较器的顺序
例:
TreeSet<String>ts=newTreeSet<String>(Collections.reverseOrder(newMycomparator()));
classMycomparatorimplementsComparator<String>
{
publicintcompare(Strings1,Strings2)
{
intnum=s1.length()-s2.length();
if(num>0)
return1;
if(num<0)
return-1;
returns1.compareTo(s2);
}
}

下面是一些常用的集合:
List集合
特点:所存入的元素是按存入顺序存放的,元素可以重复。

List集合特有的迭代器:ListIterator是Iterator的子接口。
如果想要操作如添加,修改等,就需要使用其子接口ListIterator

如何将数组转变成集合呢?

Arrays:用于操作数组的工具类,里面都是静态方法。

数组转集合有什么好处?

可以使用集合的思想和方法来操作数组中的元素。

注意:将数组变成集合,不可以使用集合的增删方法。

因为数组的长度是固定的。

如果增删会发生UnsupportedOperationException异常。

注意:如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转成集合中的素。
如果数组中的元素都是基本数据类型,那么会将该数组作为集合的元素存在。

例:

Strings[]={"a","bbbd","kcd","z"};

List<String>list=Arrays.asList(s);

inta[]={2,4,5};

List<int[]>li=Arrays.asList(a);//2,4,5表示的是基本数据类型

Integernum[]={2,4,5};

List<Integer>li2=Arrays.asList(num);//2,4,5会自动装箱,本身就是对象了

下面两个常用的List集合,如果想支持随机访问,而不必在首尾的任何位置插入或删除元素,那么使用ArrayList集合,如果要对集合进行频繁的添加和删除操作,对集合的首尾操作多,那么使用LinkedList集合更好。它提供了很多处理元素的方法。
1,ArrayList
底层的数据结构使用的是数组结构。
特点:查询速度很快,但是增删稍慢。线程不同步。
该类封装了一个动态再分配的Object[]数组,每个ArrayList对象有一个capacity.这个capacity表示存储列表中元素的数组的容量,在向集合中加入元素时,capacity在自动增加。
注意:contains(Objecto)方法,内部自动调用equals方法来比较的。

(o==null?e==null:o.equals(e))
例:
//去重复元素
 publicstaticArrayListmethod(ArrayListal)
    	{
    		Listnewal=newArrayList();
    
    		Iteratorit=al.iterator();
    
    		while(it.hasNext())
    		{
    		Objectobj=it.next();
    			if(!newal.contains(obj))
    				newal.add(obj);
    		}
    		returnnewal;
    	}


2,LinkedList
底层使用的链表数据结构。特点:增删速度很快,但查询稍慢
该类添加了一些处理列表两端元素的方法。实现所有可选的列表操作,并且允许所有元素
(包括null)。除了实现List接口外,LinkedList类还为在列表的开头及结尾get、remove和insert元素提供了统一的命名方法。

3,Vector
底层是数组数据结构。线程同步。被ArrayList替代了。
枚举就是Vector特有的取出元素方式
其实枚举和迭代是一样的,因为枚举的名称以及方法的名称都过长,所以被换代器取代了
使用方法:


	Vectorv=newVector();v.add("java001");v.add("java002");Enumerationen=v.elements();while(en.hasMoreElements()){System.out.println(en.nextElement());}


4,Stack

Stack类表示后进先出(LIFO)的对象堆栈。它通过五个操作对类Vector进行了扩展,允许将向量视为堆栈。它提供了通常的push和pop操作,以及取堆栈顶点的peek方法、测试堆栈是否为空的empty方法、在堆栈中查找项并确定到堆栈顶距离的search方法.

Set集合
特点:所存入的元素按指定排序方法存放元素(即不是按存入顺序存放),不可以重复元素。

Set底层是使用了Map集合。
1,HasHSet
数据结构是哈希表,线程是非同步的
保证元素唯一性的原理:
判断元素的hashCode值是否相同。如果相同,还会继续判断元素的equals方法,是为true如果不同,不会判断equals

一般使用HashSet都须要覆盖hashCode()、equals()两个方法
例:

往HashSet集合中存入自定义对象。

假设:姓名和年龄相同为同一个人,是重复元素。

publicinthashCode()//自动调用,复写父类。调用这个才有机会去调用equals方法

{

returnname.hashCode()+age*37;//只要返回的hashCode值唯一就行

}

publicbooleanequals(Objectobj)//复写父类

{

if(!(objinstanceofPerson))

returnfalse;

Personp=(Person)obj;

returnthis.name.equals(p.name)&&this.age==p.age;

}
注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals方法
记住:排序时,当主要条件相同时,一定要判断一下次要条件。

hashCode()作用:
hashCode()值可以说成是对象在内存中计算出来的一个值,如果值等,说明对象是同一个对象,所以这里程序员可以通过复写hashCode()来判断让其那些是同一类型。为了提高效率,让其在查找集合中是否有相同对象的时候,把hashCode()值在内存中进行了分区存放的,这样查找起来就效率提高了。正因为这样,所以在一个对象存入hash集合中的时候,就不要去更改对象中的值了,否则就会产生内存泄漏(就是内存浪费)。为什么呢?因为更改了值后,导致hashCode的改变,导致存放的区域发生了变化,所以再去删除这个对象的时候,这个对象已不在这个区域了,是无法删除到这个对象的,删除的是没改之前的对象,而这个对象已没用了。放在这里就是一处内存泄漏。

2,TreeSet
底层数据结构是二叉树。
特点:可以对Set集合中的元素进行排序。

但必须指明排序要求。

例:

TreeSetts=newTreeSet(newMyCompare());

newMyCompare()就是比较器
保证元素唯一性的依据:compareTo方法return0;

排序方式:两种

TreeSet排序的第一种方式:
让元素自身具备比较性。这种方式也称为元素的自然顺序,或者叫做默认顺序。
使用方法:

1,该类实现Comparable接口

2,覆盖compareTo方法

例:
    classStudentimplementsComparable//1,实现Comparable接口该接口强制让学生具备比较性
    {
    publicintcompareTo(Objectobj)//2,覆盖compareTo方法,是自动调用的
     {
     //按照学生的年龄进行排序
     if(!(objinstanceofStudent))
     thrownewRuntimeException("不是学生对象");
    
     Students=(Student)obj;
     if(this.age>s.age)
     return1;
     if(this.age==s.age)
     {
     returnthis.name.compareTo(s.name);//字符串的比较功能
     }
     return-1;
    
    /*
    注意:如果想实现按怎么进来的怎么出去
    只须compareTo方法return-1;或return1;即可。
    因为二叉树:存放的时候是大的放在右边,小的放在左边,
    默认输出从小到大。
    -1表示小0表示等1表示大
    */
    }
    }

TreeSet的第二种排序方式:

当元素自身不具备比较性时,或者具备的比较性不是所需要的。

这时就需要让集合自身具备比较性。
使用方法:
1,定义比较器,实现Comparator接口
2,覆盖compare方法

3,将比较器对象作为参数传递给TreeSet集合的构造函数。
例:
需求:现在要求按学生姓名排序。
    classMyCompareimplementsComparator		//1,定义比较器,实现Comparator接口
    {
     publicintcompare(Objecto1,Objecto2) //2,复写compare方法
     {
     Students1=(Student)o1;
     Students2=(Student)o2;
    
     intnum=s1.getName().compareTo(s2.getName());
     if(num==0)
     {
     if(s1.getAge()>s2.getAge())
     return1;
     if(s1.getAge()<s2.getAge())
     return-1;
     return0;
     }
     returnnum;
     }
    }

注意:如果自身具有比较性,但又传入了比较器,那么以比较器为主。

Map集合
Map接口不是Collection接口的继承。
和Set很像,其实,Set底层就是使用了Map集合。

什么时候使用map集合呢?
当数据之间存在映射关系时,就可以使用map集合,因为Map集合中存放就是映射关系。

Map集合的两种取出元素方式:

Map集合的取出原理:将Map集合转成Set集合,在通过迭代器取出。

一,Set<K>keySet
将Map中所有的键存入到Set集合,因为Set具备迭代器。
所以可以用迭代方式取出所有的键,在根据get方法。获取每一个键对应的值。
例:
    Map<String,String>map=newHashMap<String,String>();
    
    Set<String>keySet=map.keySet();//1,获取Map集合的所有键,保存到Set集合

    Iterator<String>it1=keySet.iterator();以键值迭代
    while(it1.hasNext())
    {
    Stringskey=it1.next();
     Stringsvalue=map.get(skey);通过键值获取对应的值。
    
     System.out.println("key:"+skey+"_____"+svalue);
    }


二,Set<Map.Entry<k,v>>entrySet
将Map集合中的映射关系存入到Set集合中,而这个关系的数据类型就是:Map.Entry然后在通过迭代器来取数据。
例:
    Map<String,String>map=newHashMap<String,String>();
    
    //将Map集合中的映射关系取出,存入到Set集合中
    Set<Map.Entry<String,String>>entrySet=map.entrySet();
    Iterator<Map.Entry<String,String>>it=entrySet.iterator();
    while(it.hasNext())
    {
    Map.Entry<String,String>me=it.next();//迭代器中返回的值的类型和泛型<>里的类型一样
     Stringkey=me.getKey();
     Stringvalue=me.getValue();
     System.out.println(key+"..."+value);
    }


1,HashMap
底层是哈希表数据结构,允许使用null值和null键,该集合是不同步的。将hashtable替代,jdk1.2效率高,适合在集合中插入,删除和定位元素。

例:
Map<String,String>map=newHashMap<String,String>();
map.put("01","zhangsan1");
map.put("01","zhangsan1");//如果出现添加相同的键,那么后添加的值会覆盖原有键对应值,并返回被覆盖的值。

判断一个键是否存在?
可以通过get方法的返回值来判断一个键是否存在。通过返回null来判断
System.out.println(map.get("04"));//返回null

获取map集合中的Collection视图。
Collection<String>coll=map.values();

2,TreeMap
底层是二叉树数据结构。线程不同步。可以用于给Map集合中的键进行排序。
如果想按自然顺序或自定义顺序排序,使用该集合。
例:

字符串“osjfosj0fwamfw0fimdsoja”获取该字符串中的字母出现的次数。

希望打印结果:a(1)b(3)c(2)....

思路:通过结果可以看到,每一个都有对应的次数,说明字母和次数之间都有映射关系。

所以选择Map集合,因为输出结果是有序的,所以使用TreeMap

步骤:

1,将字符串转换成字符数组,因为要对每一个字母进行操作。

2,定义一个map集合,因为打印结果的字母有顺序,所以使用TreeMap集合

3,遍历字符数组

将每一个字母作为键去查map集合

如果返回null,将该字母和次数1存入到map集合

如果返回不是null,说明字母已存在,把对应的次数加1

4,遍历map集合以指定形式打印。
    publicstaticvoidcharCount2(Stringstr)
     {
     charchs[]=str.toCharArray();//1,返回字符数组
    
     //泛型里放的是引用对象
     TreeMap<Character,Integer>tm=newTreeMap<Character,Integer>();
    
     intcount=0;
     for(inti=0;i<chs.length;i++)
     {
     Integervalue=tm.get(chs[i]);//不存在就返回null
     if(value!=null)
     count=value;
     count++;
     tm.put(chs[i],count);//加入集合,如有就更新这对值
     count=0;
     }
    
     Set<Map.Entry<Character,Integer>>entrySet=tm.entrySet();
     Iterator<Map.Entry<Character,Integer>>it=entrySet.iterator();
    
     while(it.hasNext())
     {
     Map.Entry<Character,Integer>me=it.next();
     Characterch=me.getKey();
     Integervalue=me.getValue();
     System.out.print(ch+"("+value+")");
     }
     }

3,Hashtable
底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。JDK1.0效率低

扩展练习:

一个学校有多个班级,一个班级有多个学生(学号姓名)。

拿一个集合来放班级。(学校---班级)

拿一个集合来放学生。(班级--学生)
如:
学校集合,存放班级
    HashMap<String,HashMap<String,String>>czbk=
    newHashMap<String,HashMap<String,String>>();
    
    班级集合,存放学生(学号姓名)
    HashMap<String,String>yure=newHashMap<String,String>();
    
    HashMap<String,String>jiuye=newHashMap<String,String>();
    
    //学校增加班级
    czbk.put("yureban",yure);
    czbk.put("jiuyeban",jiuye);
    
    //班级增加学生
    yure.put("01","zhansan");
yure.put("02","lisi");
jiuye.put("01","wangwu");
jiuye.put("02","zhaoliu");

//输出也是,先取班级,再通过班级取出学生信息。或也可以使用其它的方法来完成,但使用这种方法呢,我们还得对建立Student类,来保存学生信息,如果使用Map键值对呢,就可以不用写。

例:

    学校集合,存放班级
    HashMap<String,List<Student>>czbk=newHashMap<String,List<Student>>();
    班级集合,存放学生对象
    List<Student>yure=newArrayList<Student>();
    List<Student>jiuye=newArrayList<Student>();
    
    //学生信息
    classStudent(){}


Comparable与Comparator区别?
Comparable:适用于一个类自身具有比较性,即具有自然顺序的时候使用。
Comparator:定义自己的比较方式(比较器),即本身不具备比较性,或具有的比较性,不是把需要的。

注意:当两种排序都存在时,以比较器(Comparator)为主。(比较常用)
一般写好的代码不要去修改,实现接口就行了。(接口:功能扩展)
例:
按字符串长度排序
字符串本身具备比较性,但是它的比较方式不是所需要的,这时就只能使用比较器Comparator。
TreeSetts=newTreeSet(newStrLenComparator());classStrLenComparatorimplementsComparator//比较器{publicintcompare(Objecto1,Objecto2){Strings1=(String)o1;Strings2=(String)o2;intnum=s1.length()-s2.length();if(num==0)returns1.compareTo(s2);returnnum;}}


Iterator迭代器
什么是迭代器?
就是从集合里取出元素的方式。
因为每一种集合都有取出元素操作,所以把这个取方式封装成了一个类Iterator

使用方法:
集合:ArrayLista1=newArrayList();
Iteratorit=a1.iterator();//获取迭代器,用于取出集合中的元素
while(it.hasNext())//正向取出
{
System.out.println(it.next());
}
注意:在迭代时,不可以通过集合对象的方法操作集合中的元素。因为会发生并发操作异常
所以,在迭代器时,只能用迭代器的方法操作元素。
但Iterator方法有限,只能对元素进行判断,取出,删除等操作.

List集合特有的迭代器:ListIterator
它可以添加,修改,按任一方向遍历列表,获得迭代器在列表中的当前位置等。该接口只能通过List集合的ListIterator方法获取。
例:
ListIteratorli=a1.listIterator(al.size());//这里注意指定指针位置。
while(li.hasPrevious())//从后往前取出
{
System.out.prinln(li.previous());
}

心得:
这么多集合,我们在使用集合的时候要注意应该选用什么样的集合,选对集合,对于我们操作对象什么都是很方便的,List集合中存放的元素是无序的,适用于对元素无须排序,而且元素可以重复出现。Set集合呢,元素是不能重复出现的,存放的元素进行过排列的。适用于要对对象按一定要求进行排序,去除重复元素等。这里排序工作可以由Compareble或Comparetor(自定义比较器)来完成。Set集合底层就是由Map集合来完成的。Map集合呢,适用于保存那些有映射关系的。List、Set集合都是使用Iterator迭代器来输出集合内容,对于Liste还有一个特有的ListIterator迭代方法,这个提供了操作集合的一些方法,如:删除,修改等。Map集合的输出要先通过自己的方法,转换成Set集合,然后Set集合在通过Iteraor来输出。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: