在编程的过程中,多数据的存储及应用都是比较麻烦的事,以前我就只知道用数组和自己写封装类来解决,但是这两种方法在一些功能中并不适用,比如我们要根据数据库中其中一个表的数据弄一个下拉菜单的内容,这个时候我们需要从数据库获取显示给用户看的内容及对应的id。在这种情况中,因为在数据库中的这种一对的数据一般都是有好几个的,所以封装类并不适用,而数组只能存储单一的一种数据类型,并且只能通过游标获取对应的值,还有最麻烦的是数组在初始化的时候必须初始化长度,所以也数组也不太适用,这个时候我们可以使用java官方提供的容器类(集合类)。
容器类(集合类)是java官方提供给我们的存储方式,它扩展了数组使用上的自由度,如:长度可变,可存储多种数据类型的数据等。容器类在java体系中并不仅仅是一个类,而是很多的容器类所构成的一个框架、体系,不同的容器类具有不同的存储方式,因为容器类太多,所以java官方制定了一系列接口,所有的容器类都得已实现。
常用的容器类大致可分为三大类:List、Set、Map
首先介绍一下List:
List是有顺序的,其中常用的主要有Vector、ArrayList、LinkedList三个容器类,List的主要使用方法如下:
//ArrayList ls=new ArrayList(); //更多情况是如下定义 List ls=new ArrayList(); //问题: 为什么要这样定义? //某些情况下面,可能需要切换实现类 //LinkedList ls=new LinkedList();//改变太大,如果,下面有人调用到List接口没有方法 //List ls=new LinkedList();//不管换什么实现类,都没问题,因为接口没变 //----------------------------------------------------------------------------------- //List 可以存放任意类型的数据 //其实,所有类都是Object类的子类,存入的时候,将所有类型都打散成为Object //因此,拿出来的时候,肯定需要转换 String a="a"; int i=10; double d=1000.0; ls.add(a); ls.add(i); ls.add(d); //有顺序,可以根据元素的索引/游标访问元素 String a2=(String)ls.get(0); //int i2=(int)ls.get(1);//int 是基本数据类型,不是封装类,没法直接转换 int i2=(Integer)ls.get(1); double d2=(Double)ls.get(2); //如果是jdk1.5以上,可以使用泛型 //泛型:限制只能存储某一类型 List<String> ls2=new ArrayList<String>(); ls2.add("a"); ls2.add("b"); ls2.add("c"); String s=ls2.get(0);//无须再转换 //----------------------------------------------------------------------------------- //你接到一个别人发过来的List,如何取出里面所有数据 for(int j=0;j<ls2.size();j++){ System.out.println(ls2.get(j)); } //或者转换成迭代器遍历出来 Iterator it=ls2.iterator(); while(it.hasNext()){ System.out.println(it.next()); }
而在上面提到的三个常用的List容器类中,ArrayList和Vector都是使用数组方式存储数据,这两个容器类都是通过使用数组实现的,所以索引数据速度快,但是由于插入数据时涉及数组元素移动等内存操作,所以插入数据速度较慢,而由于Vector中的方法都是线程安全的,即所有方法都添加了同步锁synchronized,所以性能上要比ArrayList要差。
LinkedList是使用双向链表实现存储的,在索引数据时需要进行向前或向后的遍历,但是在插入数据时只需记录本项的前后项即可,所以其索引数据慢插入数据快。
Set是无序的,其中是不能包含重复元素的,其中常用的主要有:HashSet、TreeSet,Set的主要使用方法如下:
Set hs=new HashSet();//不能插入重复数据 //List hs = new ArrayList();//可以插入重复数据 Student s=new Student(1,"zhangsan"); hs.add(s); s.name="edit"; boolean isAdded = hs.add(s); //重复数据,不能再插入 System.out.println(isAdded); //false hs.add(new Student(2,"lisi")); hs.add(new Student(3,"wangwu")); hs.add(new Student(1,"zhangsan"));//这不是重复数据,是一个新的对象 //----------------------------------------------------------------------------------- //无顺序,只能迭代取值,顺序会有不一定的情况。 Iterator it=hs.iterator(); while(it.hasNext()){ System.out.println(it.next()); }
HashSet是无顺序的,而TreeSet是有顺序的,但是TreeSet的顺序与List那样按插入的先后排序不同,它是按照元素对象自己定义的排序规则进行排序的,因此前者允许放入null,且效率较高,而后者不允许放入null,且效率较低。
Map是以键值对的方式存储数据的一种容器类,其中常用的主要有:HashMap、HashTable、TreeMap,Map的主要使用方法如下:
HashMap hm=new HashMap(); //HashMap<String,String> hm=new HashMap<String,String>(); String a="a"; int i=10; double d=1000.0; //put(键,值) hm.put("zfc",a); hm.put("zx",i); hm.put(3,d); //hm.put(3,12.0); //key相同,覆盖已有value String a2=(String)hm.get("zfc"); int i2=(Integer)hm.get("zx"); double d2=(Double)hm.get(3); System.out.println(a2+" "+i2+" "+d2); //遍历方式1:建议方式,效率高一些 Iterator iterator = hm.keySet().iterator();//Iterator迭代器,按key来迭代遍历 while(iterator.hasNext()) { System.out.println(hm.get(iterator.next())); } //遍历方式2 Iterator it = hm.entrySet().iterator();//Iterator迭代器,按entry来迭代遍历 while(it.hasNext()){ java.util.Map.Entry entry = (java.util.Map.Entry)it.next(); // entry.getKey() 返回与此项对应的键 // entry.getValue() 返回与此项对应的值 System.out.println(entry.getValue()); }
HashMap允许有空键(null)与空值(null),非线程安全,效率较高。
HashTable不允许有空键(null)与空值(null),线程安全,效率较低。
TreeMap能把其保存的记录根据key排序(类似TreeSet),默认是按照key的默认排序,但也可指定排序的比较器,在用迭代器迭代遍历时,得到的记录是排序以后的,TreeMap不允许有空键(null)但可以有空值(null)。