JDK所提供的容器都在java.util包里面,下面开始讨论的都是JDK1.4版本的,只讲述基本知识,不涉及泛型
容器API的类图结构如下图所示
Set:元素无顺序且不可重复 List:元素有顺序且可以重复
所谓的重复,值得是两个元素equals
Collection接口中所定义的方法:
package com.collectiontest.demo; public class Name { private String fistname,lastname; public String getFistname() { return fistname; } public String getLastname() { return lastname; } public Name(String fistname, String lastname) { this.fistname = fistname; this.lastname = lastname; } @Override public String toString() { return "fistname"+" "+"lastname"; } }
package com.collectiontest.demo; import java.util.ArrayList; import java.util.Collection; public class BasicContainer { /** * @param args */ @SuppressWarnings("unchecked") public static void main(String[] args) { // TODO 自动生成的方法存根 @SuppressWarnings("rawtypes") Collection c=new ArrayList(); c.add("hello"); c.add(new Name("f1", "f2")); c.add(new Integer(100)); c.remove("hello"); c.remove(new Integer(100)); System.out.println(c.remove(new Name("f1", "f2"))); System.out.println(c); } }
容器的remove方法移除的也是能够equals成功的对象,在Main()方法的前两个remove操作中,String类和Integer类都已经覆写了Object类的equals方法了,所以可以移除成功并且返回True,而Name类默认继承Object类,也就继承了它的equals方法,Object的这个方法和“==”是一样,表示指向的是同一个对象,所以移除Name类会返回false
注:两个对象如果equals,那么他们的hascode()返回值应该也是相同的,容器类对象在调用remove、contains等方法时需要比较对象是否相等,这会涉及到对象类型的equals方法和hascode方法,对于自定义的类,需要重写equals和hascode方法以实现自定义的对象相等规则,一般比较对象的时候主要用的eqauls,当用Map接口的容器类时,如果对象作为键,那么就用的是hascode方法,因为这个效率更高,比如两个对象已经equals了,那么hascode方法就只需要返回某个字段的父类的hascode方法值就可以了
package com.collectiontest.demo; public class Name { private String fistname,lastname; public String getFistname() { return fistname; } public String getLastname() { return lastname; } public Name(String fistname, String lastname) { this.fistname = fistname; this.lastname = lastname; } @Override public String toString() { return "fistname"+" "+"lastname"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((fistname == null) ? 0 : fistname.hashCode()); result = prime * result + ((lastname == null) ? 0 : lastname.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Name other = (Name) obj; if (fistname == null) { if (other.fistname != null) return false; } else if (!fistname.equals(other.fistname)) return false; if (lastname == null) { if (other.lastname != null) return false; } else if (!lastname.equals(other.lastname)) return false; return true; } }
Iterator接口
package com.collectiontest.demo; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; public class BasicContainer { /** * @param args */ public static void main(String[] args) { // TODO 自动生成的方法存根 @SuppressWarnings("rawtypes") Collection c=new HashSet(); c.add(new Name("f1", "l1")); c.add(new Name("f2", "l2")); c.add(new Name("f3", "l3")); c.add(new Name("f4", "l4")); Iterator i=c.iterator(); while (i.hasNext()) { //next()返回值为object类型,需要转换为相应类型,1.5之后有泛型 Name n=(Name)i.next(); System.out.println(n.getFistname()+" "); } } }
再来看一个删除元素的例子
package com.collectiontest.demo; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; public class BasicContainer { /** * @param args */ public static void main(String[] args) { // TODO 自动生成的方法存根 @SuppressWarnings("rawtypes") Collection c=new HashSet(); c.add(new Name("f1", "l1")); c.add(new Name("f2", "l2")); c.add(new Name("f3", "l3")); c.add(new Name("f4", "l4")); Iterator i=c.iterator(); for (Iterator iterator = c.iterator(); iterator.hasNext();) { Name name = (Name) iterator.next(); if(name.getFistname()=="f1") { iterator.remove(); //name的remove方法会将该元素锁定 //如果换成c.remove(name); 会产生例外 } } } }
Set接口
Set接口是Collection接口的子接口,Set接口没有提供额外的方法,但实现Set接口的容器类中的元素是没有顺序的,而且不可以重复
J2SDK API中所提供的Set容器类有HashSet,TreeSet等
package com.collectiontest.demo; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class BasicContainer { /** * @param args */ public static void main(String[] args) { // TODO 自动生成的方法存根 Set s=new HashSet(); s.add("hello"); s.add(new Name("f1", "l1")); s.add("hello"); //不会添加进去 System.out.println(s); } }
package com.collectiontest.demo; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class BasicContainer { /** * @param args */ public static void main(String[] args) { // TODO 自动生成的方法存根 Set s1=new HashSet(); Set s2=new HashSet(); s1.add("a");s1.add("b");s1.add("c"); s2.add("d");s2.add("b");s2.add("a"); //set和list容器类都具有Constructor(Collection c)构造方法用以初始化容器类 Set sn=new HashSet(s1); sn.retainAll(s2); Set su=new HashSet(s1); su.addAll(s2); System.out.println(sn); System.out.println(su); } }
List接口
List接口是Collection接口的子接口,实现List接口的容器类中的元素是有顺序的,而且可以重复
List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素
J2SDK API中所提供的Set容器类有ArrayList,LinkedList等,接口中的方法(当然,这是JDK1.4的版本)如下图
List常用算法:类Java.util.Collection提供了一些静态方法实现了基于List容器的一些常用算法
Comparable接口
上面的算法根据什么确定容器中对象的“大小”顺序?
所有可以“排序”的类都实现了java.lang.Comparable接口,Compare接口中只有一个方法
public int compareTo(Object obj); 该方法:
返回0表示 this==obj
返回正数表示 this>obj
返回负数表示 this<obj
实现了Comparable接口的类通过实现compareTo方法从而确定该类对象的排序方式,比如我们在之前的Name类中实现该方法
public int compareTo(Object object) { //先比较姓,如果姓一样就比较名 Name n=Name(object); int lastcmp=lastname.compareTo(n.lastname); return (lastcmp!=0)?lastcmp:fistname.compareTo(n.fistname); }
如何选择数据结构
衡量标准:读的效率和改的效率
Array读快改慢,Linked改快读慢,Hash两者之间
Map接口
实现Map接口的类用来存储键值对,接口的实现类有HashMap和TreeMap等,接口的方法如图
在JDK1.5之前,Map接口中的方法还不具有自动装箱拆箱功能,例如添加一个数字1,必须这样写put("one",new Integer(1))
获得这个元素 int i=(Integer)map.get("one").intValue()
在JDK1.5之后,就可以直接这样写:put("one",1); int i=(Integer)map.get("one")