------- android培训、java培训、期待与您交流! ----------
一、Collection接口,该接口提供了一些对集合类对象的基本操作方法,下面有两个主要的子类——List和Set集合类。List和Set的相同点是都实现了Collection接口,都有一些共性的基本操作方法。区别是List集合类保存的元素是有序的(即存的顺序和取出的顺序一致),元素是可以重复的,而且带有索引。Set集合类则是无序的、元素不可重复,没有索引。
1、List类的常用子类——ArrayList、LinkedList和Vector,由于ArrayList最常用,故以ArrayList说明问题,为了在编程过程中保存类型安全,需要在使用集合类的时候指定接收类型(即泛型问题)。ArrayList底层是通过数组来实现的,故它存在索引访问方式,同时还可以通过通用的迭代器来遍历集合类的元素。它的特点是:通过索引访问元素效率比较高,然而,在增加和删除元素时,由于处理位置后面的元素需要进行移位操作,索引使得在增删操作时效率不高。eg:
class ArrayTest
{
public static void main(String[] args)
{
ArrayList<String> arrList=new ArrayList<String>();//注意在指定接收类型的时候,要用引用对象类型,不能使用基本数据类型,例如要存int类型元素,指定类型就为其封装类Integer
arrList.add("tianjin");//添加元素
arrList.add("shanghai");
arrList.add("beijing");
arrList.add(1,"wuhan");//在指定位置添加元素
arrList.set(2,"hangzhou");//修改指定位置的元素信息
//集合类的遍历,第一种通过索引
for(int i=0;i<arrList.size();i++)
{
System.out.println("遍历元素"+i+":"+arrList.get(i));
}
//第二种遍历方式,通过Iterator迭代器实现
int index=0;
Iterator<String> iter=arrList.iterator();//调用iterator方法返回一个迭代器
while(iter.hasNext())//通过Iterator的hasNext方法判断元素是否存在
{
System.out.println("遍历元素"+index+":"+iter.next());
index++;
}
}
}
当然,也可以保存自定义的复杂结构的数据,整个操作过程大致是一样的。注意:在使用Iterator迭代器遍历元素过程中对元素进行添加、删除等操作是不可以的,会报ConcurrentModificationException异常,这是由于你在删除元素的时候,集合类和迭代器同时操作元素,在迭代器中进行引用元素的删除操作,迭代器自身并不知道,故产生了该异常。
问题解决:可以通过Iterator下的一个子类对象ListIterator来操作,因为在该类下有一些对元素进行增删改查操作的基本方法,而通过List的listIterator方法正好可以返回一个ListIterator对象,进而可以对集合类元素进行操作。
二、Set集合类的应用:有两个常用集合HashSet和TreeSet。由其名字就可以知道HashSet底层是通过哈希表来实现的,故是无序保存且是保证元素唯一的;而TreeSet底层是通过二叉树数据结构来实现的,可以对其内部元素进行自然排序,不可有重复元素。
1、首先,HashSet是通过哈希表来保存元素的,哈希表中是按照哈希值进行排序,而要保证元素的唯一性就是通过元素的hashCode和equals方法共同完成的。保证元素唯一的原理是:对存进来的元素首先判断其hashCode的返回值是否相同,如果不同说明元素唯一,则存入集合中;如果哈希值相同则会通过调用元素自身的equals方法来判断元素值是否相同(通过equals的返回值,0表示元素值相同),相同则不予存储。
所以,要想往Set集合类中存入自定义对象元素,在创建自定义对象的时候就要复写hashCode和equals方法,保证对象能够正确地存入HashSet中。
import java.util.*;
class HashSetDemo
{
public static void main(String[] args)
{
/*HashSet<String> hSet=new HashSet<String>();
hSet.add("beijing");
hSet.add("tianjin");
hSet.add("hangzhou");
hSet.add("shanghai");
hSet.add("shengzhen");
//添加两个重复的元素
hSet.add("beijing");
hSet.add("tianjin");
System.out.println(hSet);//打印数据可以看出元素是无序的,但是,
//beijing和tianjing两个重复的元素没有保存下来,说明,Set集合保证了元素唯一
//其原理:主要是调用了String类中的hashCode和equals方法,所以在创建自定义类的时候,
//有必要对这两个方法进行复写,否则在存入Set集合时无法保证元素唯一*/
//创建一个用于保存Person元素的Set集合类对象
HashSet<Person> hash=new HashSet<Person>();
hash.add(new Person("gao1","1234"));
hash.add(new Person("guo","1354"));
hash.add(new Person("zhang","1432"));
hash.add(new Person("wang","1634"));
hash.add(new Person("gao1","1623"));
hash.add(new Person("gao","1234"));
//System.out.println(hash);
//输出元素数据
Iterator<Person> iter=hash.iterator();
while(iter.hasNext())
{
Person p=iter.next();
System.out.println("PersonName:"+p.getName()+" "+"PersonId:"+p.getId());
}
//
}
}
//创建一个Person类,有姓名和身份证号两个属性,
//靠身份证号来确定Person对象的唯一性
class Person
{
private String name;//姓名
private String id;//身份证号
public Person(String name,String id)
{
this.name=name;
this.id=id;
}
public void setName(String name)
{
this.name=name;
}
public void setId(String id)
{
this.id=id;
}
public String getName()
{
return name;
}
public String getId()
{
return id;
}
//注意为了让该类的对象能够作为元素存入到Set集合类中,需要复写两个方法
public int hashCode()
{
return this.id.hashCode();//身份证号唯一确定哈希码(不能用重复的身份证号)
}
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
throw new RuntimeException("比较类型不匹配!");
Person p=(Person)obj;
return this.id.equals(p.getId());
}
}
输出结果:
在使用该集合类的时候最重要的一点就是,要根据该集合类保证成员唯一性的特点,在你存储数据的类型中要根据需求复写hashCode和equals方法。
2、Set集合类中的另一个常用的子类是TreeSet,该类的底层是通过二叉树结构来实现的,即有个参考根节点,然后比根节点大的存到右子树,小的存到左子树。所以,该集合类的特点就是可以对里面的元素排序,排序的原理是通过一个比较器或者实现接口Comparable中的comapreTo方法实现(根据其返回值-正数、负数、0(表示重复元素不予保存))。
实现比较的两种方式:1、通过复写接口Comparable的compareTo方法,实现自定义排序。2、通过自行设计一个继承自Coparator的子类,复写compare(s1,s2)的方法,然后在应用时创建一个比较器(自己设计的类)引用对象,然后将其作为参数传递给TreeSet的构造函数即可。
<pre name="code" class="java">import java.util.*;
class HashSetDemo1
{
public static void main(String[] args)
{
/*HashSet<Person> hash=new HashSet<Person>();
hash.add(new Person("gao1","1234"));
hash.add(new Person("guo","1354"));
hash.add(new Person("zhang","1432"));
hash.add(new Person("wang","1634"));
hash.add(new Person("gao1","1623"));
hash.add(new Person("gao","1234"));
Iterator<Person> iter=hash.iterator();
while(iter.hasNext())
{
Person p=iter.next();
System.out.println("PersonName:"+p.getName()+" "+"PersonId:"+p.getId());
}*/
//利用TreeSet集合类保存Person对象元素
TreeSet<Person> tree=new TreeSet<Person>(new NewComparator());//第二种方式——传入一个自定义比较器的引用,该方式具有较高优先级
tree.add(new Person("gao1","1234"));
tree.add(new Person("guo","1354"));
tree.add(new Person("zhang","1432"));
tree.add(new Person("wang","1634"));
tree.add(new Person("gao1","1623"));
tree.add(new Person("gao","1234"));
//System.out.println(hash);
//输出元素数据
Iterator<Person> iter=tree.iterator();
while(iter.hasNext())
{
Person p=iter.next();
System.out.println("PersonName:"+p.getName()+" "+"PersonId:"+p.getId());
}
//
}
}
//创建一个Person类,有姓名和身份证号两个属性,
//靠身份证号来确定Person对象的唯一性
class Person implements Comparable<Person>
{
private String name;//姓名
private String id;//身份证号
public Person(String name,String id)
{
this.name=name;
this.id=id;
}
public void setName(String name)
{
this.name=name;
}
public void setId(String id)
{
this.id=id;
}
public String getName()
{
return name;
}
public String getId()
{
return id;
}
//注意为了让该类的对象能够作为元素存入到Set集合类中,需要复写两个方法
public int hashCode()
{
return this.id.hashCode();//身份证号唯一确定哈希码(不能用重复的身份证号)
}
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
throw new RuntimeException("比较类型不匹配!");
Person p=(Person)obj;
return this.id.equals(p.getId());
}
//为适应TreeSet集合类的存储,需要实现接口Comparable,复写compareTo方法——第一种控制排序的方式
public int compareTo(Person p)
{
//按姓名排序
int num=this.name.compareTo(p.getName());
if(0==num)
return this.id.compareTo(p.getId());
return num;
}
}
//第二种控制比较排序的方式,创建Comparator的子类
class NewComparator implements Comparator<Person>
{
public int compare(Person p1,Person p2)
{
//按照身份证号的顺序排序
return p1.getId().compareTo(p2.getId());
}
}
运行结果:
三、Map集合类:Map和Collection的最大的不同就是:Collection是单列存储元素——即元素值,而Map存储双列元素——实际保存的是<Key,Value>的键值对组合。常用的两个子类是HashMap和TreeMap,他们的底层实现结构同HashSet和TreeSet一样,分别是哈希表和二叉树。该集合类也提供了对集合进行操作的基本方法如添加put(k,v),删除remove(k),判断cotainsKey(k)、containsValue(v)、isEmpty(),获取get(k)。
注意:Map集合类无法直接遍历自身的元素,而是要通过返回Set集合对象的方式,然后通过Set结合的迭代器方式去遍历Map自身的元素信息。这里有两个重要方法:Set<Key> keySet()和Set<Map.Entry<Key,Value>> entrySet(),他们返回的都是一个Set集合对象,但是这两个集合对象里的元素是不同的:第一个保存的是Key,而第二个保存的是Key和Value的映射关系——Map.Entry<Key,Value>。具体操作见实例:
import java.util.*;
//将Person类的对象与其对于的电话号码作为一组键值对,保存到TreeMap中,其中Person对象为Key,电话号码为Value
class TreeMapDemo
{
public static void main(String[] args)
{
//利用TreeMap集合类保存Person对象和电话号码键值对元素
TreeMap<Person,String> tree=new TreeMap<Person,String>();
tree.put(new Person("gao1","1234"),"13523452");
tree.put(new Person("guo","1354"),"132243452");
tree.put(new Person("zhang","1432"),"138267842");
tree.put(new Person("wang","1634"),"18723494");
tree.put(new Person("gao1","1623"),"15224252");
tree.put(new Person("gao","1234"),"1513523452");
//System.out.println(hash);
//通过keySet方法返回保存Key的Set集合,通过操作Set集合的Iterator对象来遍历Map中的元素
System.out.println("第一种遍历方式的结果:");
Set<Person> set=tree.keySet();
Iterator<Person> iter=set.iterator();
while(iter.hasNext())
{
Person p=iter.next();
System.out.println("PersonName:"+p.getName()+" "+"PersonId:"+p.getId()+"--电话号码:"+tree.get(p));
}
//通过entrySet方式遍历
System.out.println("第二种遍历方式的结果:");
Set<Map.Entry<Person,String>> entrySet=tree.entrySet();
Iterator<Map.Entry<Person,String>> entryIter=entrySet.iterator();
while(entryIter.hasNext())
{
Map.Entry<Person,String> entry=entryIter.next();
Person p=entry.getKey();
System.out.println("PersonName:"+p.getName()+" "+"PersonId:"+p.getId()+"--电话号码:"+entry.getValue());
}
}
}
//创建一个Person类,有姓名和身份证号两个属性,
//靠身份证号来确定Person对象的唯一性
class Person implements Comparable<Person>
{
private String name;//姓名
private String id;//身份证号
public Person(String name,String id)
{
this.name=name;
this.id=id;
}
public void setName(String name)
{
this.name=name;
}
public void setId(String id)
{
this.id=id;
}
public String getName()
{
return name;
}
public String getId()
{
return id;
}
//注意为了让该类的对象能够作为元素存入到Set集合类中,需要复写两个方法
public int hashCode()
{
return this.id.hashCode();//身份证号唯一确定哈希码(不能用重复的身份证号)
}
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
throw new RuntimeException("比较类型不匹配!");
Person p=(Person)obj;
return this.id.equals(p.getId());
}
//为适应TreeSet集合类的存储,需要实现接口Comparable,复写compareTo方法——第一种控制排序的方式
public int compareTo(Person p)
{
//按姓名排序
int num=this.name.compareTo(p.getName());
if(0==num)
return this.id.compareTo(p.getId());
return num;
}
}
//第二种控制比较排序的方式,创建Comparator的子类
class NewComparator implements Comparator<Person>
{
public int compare(Person p1,Person p2)
{
//按照身份证号的顺序排序
return p1.getId().compareTo(p2.getId());
}
}
运作结果:
总结:对于哈希表结构实现的集合类,在自定义元素类型的时候,切记要根据需求复写两个方法——hashCode和equals;对于二叉树结构实现的集合类,在自定义元素类型是要实现接口Comparable的compareTo方法或者自定义比较器实现接口Comparator,复写compare方法,然后将其引用作为参数传递给Tree集合类的构造函数。