zoukankan      html  css  js  c++  java
  • java的集合类【转】

     在JDK API中专门设计了一组类,这组类的功能就是实现各种各样方式的数据存储,这样一组专门用来存储其它对象的类,一般被称为对象容器类,简称容器类,这组类和接口的设计结构也被统称为集合框架(Collection Framework)。

             这组类和接口都包含在java.util包中。

             为了使整个集合框架中的类便于使用,在设计集合框架时大量的使用接口,实际实现的功能类实现对应的接口,这样可以保证各个集合类的使用方式保持统一。

             在集合框架中,提供的存储方式共有两种:

                       1、按照索引值操作数据

    在这种存储方式中,为每个存储的数据设定一个索引值,存储在容器中的第一个元素索引值是0,第二个索引值是1,依次类推。在操作数据时按照索引值操作对应的数据,实现这种方式的集合类都实现java.util.Collection接口。

                       2、按照名称操作数据

    在这种存储方式中,为每个存储的数据设定一个名称(任意非null的对象都可以作为名称),以后按照该名称操作该数据,要求名称不能重复,每个名称对应唯一的一个值。这种存储数据的方式也称作名称-数值对,也就是名值对存储。实现这种方式的几个类都实现java.util.Map接口。

             这里“按照索引值操作数据”的存储方式,又按照容器内部是否能够存储重复的元素,划分成两类:

                       1、允许存储重复元素。

                                这种存储方式中,所有的类都实现了java.util.List接口。

                       2、不允许存储重复元素。

                                这种存储方式中,所有的类都实现了java.util.Set接口。

             这样,集合框架中的类就分成了三大类:

                       1、List系列

                                该系列中的类按照索引值来操作数据,允许存放重复的元素。

                       2、Set系列

                                该系列中的类按照索引值来操作数据,不允许存放重复的元素。

                       3、Map系列

    该系列中的类按照名称来操作数据,名称不允许重复,值可以重复,一个名称对应一个唯一的值。

             而 在数据结构中,实现数据的存储又可以使用不同的数据结构类型进行存储,例如数组、链表、栈、队列和树等,则以上三类集合框架可以使用不同的数据结构类进行 实现,使用每种数据结构则具备该中数据结构的特点。例如使用数组则访问速度快,使用链表则便于动态插入和删除等,这样就造成了集合框架的复杂性。

             另外,在将对象存储到集合类中,为了加快存储的速度,要求被存储对象的类中必须覆盖equals方法和hashCode方法。

             对于这些集合类,下面按照以上三个系列的顺序一一进行说明。

    9.6.3.1 List系列

             List系列的类均实现List接口,大部分的类都以List作为类名的后缀,也有部分该体系中的类命名比较特殊。

             该系列中的类,比较常见的有ArrayList和LinkedList两个。其中ArrayList是以数组为基础实现的List,而LinkedList则是以链表为基础实现的List,ArrayList拥有数组的优点,而LinkedList拥有链表的优点。

             由于该体系中的类均实现List接口,所以在这些类的内部,相同的功能方法声明是保持一致的,下面进行一一介绍:

             a、add方法

                                boolean add(Object o)

                       该方法的作用是追加对象o到已有容器的末尾。

                       另外一个add方法:

                                void add(int index, Object element)

    该方法的作用是将对象element插入到容器中索引值为index的位置,原来位于该位置的对象以及后续的内容将依次向后移动。

             b、addAll方法

                                boolean addAll(Collection c)

                       该方法的作用是将容器对象c中的每个元素依次添加到当前容器的末尾。

                       另外一个addAll方法:

                                boolean addAll(int index, Collection c)

    该方法的作用是将容器对象c中的第一个元素插入到当前容器中索引值为index的位置,第二个元素插入到当前容器中索引值为index+1的位置,依次类推。而当前容器中原来位于index以及index索引值以后的元素则依次向后移动。

             c、get方法

                                Object get(int index)

                       该方法的作用是返回当前容器对象中索引值为index的元素的内容。

             d、indexOf方法

                                int indexOf(Object o)

    该方法的作用是查找当前容器中是否存在对象o,如果存在则返回该对象第一次出现位置的索引值,如果不存在则返回-1。

    另外一个方法lastIndexOf则是从末尾向前查找,返回从末尾向前第一次出现位置的索引值,如果不存在则返回-1。

             e、remove方法

                                Object remove(int index)

    该方法的作用是删除索引值为index的对象的内容,如果删除成功则返回被删除对象的内容。

                       另外一个remove方法:

                                boolean remove(Object o)

    该方法的作用是删除对象内容为o的元素,如果相同的对象有多个,则只删除索引值小的对象。如果删除成功则返回true,否则返回false。

    无论使用哪一个remove方法,类内部都自动移动将被删除位置后续的所有元素向前移动,保证索引值的连续性。

             f、set方法

                                Object set(int index, Object element)

    该方法的作用是修改索引值为index的内容,将原来的内容修改成对象element的内容。

             g、size方法

                                int size()

                       该方法的作用是返回当前容器中已经存储的有效元素的个数。

             h、toArray方法

                                Object[] toArray()

                       该方法的作用是将当前容器中的元素按照顺序转换成一个Object数组。

             下面是一个简单的以ArrayList类为基础实现的List系列中类基本使用的示例,代码如下:

      import java.util.*;
    
    /**
     * 以ArrayList类为基础演示List系列类的基本使用
     */
    public class ArrayListUse {
             public static void main(String[] args) {
                       //容器对象的初始化
                       List list = new ArrayList();                 
                       //添加数据
                       list.add("1");
                       list.add("2");
                       list.add("3");
                       list.add("1");
                       list.add("1");            
                       //插入数据
                       list.add(1,"12");               
                       //修改数据
                       list.set(2, "a");                  
                       //删除数据
                       list.remove("1");              
                       //遍历
                       int size = list.size(); //获得有效个数
                       //循环有效索引值
                       for(int i = 0;i < size;i++){
                                System.out.println((String)list.get(i));
                       }
             }
    }
             该程序的运行结果为:
    
                       12
    
    a
    3
    1
    1
    ArrayList类 为基础实现的List系列

             在List系列中,还包含了Stack(栈)类和Vector(向量)类,Stack类除了实现List系列的功能以外,还实现了栈的结构,主要实现了出栈的pop方法和入栈的push方法。

             而Vector类由于需要兼容老版本JDK中缘故,所以在实现的方法中需要提供老版本Vector类中对应的方法,这样导致Vector类中相同或类似的功能方法一般是成对出现的。

     Set系列

             Set系列中的类都实现了Set接口,该系列中的类均以Set作为类名的后缀。该系列中的容器类,不允许存储重复的元素。也就是当容器中已经存储一个相同的元素时,无法实现添加一个完全相同的元素,也无法将已有的元素修改成和其它元素相同。

             Set系列中类的这些特点,使得在某些特殊场合的使用比较适合。

    该系列中常见的类有:

                       1、CopyOnWriteArraySet

                                以数组为基础实现的Set类。

                       2、HashSet

                                以哈希表为基础实现的Set类。

                       3、LinkedHashSet

                                以链表为基础实现的Set类。

                       4、TreeSet

                                以树为基础实现的Set类。

             以不同的数据结构类型实现的Set类,拥有不同数据结构带来的特性,在实际使用时,根据逻辑的需要选择合适的Set类进行使用。

             Set系列中的类的方法和List系列中的类的方法要比List系列中少很多,例如不支持插入和修改,而且对于Set系列中元素的遍历也需要转换为专门的Iterator(迭代器)对象才可以进行遍历,遍历时顺序和Set中存储的顺序会有所不同。

             下面是以HashSet类为基础实现的示例代码,代码如下:

          

                 import java.util.*;
    
    /**
    
     * 以HashSet为基础演示Set系列类的基本使用
    
     */
    
    public class HashSetUse {
    
             public static void main(String[] args) {
    
                       //容器对象的初始化
    
                       Set set = new HashSet();         
    
                       //添加元素
    
                       set.add("1");
    
                       set.add("2");
    
                       set.add("3");
    
                       set.add("1");
    
                       set.add("1");                              
    
                       //删除数据
    
                       //set.remove("1");          
    
                       //遍历
    
                       Iterator iterator = set.iterator();
    
                       while(iterator.hasNext()){
    
                                System.out.println((String)iterator.next());
    
                       }
    
             }
    
    }
    
             该程序的运行结果为:
    
                       3
    
    2
    
    1
    以HashSet为基础演示Set系列类的基本使用

    Map系列

             Map系列中的类都实现了Map接口,该系列中的部分类以Map作为类名的后缀。该系列容器类存储元素的方式和以上两种完全不同。

             Map提供了一种使用“名称:值”这样的名称和数值对存储数据的方法,在该存储方式中,名称不可以重复,而不同的名称中可以存储相同的数值。具体这种存储的格式将在示例代码中进行实现。

             在这种存储结构中,任何不为null的对象都可以作为一个名称(key)来作为存储的值(value)的标识,使用这种形式更利于存储比较零散的数据,也方便数据的查找和获得。Map类中存储的数据没有索引值,系统会以一定的形式索引存储的名称,从而提高读取数据时的速度。

             该系列中常见的类有:

                       1、HashMap

                                以Hash(哈希表)为基础实现的Map类。

                       2、LinkedHashMap

                                以链表和Hash(哈希表)为基础实现的Map类。

                       3、TreeMap

                                以树为基础实现的Map类。

             和上面的结构类似,以不同的数据结构实现的Map类,拥有不同数据结构的特点,在实际的项目中使用时,根据需要选择合适的即可。

             该系列的类中常见的方法如下:

                       a、get方法

                                         Object get(Object key)

                                该方法的作用是获得当前容器中名称为key的结构对应的值。

                       b、keySet方法

                                         Set keySet()

    该方法的作用是返回当前容器中所有的名称,将所有的名称以Set的形式返回。使用这个方法可以实现对于Map中所有元素的遍历。

                       c、put方法

                                         Object put(Object key, Object value)

                                该方法的作用是将值value以名称key的形式存储到容器中。

                       d、putAll方法

                                         void putAll(Map t)

    该方法的作用是将Map对象t中的所有数据按照原来的格式存储到当前容器类中,相当于合并两个Map容器对象。

                       e、remove方法

                                         Object remove(Object key)

                                该方法的作用是删除容器中名称为key的值。

                       f、size方法

                                         int size()

                                该方法的作用是返回当前日期中存储的名称:值数据的组数。

                       g、values方法

                                         Collection values()

    该方法的作用是返回当前容器所有的值组成的集合,以Collection对象的形式返回。

             下面是一个简单的示例,在该示例中演示Map系列类的基本使用,代码如下:

                       import java.util.*;
    
    /**
    
     * 以HashMap为基础演示Map系列中类的使用
    
     */
    
    public class HashMapUse {
    
             public static void main(String[] args) {
    
                       //容器对象的初始化
    
                       Map map = new HashMap();           
    
                       //存储数据
    
                       map.put("苹果", "2.5");
    
                       map.put("桔子", "2.5");
    
                       map.put("香蕉", "3");
    
                       map.put("菠萝", "2");             
    
                       //删除元素
    
                       map.remove("桔子");              
    
                       //修改元素的值
    
                       map.put("菠萝", "5");             
    
                       //获得元素个数
    
                       int size = map.size();
    
                       System.out.println("个数是:" + size);          
    
                       //遍历Map
    
                       Set set = map.keySet();
    
                       Iterator iterator = set.iterator();
    
                       while(iterator.hasNext()){
    
                                //获得名称
    
                                String name = (String)iterator.next();
    
                                //获得数值
    
                                String value = (String)map.get(name);
    
                                //显示到控制台
    
                                System.out.println(name + ":" + value);
    
                       }
    
             }
    
    }
    
             该程序的运行结果为:
    
                       个数是:3
    
    香蕉:3
    
    菠萝:5
    
    苹果:2.5
    以HashMap为基础演示Map系列中类的使用

     使用示例

             如前所述,集合框架中的类只是提供了一种数据存储的方式,在实际使用时,可以根据逻辑的需要选择合适的集合类进行使用。

             下面以一个字符串计算的示例演示集合类的实际使用。

             该程序的功能为计算一个数字字符串,例如”1+2*31-5”、”12*30/34-450”等,的计算结果,在该示例中支持四则运算,但是不支持括号。本示例中计算的字符串要求合法。

             该程序实现的原理是:首先按照运算符作为间隔,将字符串差分为数字字符串和运算符字符串的序列,由于分拆出的字符串数量不固定,所以存储到List系列的Vector容器中,然后按照运算符的优先级进行计算。

             该程序的代码如下:

      

                     import java.util.*;
    
    /**
    
     * 计算字符串的值
    
     */
    
    public class CalcStr {
    
             public static void main(String[] args) {
    
                       String s = "1+20*3/5";
    
                       double d = calc(s);
    
                       System.out.println(d);
    
             }       
    
             /**
    
              * 计算字符串的值
    
              * @param s 需要计算的字符串
    
              * @return 计算结果
    
              */
    
             public static double calc(String s){
    
                       //拆分字符串
    
                       Vector v = split(s);
    
                       //print(v); //测试代码
    
                       //计算字符串
    
                       double d = calcVector(v);
    
                       return d;
    
             }
    
            
    
             /**
    
              * 将字符串拆分为数字和运算符。
    
              * 例如:"1+23*4"则拆分为:"1"、"+"、"23"、"*"和"4"
    
              * @param s 需要拆分的字符串
    
              * @return 拆分以后的结果
    
              */
    
             private static Vector split(String s){
    
                       Vector v = new Vector();
    
                       String content = "";
    
                       int len = s.length(); //字符串长度
    
                       char c;
    
                       for(int i = 0;i < len;i++){
    
                                c = s.charAt(i);
    
                                //判断是否为运算符
    
                                if(c == '+' ||
    
                                         c == '-' ||
    
                                          c == '*' ||
    
                                          c == '/'){
    
                                         //存储数字
    
                                         v.add(content);
    
                                         //存储运算符
    
                                         v.add("" + c);
    
                                         //清除已有字符串
    
                                         content = "";
    
                                }else{
    
                                         content += c; //连接字符串
    
                                }
    
                       }
    
                       v.add(content); //添加最后一个数字
    
                       return v;
    
             }
    
            
    
             /**
    
              * 测试代码,输出拆分以后的结果
    
              * @param v 需要打印的Vector对象
    
              */
    
             private static void print(Vector v){
    
                       int size = v.size();
    
                       for(int i = 0;i < size;i++){
    
                                System.out.println((String)v.get(i));
    
                       }
    
             }
    
            
    
             /**
    
              * 计算Vector中的数据
    
              * @param v 存储拆分后字符串的Vector
    
              * @return 计算结果
    
              */
    
             private static double calcVector(Vector v){
    
                       int index1;
    
                       int index2;
    
                       //计算乘除
    
                       while(true){
    
                                index1 = v.indexOf("*"); //乘号索引值
    
                                index2 = v.indexOf("/"); //除号索引值
    
                                //无乘除符号
    
                                if(index1 == - 1 && index2 == -1){
    
                                         break; //结束循环
    
                                }                          
    
                                //如果有乘号
    
                                if(index1 != -1){
    
                                         //没有除号或乘号在前
    
                                         if(index2 == -1 || index1 < index2){
    
                                                   String s1 = (String)v.get(index1 - 1); //第一个数字
    
                                                   String opr = (String)v.get(index1); //运算符
    
                                                   String s2 = (String)v.get(index1 + 1); //第二个数字
    
                                                   //计算
    
                                                   String answer = calc(s1,s2,opr);
    
                                                   //计算以后的处理
    
                                                   handle(answer,index1 - 1,v);
    
                                         }
    
                                }
    
                                //有除号
    
                                if(index2 != -1){
    
                                         //没有乘号或除号在前
    
                                         if(index1 == -1 || index2 < index1){
    
                                                   String s1 = (String)v.get(index2 - 1); //第一个数字
    
                                                   String opr = (String)v.get(index2); //运算符
    
                                                   String s2 = (String)v.get(index2 + 1); //第二个数字
    
                                                   //计算
    
                                                   String answer = calc(s1,s2,opr);
    
                                                   //计算以后的处理
    
                                                   handle(answer,index2 - 1,v);
    
                                         }
    
                                }
    
                       }
    
                       //计算加
    
                       int index3 = v.indexOf("+");
    
                       while(index3 != -1){ //有加号
    
                                String s1 = (String)v.get(index3 - 1); //第一个数字
    
                                String opr = (String)v.get(index3); //运算符
    
                                String s2 = (String)v.get(index3 + 1); //第二个数字
    
                                //计算
    
                                String answer = calc(s1,s2,opr);
    
                                //计算以后的处理
    
                                handle(answer,index3 - 1,v);
    
                                //获得下一个加号的位置
    
                                index3 = v.indexOf("+");
    
                       }
    
                      
    
                       //计算减
    
                       index3 = v.indexOf("-");
    
                       while(index3 != -1){ //有加号
    
                                String s1 = (String)v.get(index3 - 1); //第一个数字
    
                                String opr = (String)v.get(index3); //运算符
    
                                String s2 = (String)v.get(index3 + 1); //第二个数字
    
                                //计算
    
                                String answer = calc(s1,s2,opr);
    
                                //计算以后的处理
    
                                handle(answer,index3 - 1,v);
    
                                //获得下一个减号的位置
    
                                index3 = v.indexOf("-");
    
                       }
    
                       //反馈结果
    
                       String data = (String)v.get(0);
    
                       return Double.parseDouble(data);
    
             }
    
            
    
             /**
    
              * 计算两个字符串类型的值运算结果
    
              * @param number1 数字1
    
              * @param number2 数字2
    
              * @param opr 运算符
    
              * @return 运算结果
    
              */
    
             private static String calc(String number1,String number2,String opr){
    
                       //将字符串转换为数字
    
                       double d1 = Double.parseDouble(number1);
    
                       double d2 = Double.parseDouble(number2);
    
                       //判断运算符
    
                       if(opr.equals("+")){
    
                                return "" + (d1 + d2);
    
                       }
    
                       if(opr.equals("-")){
    
                                return "" + (d1 - d2);
    
                       }
    
                       if(opr.equals("*")){
    
                                return "" + (d1 * d2);
    
                       }
    
                       if(opr.equals("/")){
    
                                return "" + (d1 / d2);
    
                       }
    
                       return "0"; //运算符错误时返回0
    
             }
    
            
    
             /**
    
              * 计算以后的处理
    
              * @param answer 计算结果
    
              * @param index 参与计算的三个字符串中第一个字符串的起始位置
    
              * @param v 存储字符串的容器
    
              */
    
             private static void handle(String answer,int index,Vector v){
    
                       //删除计算过的字符串
    
                       for(int i = 0;i < 3;i++){
    
                                v.remove(index);
    
                       }
    
                       //将计算结果插入到index位置
    
                       v.insertElementAt(answer, index);
    
             }
    
    }
    
             该程序的运行结果为:
    
                       13.0
    计算字符串的值
  • 相关阅读:
    动态规划——Best Time to Buy and Sell Stock IV
    动态规划——Split Array Largest Sum
    动态规划——Burst Ballons
    动态规划——Best Time to Buy and Sell Stock III
    动态规划——Edit Distance
    动态规划——Longest Valid Parentheses
    动态规划——Valid Permutations for DI Sequence
    构建之法阅读笔记05
    构建之法阅读笔记04
    构建之法阅读笔记03
  • 原文地址:https://www.cnblogs.com/bruce_zhao/p/3810088.html
Copyright © 2011-2022 走看看