Java——集合容器

来源:互联网 发布:vgg 网络结构 编辑:程序博客网 时间:2024/05/16 07:50

集合框架

集合类:
      面向对象编程中会出现很多的对象,为了方便这些对象的存储,便出现了集合框架。集合框架可以存储和操作多个对象,而它和数组的不同是在于,数组只能存储同一类型的对象,而集合可以存储不同类型的对象,而且集合的长度可以是任意的。
      集合框架中有很多中容器,用来存储对象。为什么会出现这么多容器呢?是因为每一个容器对对象的存储方式都不同,这种存储方式称为数据结构。

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

Collection类中常见方法:
添加元素
        add(Object obj); 
删除元素
        remove(Object obj);
        removeAll(集合);//删除参数集合中有的元素
        clear();//清空集合
判断元素
        contains(Object obj);//是否包含参数
        isEmpty();//判空
获取集合长度
       size();
取交集
       retainAll(集合);//取和参数集合的交集


迭代器
迭代器就是用来从集合中取出元素的方式。而迭代器被定义成内部类的形式,是因为Collection中有很多不同的子容器,这些子容器的数据结构不同,对元素的取出方式也不一样,但对外都提供了Iterator()方法进行取出操作。
迭代器的常见方法:
      hasNext();//判断是否有下一个元素
      next();//取出下一个元素
      remove();//移除元素
遍历取出元素时,用循环判断hasNext()进行取出。推荐使用for循环,因为for循环中的迭代器是局部变量,循环后就会在内存中清除,写法如下:
for(Iterator it = a.iterator();it.hasNext();  ){           System.out.println(it.next());}

List类:
      元素是有序的,元素可以重复。因为该集合体系有索引。
list类的特有方法:list类方法的特点是对索引进行操作。
  增
      add(index,element);//在指定位置添加元素
      addAll(index,Collection);//在指定位置增加给定集合中的元素
  删
      remove(index);//删除指定位置的元素
  改
      set(index,element);//修改指定位置的元素。
  查
      get(index);//通过索引获取元素
      subList(from,to);//获取子集的对象元素

List的三个子类
     1. ArrayList
     2.LinkedList
     3.Vector
List集合判断元素是否相同,移除等操作,依据的是元素的equals方法。

ArrayList:
    对应的数据结构是顺序表,查询速度快,增删速度慢。线程不同步。
Vector:
    和ArrayList数据结构相同,因线程同步被ArrayList取代。
LinkedList:
    对应的数据结构是链表,增删速度快,查询速度慢。

ListIterator:
    它定义了针对于List数据结构的特有方法:
     add(obj); //增加
     set(obj); //修改为obj
     hasPrevious(); //判断前面是否有元素

Enumeration:
    相当于Vector的迭代器。
    特有方法:
         addElement(obj);//相当于add(obj);
         Enumerationelements();//Vector的取出元素方式
         hasMoreElements();//相当于Iterator的hasNext()方法
         nextElements();//相当于Iterator的next()方法
    
LinkedList:
     特有方法:因为链表增删操作繁琐,所以只有从头和从尾的增删方法。
     增
         addFirst();
         addLast();
     查
        getFirst();
        getLast();
     删
         removeFirst();
         removeLast();
    查找和删除方法都会返回当前元素,如果没有获取到元素,则抛出NoSuchElementException。
在JDK1.6以后,出现了替代方法。
     增
        offFirst();
        offLast();
     获取
        peekFirst();
        peekLast();
     删
        pollFirst();
        pollLast();
    同上,查找和删除方法都会返回当前元素,如果没有获取到元素,则返回null。


下面一个List集合的练习:
首先是LinkedList练习,用LinkedList实现队列和栈的存取操作。代码如下:
        
class MyQueue//队列结构元素存取顺序是FIFO(先进先出){private LinkedList link;public MyQueue(){link = new LinkedList();}public void push(Object obj){link.add(obj);}public Object pop(){return link.removeLast();}public boolean isNull(){return link.isEmpty();}}class MyStack//栈结构存取顺序是FILO(先进后出){private LinkedList link;public MyStack(){link = new LinkedList();}public void push(Object obj){link.add(obj);}public Object pop(){return link.removeFirst();}public boolean isNull(){return link.isEmpty();}}

Set类


在set集合中,元素是无序的,元素不可以重复。   
      常用的子类有两个:
         HashSet,
         TreeSet。

HashSet:
      基于哈希表的Set集合,首先用hashcode()函数保证元素的唯一性, 如果hashcode的结果相同,则用equals()比较元素是否相同。
 下面是HashSet存储自定义元素的程序示例:
import java.util.*;class Person//人类描述,存储的元素{private String name;private int age;Person(String name,int age){this.name=name;this.age=age;}public String getName(){return name;}public int getAge(){return age;}public boolean equals(Object obj){if(!(obj instanceof Person))return false;Person p=(Person)obj;return this.name.equals(p.name)&&this.age==p.age;}public int hashCode(){return this.name.hashCode()+this.age;}}class  HashSetTest{public static void main(String[] args) {HashSet h=new HashSet();h.add(new Person("shenm",10));h.add(new Person("shenm2",6));h.add(new Person("shenm1",30));h.add(new Person("shenm0",10));h.add(new Person("shenm0",10));for (Iterator it=h.iterator(); it.hasNext(); )//取出元素{Person p=(Person)it.next();print(p.getName()+"..."+p.getAge());}}public static void print(Object obj){System.out.println(obj);}}

TreeSet:
       基于的数据结构是二叉树,每次存入元素时对元素进行比较。比较的方法有二,一种是让元素自身具备比较性——就是实现Comparable接口,并覆盖CompareTo(Object obj)方法。第二种是自定义一个比较器类,实现Comparator接口,并覆盖Compare(Object o1, Object o2)方法。这两个函数的返回值是正数、负数、零,分别对应元素的比较结果为——大于、小于、等于。
      下面给出两种比较方法的代码示例:
1、实现Comparable接口
class Person implements Comparable{private String name;private int age;public Person(String name, int age){this.name = name;this.age = age;}public String getName(){return this.name;}public int getAge(){return this.age;}@Overridepublic int compareTo(Object obj){if(!(obj instanceof Person))throw new RuntimeException("not a Person");Person p = (Person)obj;System.out.println(this.name + "   compare to   " + p.name);if(this.age > p.age)return 1 ;if(this.age == p.age)return this.name.compareTo(p.name);return -1;}}class TreeSetTest{public static void main(String args[]){TreeSet<Person> tr = new TreeSet<Person>();tr.add(new Person("zhangsan1", 11));tr.add(new Person("zhangsan2", 12));tr.add(new Person("zhangsan3", 13));tr.add(new Person("zhangsan4", 15));tr.add(new Person("zhangsan6", 19));tr.add(new Person("zhangsan5", 19));Iterator it = tr.iterator();while(it.hasNext()){Person p = (Person)it.next();print(p.getName() + "---" + p.getAge());}}public static void print(Object obj){System.out.println(obj);}}

2、自定义比较器实现Comparator接口

import java.util.*;class Person {private String name;private int age;public Person(String name, int age){this.name = name;this.age = age;}public String getName(){return this.name;}public int getAge(){return this.age;}}class TreeSetTest{public static void main(String args[]){TreeSet<Person> tr = new TreeSet<Person>(new PersonComparator());tr.add(new Person("zhangsan1", 11));tr.add(new Person("zhangsan2", 12));tr.add(new Person("zhangsan3", 13));tr.add(new Person("zhangsan4", 15));tr.add(new Person("zhangsan6", 19));tr.add(new Person("zhangsan5", 19));Iterator<Person> it = tr.iterator();while(it.hasNext()){Person p = (Person)it.next();print(p.getName() + "---" + p.getAge());}}public static void print(Object obj){System.out.println(obj);}}class PersonComparator implements Comparator<Person>  {      public int compare(Person p1,Person p2)      {          int num=new Integer(p1.getName().length()).compareTo(new Integer(p2.getName().length()));          if (num==0)          {              return new Integer(p1.getAge()).compareTo(p2.getAge());          }          return num;      }  }  



Map类

Map类存放的元素是键值对,同时要保证键的唯一性。

Map类常见的子类有:
       Hashtable
       HashMap
       TreeMap
Hashtable和HashMap都是基于哈希表的集合,HashMap较新,代替了Hashtable,允许存储null值和null键,线程不同步。
TreeMap是基于二叉树的集合。

Map类特有方法:
增:
   put(K key,V value )  //添加元素
   putAll(Map<? extends K , ? extends V> m ) //添加一组元素
删:
   remove(Object  key) //删除指定键值对
   clear() //清空容器
查:
   containsKey(Object key) //是否包含指定键
   containsValue(Object value) //是否包含指定值
   isEmpty() //判空
获取:
   get(Object key) //通过键值获取对应的值
   重要的是下面两个取出方法:
   entrySet() //返回一个元素类型是Map.Entry<K, V>的Set集合,包含Map所有的键值对。
   keySet() //返回一个包含map所以键值的Set集合。

在进行有关集合的练习时,应注意养成将元素都实现Comparable接口和自定义比较器的习惯。

下面是Map集合取出键值对的两种方式:
1、通过entrySet()方法直接返回包含键值对的Set集合:
代码如下:
示例Map的元素是自定义的学生类
import java.util.*;class Student implements Comparable<Student>{private String name;private int age;Student(String name, int age){this.name = name;this.age = age;}@Overridepublic int hashCode(){return name.hashCode() + age * 34;}@Overridepublic boolean equals(Object obj){if(!(obj instanceof Student))return false;//throw new ClassCastException("类型不匹配");Student s = (Student)obj;return this.name.equals(s.name) && this.age == s.age;}public String getName(){return name;}public void setName(String name){this.name = name;}public int getAge(){return age;}public void setAge(int age){this.age = age;}@Overridepublic String toString(){return "Student [name=" + name + ", age=" + age + "]";}@Overridepublic int compareTo(Student s){int num = new Integer(this.age).compareTo(new Integer(s.age));if(num == 0)return this.name.compareTo(s.name);return num;}}class MapTest2{public static void main(String[] args){TreeMap<Student, String> tm = new TreeMap<Student, String>(new StuNameComparator());tm.put(new Student("lisi03", 24), "武汉");tm.put(new Student("lisi01", 22), "北京");//tm.put(new Student("lisi01", 21), "天津");tm.put(new Student("lisi04", 23), "南京");tm.put(new Student("lisi02", 21), "上海");Set<Map.Entry<Student, String>> entrySet = tm.entrySet();Iterator<Map.Entry<Student, String>> it = entrySet.iterator();while(it.hasNext()){Map.Entry<Student, String> me = it.next();Student s = me.getKey();String addr = me.getValue();print(s + "--" + addr);}}public static void print(Object obj){System.out.println(obj);}}class StuNameComparator implements Comparator<Student>{public int compare(Student s1, Student s2){int num = s1.getName().compareTo(s2.getName());if(num == 0)return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));return num;}}

2、第二种方法是用keySet()方法返回包含键值的Set,然后用get方法一次取出对应的值。
代码如下:(学生类定义部分不再给出)
class MapTest{public static void main(String[] args){HashMap<Student, String> hm = new HashMap<Student, String>();hm.put(new Student("lisi01", 21), "北京");hm.put(new Student("lisi01", 21), "天津");hm.put(new Student("lisi02", 22), "上海");hm.put(new Student("lisi03", 23), "武汉");hm.put(new Student("lisi04", 24), "南京");Iterator<Student> it1 = hm.keySet().iterator();while(it1.hasNext()){Student s = it1.next();String addr = hm.get(s);print(s + ".." + addr);}}public static void print(Object obj){System.out.println(obj);}}

Map扩展知识:
   Map的映射关系不仅可以建立在单个元素之间,也可以建立在集合与元素,集合与集合之间,这样就形成了映射关系的嵌套。
   比如传智播客体系,可以分为预热班,就业班,每个班中又有学生元素,学生可以有学号和姓名的映射关系。

给出代码示例:

import java.util.*;class  MapExpandKnow{public static void main(String[] args) {//预热班HashMap<String,String> yureban=new HashMap<String,String>();//就业班HashMap<String,String> jiuyeban=new HashMap<String,String>();//传智播客HashMap<String,HashMap<String,String>> czbk=new HashMap<String,HashMap<String,String>>();czbk.put("yureban",yureban);czbk.put("jiuyueban",jiuyeban);//预热班级中学号与姓名的映射yureban.put("01","zhangsan");yureban.put("02","lisi");//就业班级中学号与姓名的映射jiuyeban.put("01","wangwu");jiuyeban.put("02","zhouqi");//直接显示全部学生信息getInfo(czbk);}//定义一个方法获取全部学生信息,包括在哪个班级,叫什么名字,学号多少public static void getInfo(HashMap<String ,HashMap<String,String>> hm){for (Iterator<String> it=hm.keySet().iterator();it.hasNext() ; ){String s= it.next();System.out.println(s+":");HashMap<String,String> stu=hm.get(s);getStuInfo(stu);}}//获取班级中学生的信息,包括姓名和学号public static void getStuInfo(HashMap<String,String> hm){for (Iterator<String> it=hm.keySet().iterator();it.hasNext() ; ){String key=it.next();//学号String value=hm.get(key);//姓名System.out.println(key+"..."+value);}}}





泛型
泛型是JDK1.5版本以后出现的新特性。用于解决安全问题,是一个类型安全机制。泛型要求在定义集合时,明确你要在集合中操作何种类型的数据,格式是通过<>来定义要操作的引用数据类型,如ArrayList<String>。这样就可以将运行时期出现的问题ClassCastException,转移到编译时期。方便于程序员解决问题。让运行时期问题减少、安全。同时也避免了强制转换的麻烦。当传入的类型不确定时,可以使用通配符?,也称为占位符。使用通配符的好处是可以不用明确传入的类型,这样在使用泛型类或者泛型方法时,提高了扩展性。
泛型限定:对泛型的上下限进行限定,明确泛型的范围。
     <? extends E>:可接收E类型或E类型的子类型,称之为上限。
     <? super E>:可接收E类型或E类型的父类型,称之为下限。
泛型类:当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展。现在定义泛型来完成扩展。

泛型方法:不同方法如果要操作不同类型的参数,而且类型还不确定,那么可以将泛型定义在方法上。

格式如下:
class Test<T>//泛型类{private T t;public void setObject(T t){this.t = t;}public T getObject(){return t;}//-----------------泛型方法public <E> void print(E e){System.out.println(e);}public <Q> void show(Q q){System.out.println(q);}}class GenericTest{public static void main(String[] args){Test<String> t = new Test<String>();t.setObject("GG");System.out.println(t.getObject());t.show(4);}}



0 0
原创粉丝点击