黑马程序员——Java 集合(上)(第八篇)

来源:互联网 发布:微信外卖系统源码下载 编辑:程序博客网 时间:2024/06/06 01:40

-----------android培训java培训、java学习型技术博客、期待与您交流!------------  


(1)List与Set有什么区别?为什么    

 (2)HashSet与TreeSet有什么区别?它们之间是如何判断元素的唯一性    



第一讲    集合框架

先看下面的图:


 

一、为什么出现集合类?

        面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。

 

二、数组和集合类同是容器,有何不同?

        数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象

 

三、集合类的特点

        集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。

            Collection

                     |--List//元素是有序的,元素可以重复。因为该集合体系有索引。

                     |--Set//元素是无序的,元素不可以重复。

 



一、List

组成

        List:元素是有序的,元素可以重复。因为该集合体系有索引。

            |--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。

            |--LinkedList:底层使用的是链表数据结构。特点:增删速度很快,查询稍慢。

            |--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。

 

二、List的特有方法

        凡是可以操作角标的方法都是该体系特有的方法。


ArrayList al = newArrayList();        //添加元素        al.add("01");        al.add("02");        al.add("03");        al.add("04");        //获取个数,集合的长度        System.out.println(al.size());        //删除元素        al.remove("01");        //判断元素        System.out.println(al.contains("02"));    ArrayList al2 = new ArrayList();        al2.add("01");        al2.add("02");    //取交集,al中存放的为交集    System.out.println(al.retainAll(al2));        System.out.println(al);  


 

三、ListIterator

1、概述 

        ListIteratorList集合特有的迭代器,是Iterator的子接口。

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

2ListIterator特有的方法

        add(obj);//增加

        set(obj);//修改为obj

        hasPrevious();//判断前面有没有元素

        previous();//取前一个元素

 

import java.util.LinkedList;import java.util.List;import java.util.ListIterator;public class TestListIterator{ public static void main(String args[]) {  TestListIterator tliterator=new TestListIterator();  List<String> list=new LinkedList<String>();  tliterator.initial(list);//初始化这个链接表  ListIterator<String>  li=list.listIterator();//将该链接表转化为ListIterator  //下面的代码进行ListIterator对象li的各种功能检测  //顺序输出迭代器中的元素  while(li.hasNext())  {System.out.print(li.next().toString()+" ");}  //验证add方法,给li添加两个元素  li.add("元素五");  li.add("元素六");  System.out.println();//产生换行操作  //通过使用ListIterator的特有方法hasPrevious与previous实现List的元素  //逆序输出  for(String str;li.hasPrevious();)  {System.out.print(li.previous().toString()+" ");}  System.out.println();//产生换行操作  //顺序输出li迭代器中现有的元素  while(li.hasNext())  {System.out.print(li.next().toString()+" ");}  System.out.println();//产生换行操作  //通过使用ListIterator的set方法来改变li中的元素  for(String str;li.hasPrevious();)  {   str=li.previous().toString();   li.set(str.replaceAll("元素","元素编号"));  }  //顺序输出li迭代器中现有的元素  while(li.hasNext())  {System.out.print(li.next().toString()+" ");}  } //初始化List方法 public void initial(List<String> list) {  list.add("元素一");  list.add("元素二");  list.add("元素三");  list.add("元素四"); }}


四、枚举Enumeration

枚举:

        就是Vector特有的取出方式。Vector有三种取出方式。

        其实枚举和迭代是一样的。因为枚举的名称以及方法的名称都过长。所以被迭代器取代了。

特有方法:

         addElement(obj);//添加元素,相当于add(obj);

         Enumerationelements();//Vector特有取出方式(枚举)

         hasMoreElements();//相当于IteratorhasNext()方法

         nextElements();//相当于Iteratornext()方法



五、LinkedList

        LinkedList:底层使用的是链表数据结构。特点:增删速度很快,查询稍慢。


LinkedList link= new LinkedList();               link.add("01");        link.add("02");        link.add("03");        //LinkedList的特有方法        link.addFirst("first");//在集合的开始添加元素        link.addLast("last");//在集合的结尾添加元素        System.out.println(link);        link.getFirst();//得到集合的一个元素        link.getLast();//得到自己和的最后一个元素        link.removeFirst();//删除第一个元素,并得到        link.removeLast();//删除最后一个元素,并得到        //当集合中没有元素的时候,调用get和remove的方法会抛出异常        //使用pollFirst去替代remove,当没有元素的时候,返回null;        //使用offerFirst()替换getFirst()        link.clear();        System.out.println(link.pollFirst());//null  


set 概述


在Collection中,除了List派系之外,还有一个Set派系,

List:元素是有序的(存入和取出的顺序一致),元素可以重复。因为该集合体系有索引。可以在指定位置对元素进行操作。凡是带角标的,底层的实现都是数组数据结构。

Set:元素是无序(存入和取出的顺序不一定一致)的,元素不可以重复。

查看Set接口的功能,才发现Set和Collection是一致的。(增删改查的功能)

在学习Set时候,最重要的是如何才能控制其中的元素唯一。

在Set接口下,有两个我们常用的类比较重要

HashSet:它的底层数据结构是哈希表(保证元素唯一性是判断元素的hashCode和equals方法。)



  Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。     

         |--HashSet 保证元素唯一性的原理:hashCode  与 equals

         |--TreeSet: 保证元素唯一性的依据:compareTo

      

 

二、HasSet

        HashSet:线程不安全,存取速度快。

HashSet hs = new HashSet();      hs.add("java01");      hs.add("java02");      hs.add("java03");      hs.add("java03");//返会false。表示为同一个元素      Iterator it = hs.iterator();      while(it.hasNext())      {          System.out.println(it.next());      }  //输出  java02 java03  java01  
定义一个Person类
class Person   {      private String name;      private int age;      public Person(String name,int age)      {      this.name = name;      this.age = age;      }      @Override      public String toString()      {      return this.name +"...."+this.age;      }  }  
并使用下边的例子实现
Person p = new Person("1",1);  Person p2 = new Person("1",1);  Person p1 = new Person("2",2);  HashSet hs = new HashSet();    hs.add(p);  hs.add(p1);  hs.add(p2);  Iterator it  = hs.iterator();  while(it.hasNext())  {      Person pp = (Person)it.next();            System.out.println(pp);        }  /输出: 1....1  1....1  2....2  

说明相同的人被存入到HashSet中了,不满足HashSet所定义的那样了,必须处理自定义对象,使HashSet中不能存入相同的对象。(满足其原先定义的那样)

也就是必须让相同的对象其hash值相同。建立Person对象的hash值。

对象通过怎么判断相等(如Person中的agename,就用这些值去生成hash值

对于底层数据结构是哈希表的数据结构的集合,如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals,如果元素的hashCode值相同,才会判断equals是否为true,如果元素的hashCode值不同,不会调用equals。所以不同的对象一般使其hashCode值不同,会更加的高效,不用去调用equels方法去判断是否相等。


三、TreeSet

1、特点

        a、底层的数据结构为二叉树结构(红黑树结构)

        b)可对Set集合中的元素进行排序,是因为:TreeSet类实现了Comparable接口,该接口强制让增加到集合中的对象进行了比较,需要复写compareTo方法,才能让对象按指定需求(如人的年龄大小比较等)进行排序,并加入集合。

        java中的很多类都具备比较性,其实就是实现了Comparable接口。

注意:排序时,当主要条件相同时,按次要条件排序。


class Student  {      private String name;      public Student(String name, int age)      {      super();      this.name = name;      this.age = age;      }      private int age;      public String getName()      {          return name;      }      public int getAge()      {          return age;      }      public String toString()      {      return this.name+"...."+this.age;      }        }          TreeSet  ts = new TreeSet();      ts.add(new Student("01",10));      ts.add(new Student("02",13));      ts.add(new Student("03",11));      ts.add(new Student("04",22));            System.out.println(ts);  

上面的列子报错了,原因是由于TreeSet要对放入其中的元素进行排序,但是按照什么顺序排,它并不知道,所以就报错了,也就是学生对象根本不具备比较性,所以要实现一个接口Comparable(也就是让存入的元素具备了比较性),此接口强行对实现它的每个类的对象进行整体排序,这种排序也称为类的自然排序。

元素实现Comparable接口,就是让元素具备了比较性。

public interface Comparable<T> {      public int compareTo(T o);  }  
强制让学生具备比较性。
class Student implements Comparable  {     public int compareTo(Object o)      {      Student s = (Student)o;      return this.age - s.age;      }  }  




        c、保证数据的唯一性的依据:通过compareTo方法的返回值,是正整数、负整数或零,则两个对象较大、较小或相同。相等时则不会存入

2Tree排序的两种方式

        1)第一种排序方式:自然排序

        让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。这种方式也被称为元素的自然顺序,或者叫做默认顺序。


     2)第二种方式:比较器

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

        在集合初始化时,就有了比较方式。定义一个比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。

        比较器构造方式:定义一个类,实现Comparator接口,覆盖compare方法。

        当两种排序都存在时,以比较器为主。




第五讲     Map集合


该集合存储键值对。一对一对往里存,而且要保证键的唯一性(与Set集合保证元素唯一性一致)。一个映射不能包含重复的键。每个键最多只能映射到一个值。


 

Map集合中常见的三个子类对象

HashMap:底层是哈希表数据结构,线程不同步。允许使用null值和null键,效率高

HashTable:线程同步。不允许存入null值和null键,效率低

为了成功的在哈希表中存储和获取对象,用作键的对象必须实现hashCode方法和equals方法。

TreeMap:底层是二叉树数据结构,线程不同步,给键排序是它的主要特点。

 

其实Set底层就是使用了Map集合。

当Map仅存入一个键值的 时候,就是Set。

下边具体写一个例子来使用上述方法


import java.util.*;  public class MapDemo   {        public static void main(String[] args)       {          Map<String,String> mp = new HashMap<String,String>();          System.out.println(mp.put("01","001"));          System.out.println(mp.put("01","0001"));  //在Map中存入一个键相同的值后,新的值会替换旧的值,这与set集合不同。  //旧的值通过put方法返回          mp.put("02", "002");          mp.put("03","003");          mp.put("04","004");          System.out.println(mp.containsKey("02"));          System.out.println(mp.remove("01"));  //当remove删除键在集合中不存在时候,返回null  //当remove删除的键在集合中存在时,返回这个键所对应的值          System.out.println(mp);          String s = mp.get("04");              //通过键去得到键所对应的值          System.out.println(s);                mp.put(null,null);          //HashMap中能存null键与null值          //获取map中所有的值                  Collection<String> c = mp.values();          System.out.println(c);          c.remove("002");          System.out.println(c);          System.out.println(mp);      }  }  


Map中不能通过迭代器的方式去取出所有的元素,只用Collection体系下的集合才能使用Iterator去迭代取出。

有两种方式

keySet() 
返回此映射中包含的键的 Set 视图。

将map中所有的键存入到Set集合中,由于Set具备迭代器,所以可以使用迭代方式取出所有的键,在根据get方法,获取每一个键对应的值。

例如

Map<String,String> mp = new HashMap<String,String>();          mp.put("02", "002");          mp.put("03","003");          mp.put("04","004");          Set<String> set = mp.keySet();          Iterator<String> it = set.iterator();          while(it.hasNext())          {              String key = it.next();              System.out.println(key+"...."+mp.get(key));          }  



entrySet() 
返回此映射中包含的映射关系的 Set 视图。

Map<String,String> mp = new HashMap<String,String>();          mp.put("02", "002");          mp.put("03","003");          mp.put("04","004");          Set<Map.Entry<String,String>> set = mp.entrySet();          Iterator<Map.Entry<String,String>> it  = set.iterator();          while(it.hasNext())          {              Map.Entry<String,String> mpe = it.next();              System.out.println(mpe.getKey()+".."+mpe.getValue());          }  


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

在Map集合的子类中实现了Map.entry,对应集合的特定取出方式。跟迭代器原理一样。

上边的Map.entry类型其实就是关系类型。每一个键值对组成了一个关系。



0 0
原创粉丝点击