您的位置:首页 > 职场人生

黑马程序员——Java学习之Collection、List、Set

2015-03-09 01:45 471 查看
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

今天来总结一下这几天学习的关于java的集合框架的内容:

集合,某种程度而言是在数组的基础上发展而来,算的上是”数据容器”的高级版本。

首先看看集合和数组之间的异同吧!

我们存储大量的”对象引用”,使用数组:

数组:

1。数组的长度不可变。(局限性)

2。数组只能存储同类型;

那么有没有什么类似于数组的容器,对于程序员来说,可以无限的存储任何的对象引用。也正是这样的需求,促使集合类的出现!

集合类:

1。集合类本质上就是一个容器,存储对象引用;

2。对于程序员来说,它似乎可以无限的存储任意数量的对象引用。(与数组的不同,也是我们使用集合的原因,用起来比较方便。)

3。集合只能存储引用类型的数据。(这里有一个注意点:我们在工作中会看到直接将一个基本数据类型存储到集合中,其实这是隐式的装箱操作,存储的仍然是引用)

数组和集合的共同点:

1。都是容器;

不同点:

1。数组是定长的。集合的长度可变的。

2。数组可以存储任何类型的数据;

集合只能存储引用类型;

集合有ArrayList、Vector、LinkList、HashSet、LinkedHashSet、TreeSet、HashMapTreeMap等多种实现。为了屏蔽实现差异,java提供了一个Collection接口和Map接口,规定必须实现一些公用的成员方法,比如add、remove、contains、isEmpty、size等等。

不管底层细节是如何实现,这些实现接口的子类至少拥有上面方法。

集合框架包含了两部分:一部分是接口,一部分是类

Collection主要结构图:

常见混淆处:

1。 在集合框架中,接口Map和Collection在层次结构上没有任何关系,它们是截然不同的,千万不要自以为Map接口也是继承自Collection接口哦。

2。 Collection、Lis、Set和Map都只是接口,不是具体的类(即不可直接实例化对象)实现。

Collection 接口:

Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。

所有通用的 Collection 实现类提供两个“标准”构造方法:一个是 void(无参数)构造方法,用于创建空 collection;另一个是带有 Collection 类型单参数的构造方法,用于创建一个具有与其参数相同元素新的 collection。实际上,后者允许用户复制任何 collection,以生成所需实现类型的一个等效 collection。 —– 此段 摘自JAVA API 官方文档

如何遍历Collection中的每一个元素?

用该迭代器即可逐一访问Collection中每一个元素,collection实现类皆支持一个iterator()的方法,该方法实现遍历功能。

Iterator it = collection.iterator();
while(it.hasNext()){
Object obj = it.next();
}


||- - List接口

List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(类似于数组下标)来访问list中的元素。和下面要提到的Set不同,List允许有相同的元素。

除了因继承自Collection接口具有Collection接口必备的iterator()方法外,list还提供一个listiterator()方法,返回一个Listiterator接口,和标准的iterator接口相比,还允许添加、删除、设定元素、还能向前或向后遍历。

实现List接口的常用类有以下:

||- - List 接口

||- -ArrayList类

||- - List 接口

||- -LinkedList类

LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get、remove、insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈,队列或者双向队列。

LinkedList:不保证线程安全,效率高。链表实现;

特有功能:

public void addFirst(E e)及addLast(E e)

public E getFirst()及getLast()

public E removeFirst()及public E removeLast()

||- - List 接口

||- -Vector类

Vector 类是基于数组实现的List 类,Vector 比较古老,被ArrayList 取代了。

虽然ArrayList 是线程不安全的,而Vector 是线程安全的,但是即使这样,也不推荐使用Vector,因为Collections 有方法可以得到线程安全的ArrayList 对象。

比较可总结出List三个子类的特点:

ArrayList: 底层 数组 实现。不保证线程安全,常用于单线程访问。速度较快。

Vector: 底层 数组 实现。线程安全的,可以多线程访问。速度较慢。

LinkedList: 底层 链表 实现。不保证线程安全。速度快。

并发修改异常产生的原因:

当我们通过Iterator遍历集合时,因为Iterator已经有了一份集合的拷贝,它将遍历这个集合,如果正在遍历时,通过”集合对象”去向集合中添加元素时,与Iterator的拷贝就不一致了,这时就产生一个:并发修改异常;

解决方法:

1.使用ListIterator遍历,可以通过ListIterator去添加元素:添加到当前元素的后面;

2.使用List遍历,使用List去添加:添加到集合的最后;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class Demo {
public static void main(String[] args) {
List list = new ArrayList();
list.add("aaa");
list.add("bbb");
list.add("ccc");

/*
* 并发修改异常:
* Iterator it = list.iterator();
while(it.hasNext()){
//正在使用迭代器遍历时,通过list去向集合中添加元素
String str = (String)it.next();//java.util.ConcurrentModificationException
if(str.equals("bbb")){
list.add("eee");
}
}*/

//解决方法一:使用ListIterator遍历集合,通过ListIterator去修改
/*ListIterator listIt = list.listIterator();
while(listIt.hasNext()){
String str = (String)listIt.next();
if(str.equals("bbb")){
listIt.add("eee");
}
}
System.out.println(list);*/

//解决方法二:使用List遍历,使用List添加
for(int i = 0;i < list.size();i++){
String str = (String)list.get(i);
if(str.equals("bbb")){
list.add("eee");
}
}
System.out.println(list);

}
}


Set 接口:

虽然Set接口是无序(取出的顺序不同于存入的顺序)的,但不允许重复元素,即使是null值,也只能存唯一一个。

Set保证不重复的原理:

1.先调用集合中每个对象的hasCode()方法与参数的hasCode()方法的值进行比较,如果相同,继续判断equals()方法;否则,认为不同。

2.简单说就是两个对象的hasCode()返回值相同,并且两个对象的equals()方法返回true。则认为相同,禁止存储.

||- -Set接口

||- -HashSet类

||- -Set接口

||- -LinkedHashSet类

||- -Set接口

||- -TreeSet类

TreeSet 是SortedSet 接口唯一的实现,与HashSet 相比额外的方法如:

Comparator comparator(): 返回当前Set 使用的Comparator,若返回null,表示以自然顺序排序。

1.自然排序:

2.定制排序 (比较器):

TreeSet 的自然排序是根据元素的大小进行升序排序的,若想自己定制排序,比如降序排序,就

可以使用Comparator 接口;

我在基础测试阶段时涉及到的真题分析,使用了自定义比较器(即定制排序)的方式重写

声明类Student,包含3个成员变量:name、age、score,

创建5个对象装入TreeSet,按照成绩排序输出结果(考虑成绩相同的问题)。

分析:题目中要求排序,那么很自然会想到Tree结构,由于是按照单项比较,故TreeSet可满足要求;题目有强调考虑成绩相同情况,故可以根据年龄进行排序,分数相同但年龄小的可排在前面,更需要使用比较器进行比较,自己重写compare()方法,进行排序。

import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;

//定义学生Student类,包含成员属性 name、age、score
class Student{
private String name;
private int age;
private int score;

public Student(String name, int age, int score) {
super();
this.name = name;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}

}

public class Test {

public static void main(String[] args) {
//使用比较器实例化一个TreeSet,并且重写其中的compare()方法
//实例化TreeSet时,使用构造函数:TreeSet<>(Comparator com);
TreeSet<Student> stuSet = new TreeSet<>(new Comparator<Object>(){

public int compare( Object obj1,  Object obj2) {
//obj 转换为 Student
Student stu1 = (Student)obj1;
Student stu2 = (Student)obj2;
//比较分数,分数高的排名靠前
int Score = stu2.getScore() - stu1.getScore();
//当分数一致时,则比较年纪,年纪小的排名靠前
int Age = (Score == 0 ? stu1.getAge() - stu2.getAge(): Score);
return Age;
}});

//循环输入5个Student对象的成员信息
for(int i = 1 ;i <= 5 ; i++){
System.out.println("请输入第 "+ i +"名学员信息:");
System.out.print("姓名:");
String name = (new Scanner(System.in)).next();
System.out.print("年龄:");
int age = (new Scanner(System.in)).nextInt();
System.out.print("分数:");
int score = (new Scanner(System.in)).nextInt();

//封装Student对象
Student stu = new Student(name,age,score);

//将每一个输入的对象信息添加到stuSet集合中
stuSet.add(stu);
}
System.out.println("\t姓名\t年龄\t分数");
//使用增强for遍历stuSet集合中的所有元素,并打印出排好顺序的集合元素
for(Student stu : stuSet){
System.out.println("\t"+ stu.getName() + "\t" + stu.getAge() + "\t" + stu.getScore());
}
}
}


——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐