------- android培训、java培训、期待与您交流! ----------
集合是一种可以存储对象的容器,当然这个容器也是一个对象。和数组相比,集合的优势在于他的长度是可以变化,另外集合可以存储多个类型的对象,而数组的长度是固定的,只能存储一个类型的元素;但是集合不能存储基本数据类型,而数组却可以。
所有的集合类都是Collection接口的子类。实现Collection中定义的集合共有功能。其中包括:
public boolean add(Object obj)-->在集合中添加一个对象
public boolean addAll(Collection c) -->在集合中添加一个集合
public void clear()-->将集合中所有对象清空
public int size()-->返回集合中对象的个数
public boolean contains(Object obj) -->判断集合中是否存在对象obj
public boolean containsAll(Collection c) -->判断集合中是否存在集合c
public boolean isEmpty()-->判断集合是否为空,其实内部是在调用size方法,如果为零则返回true
public boolean remove(Object obj)-->在集合中清除对象obj
public boolean removeAll(Collect c) -->在集合中清除与集合c的交集
public Collection retainAll(Collection c) -->返回集合中与集合c的交集
public Iterator iterator()-->获取该集合的迭代器
我们可以通过迭代器来获取这个集合中的所有元素。关于迭代器的方法:
public boolean hasNext()-->判断是否仍有元素可以迭代,如果有则返回true
public Object next()-->返回下一个迭代的元素
public void remove()-->删除指针上的元素。因为如果在迭代中如果用集合对元素的操作方法,会引发并发访问的安全隐患,会触发一个RuntimeException----- ConcurrentModificationException,所以迭代器中定义了自己对元素的操作方法。Iterator中对元素的操作方法只有删除,其他的增加判断的方法定义在子接口ListIterator中。
那么我们去取出一个集合中的所有元素进行打印的话,用迭代器的代码如下
collection c=new ArrayList();
c.add(new String(“abc1”));
c.add(new String(“abc2”));
Iterator it=c.iterator();//获取集合c的迭代器
while(it.hasNext())
{
System.out.println(it.next());
}
Collection有两个子类接口一个是List接口,一个是Set接口。List接口的子类集合是有序集合,可以根据集合中的角标对集合中元素进行操作,可以存在相同元素。而Set接口的子类集合是无序集合,但是他不允许存在相同的元素。List接口子类所共有的方法其实就是在Collection的方法基础上增加了角标的操作。
public void add(int index,Object obj)-->在指定index角标位添加元素public void add(int index,Collection c)-->在index角标位添加元素集合c
public Object remove(int index) -->删除index角标位的元素
public Object set(int index,Object obj) -->讲index角标位元素改成obj元素
public Object get(int i ndex) -->获取index角标位的元素
public int indexOf(Object obj) -->获取第一个为obj元素的角标位
public Collection subList(int start,int end)-->将元素集合中从start角标到end角标中的元素取出封装成集合并返回
public ListIterator listIterator()-->返回该集合的listIterator迭代器
List接口下有三个子类,分别是ArrayList,LinkedList,Vector。
ArrayList底层是数组结构,所以如果数据较大查询的效率较高,但也正因如此,他每次添加或者删除元素,都相当于重建了一个数组,所以如果集合中频繁有增删操作,建议使用LinkedList。线程不同步。方法基本都继承自List。
LinkedList底层是链表结构,每一个元素都是跟自己前一个和后一个元素发生关系,所以他的增删操作只需要改变与其位置相关联的两个元素关系即可,所以效率比较高,但是如果角标读取的话就要从1角标开始计算,所以如果集合中频繁有读取操作,建议使用ArrayList。线程不同步。因为底层结构的不同,所以LinkedList有自己的特有方法来增加效率。
public Boolean addFirst(Object obj)-->在集合第一角标位添加元素obj,jdk1.6出现替代方法--> publicBoolean offerFirst(Object obj)public Boolean addLast(Object obj) -->在集合最大角标位添加元素obj,jdk1.6出现替代方法--> publicBoolean offerFirst(Object obj)
public Boolean removeLast() -->删除集合第一角标位元素,jdk1.6出现替代方法--> publicBoolean pollLast()
public Boolean removeLast() -->删除集合最大角标位元素,jdk1.6出现替代方法--> publicBoolean pollLast()
public Object getLast() -->获取集合第一角标位元素,jdk1.6出现替代方法--> publicObject peekLast()
public Object getLast() -->获取集合最大角标位元素,jdk1.6出现替代方法--> publicObject peekLast()
Vector同ArrayList,底层都是数组结构,但是不同的是Vector是线程同步的,在一般情况下回大大降低效率。所以采用较少。但是Vector特有的取出方式枚举需要说一下。在IO流中的合并流SequenceInputStream中会用到。
Vector v=new Vector();
Enumeration e=v.elements();
while(e.hasMoreElements())
System.out.println(e.nextElements());
Set接口下的子类有HashSet和TreeSet。
HashSet的底层结构是哈希表(实际上是一个HashMap实例)。HashSet集合是通过元素中继承自Object超类的hashCode()方法和equal()方法来判断两个对象是否相同的。通过hashCode方法可以避免每次添加都需要equals的繁琐过程。所以我们在自己定义对象的时候,可以覆写对象继承自Object的这两个方法,使他们按照我们的意志来判断两个元素是否是同一元素。
比如一个学生对象,他有很多属性,我姑且认为姓名相同并且年龄相同就是同一个人。那么我就覆写学生的这两个方法如下:
class Student
{
private String name;
private int age;
Student(String name,int age)
{
this.name=name;
this.age=age;
}
public int hashCode()
{
return name.hashCode()+age*29;//尽量保证返回的值能根据姓名和年龄而不同
}
public Boolean equals(Object obj)
{
if(!(obj instanceOf Student) )//如果传入的对象连学生对象都不是,那么肯定不会是同一个了
return false;
Student s=(Student)obj;//equals方法继承自Object所以必须接收Object对象并强转
return this.name.equals(s.name)&&this.age==s.age;//根据我们的需求只有姓名和年龄相同才会返回true
}
}
此时我们将几个Student对象存入HashSet集合再用迭代器将他们取出会发现他们不会存入相同姓名和年龄的学生。
HashSet是根据哈希值的范围来提高查找效率,如果对象的属性参与hashCode计算,就要谨慎去修改。因为如果修改了该属性,该对象的哈希值就会改变,以后要删除该对象的时候,该对象在HashSet中的索引与现在的哈希值不匹配,就会找不到该元素,他的声明周期会随着HashSet的结束而结束,造成内存泄露。
TreeSet集合的底层是二叉树数据结构。他不仅不允许相同元素存在,更可以帮我们排序。我们将元素存入TreeSet集合之后他是按照自然顺序排序的。而我们要想让元素按照我们的意志进行排序,让元素实现Comparable接口,然后实现里面的CompareTo方法,返回0则代表元素相同,否则根据正数或者负数来判断排列顺序 还是上面的学生类按照姓名和年龄来判断是否为同一个人,但是我还希望集合能帮我把学生按照年龄进行排序。
class Student implements Comparable
{
private String name;
private int age;
Student(String name,int age)
{
this.name=name;
this.age=age;
}
compareTo(Object obj)
{
if(!(obj instanceOf Student))//判断如果不是学生类则抛出运行异常
throw new RuntimeException(“不是学生类”);
Student s=(Student)obj;
if(s.age==this.age)//如果年龄相同,不能返回0,那样就代表是同一个人
return s.name.compareTo(this.name);//字符串得到两个名字的差,如果相同则是同一个人,返回0,否则根据名字排序这两个人
return s.age-this.age;//如果不相等,差肯定是一个正数或者负数,就按照年龄排序}
}
但是如果一个类已经写好我们就尽量不要去改动它,这就用到了比较器。第二种方法是自定义一个比较器,该比较器实现Comparator,然后在比较器中覆写Compare方法,然后再创建TreeSet集合的时候将这个比较器作为参数传给TreeSet集合对象。
class StudentComparator implements Comparable
{
public int compare(Object obj1,Object ojb2)
{
Student s1=(Studnet)obj1;
Student s2=(Studnet)obj2;
if(s1.getAge()==s2.getAge())
return s1.getName().compareTo(s2.getName());
return s1.getAge()-s2.getAge();
}
}
然后我们在定义集合的时候把这个比较器当做参数传给他就可以了TreeSet ts=new TreeSet(StudentComparable);此时ts比较器就拥有了对Student对象进行排序的功能。