------- 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集合类的构造函数。
本文深入探讨Java集合框架的核心组成部分:List、Set与Map。详细解释了各种集合类的特性和应用场景,包括ArrayList、HashSet和TreeSet等,并展示了如何在自定义对象中实现必要的方法以支持这些集合类的功能。
1165

被折叠的 条评论
为什么被折叠?



