Collection是集合框架中的一个超级接口,表示一组对象,这些对象也称为 collection 的元素。实现collection接口的主要是两个接口:List和Set,另外的一个是独立的Map接口。
一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
Set集合的特点:一个不包含重复元素的 collection,元素无序排列,长度可变。
HashSet:HashSet实现Set 接口,由哈希表(实际上是一个 HashMap 实例)支持.HashSet的实现是不同步的。如果多个线程同时访问一个集合,而其中至少一个线程修改了该集合,那么它必须 保持外部同步.
当需要向HashSet中放置元素时,应该为要存放到散列表的各个对象定义hashCode()和equals();
下面是一个简单的小例子:
package collection;
import java.util.HashSet;
import java.util.Iterator;
public class HashSetDemo {
public static void main(String[] args) {
HashSet<Student> hashSet=new HashSet<Student>();
Student stu1=new Student("张三",22,"男");
Student stu2=new Student("张三",22,"男");
Student stu3=new Student("张三",22,"男");
hashSet.add(stu1);
hashSet.add(stu2);
hashSet.add(stu3);
Iterator<Student> it=hashSet.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
class Student{
private String name;
private int age;
private String sex;
public Student(String name,int age,String sex){
this.name=name;
this.age=age;
this.sex=sex;
}
public String toString(){
return this.name+"今年"+this.age+"岁了!";
}
/**
* 重写equals()方法和hashCode()方法
* 当没有重写hashCode()方法时,输出结果不同,说明stu1,stu2,stu3是三个不同的对象
* 如果equals()方法只是return this==obj会发现会输出三个结果
*/
public boolean equals(Object obj){
boolean isEquals=false;
if(obj instanceof Student){
Student stu=(Student)obj;
if(this.name.equals(stu.name)&&this.age==stu.age&&this.sex.equals(stu.sex)){
isEquals=true;
}else{
isEquals=false;
}
}
return isEquals;
}
public int hashCode(){
return this.name.hashCode()+new Integer(age).hashCode()+this.sex.hashCode();
}
}
上面例子的运行我们可以按照以下方式:
首先,直接运行案例,你会发现输出的结果为:张三今年22岁了!只有一个元素,这表明我们重写的equals()和hashCode()方法使得集合中的元素是不能重复的
然后,将equals()方法改写为:
public boolean equals(Object obj){
return this==obj;
}
你会发现运行结果为:张三今年22岁了!张三今年22岁了!张三今年22岁了!
这是为什么呢!
因为,此处的equals()方法只是判断当前的对象是否与添加的对象是同一类型,而每一个对象都会在内存中开辟一个空间来保存。这三个对象是不一样的,如果我们将hashCode()和toString()方法注释掉再运行,就会看见是三个不同的结果。事实上,即使不重写equals(),hashCode(),他们也已经默认被调用了。
如果我们不将hashCode()注释掉,显示的三条结果还是一样,但是需要注意的是,这是我们人为定义的,它们的内存地址是不一样的。
TreeSet:此类保证排序后的 set 按照升序排列元素,根据使用的构造方法不同,可能会按照元素的自然顺序 进行排序,或按照在创建 set 时所提供的比较器进行排序,意味着TreeSet中元素要实现Comparable接口
下面是一个简单的小例子:
package collection;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet<Student1> treeSet=new TreeSet<Student1>();
Student1 stu1=new Student1("张三",21);
Student1 stu2=new Student1("张三",20);
Student1 stu3=new Student1("张三",22);
treeSet.add(stu1);
treeSet.add(stu2);
treeSet.add(stu3);
Iterator<Student1> it=treeSet.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
class Student1 implements Comparable<Student1>{
private String name;
private int age;
public Student1(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
return this.name+"今年"+this.age+"岁了!";
}
@Override
public int compareTo(Student1 stu) {
// return 0;
int a=0;
if(this.age==stu.age){
return a;
}else{
a=this.age>stu.age?-1:1;
}
return a;
}
}
上面的例子,我们按照以下方式运行就会很好的理解TreeSet的要义:
首先直接运行,发现结果按年龄从小到大排序
然后,将代码中1和-1调换位置,发现年龄按从大到小排序
然后,将compareTo()中的代码直接改为return 1;会发现,所有结果按添加顺序打印
若改为return -1;所有结果按添加的顺序倒序打印
若改为 return 0;只会打印一条语句:张三今年21岁了!
这是为什么呢!
我们会发现,compareTo()里的参数是一个对象,在API里是这样说明的:
比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
也就是说,此时参与比较的是stu1,stu2,stu3这三个对象,若return 1,表示被比较的对象永远都是最大的,且按照从大到小排序
所以,stu1大于stu2,stu2大于stu3,反之,return -1,道理正好相反。当return 0时需要注意,我们知道,TreeSet实现的是Set接口
那么它首先也是一个元素不能重复的集合,而我们发现打印的数据只有一条,也就是说,在利用add()方法添加元素之前,首先执行的是comparable接口的方法,这样重复的对象被过滤掉了,我们定义返回值是0,也就是说,是死是活都让这三个对象相等,那么后来被添加的stu3和stu2自然被过滤掉了。
List集合特点:一个包含重复元素的collection,元素有序排列,长度可变。 List 接口提供了特殊的迭代器,称为 ListIterator,除了允许 Iterator 接口提供的正常操作外,该迭代器还允许元素插入和替换,以及双向访问。
ArrayList的特点:实现了List接口,存储数据是以数组的形式,排列顺序是按照数据的先后插入顺序,他有一个很大的缺点就是在中间或头部插入或删除数据会浪费很多时间,因为数组中索引会自动前移或后移,效率不高,在数据修改不是很频繁的条件下可以使用。这样的特点是因为它的实现方式是在存储数据的时候还隐含存储了一个指针,这个指针指向下一个元素。
LinkedList的特点:支持顺序或着倒序插入提取数据,只要不是无规则的提取数据它的效率高。
它所存储的指针与ArrayList的不同在于它的指针并不一定指向下一元素,这样对频繁的增删操作提供了更强大的支持。
Map集合的特点:提供三种collection 视图,允许以键集、值集或键-值映射关系集的形式存储和查看数据。
HashMap:实现了Map接口,基于哈希表实现。使用HashMap要求添加的键类明确定义了hashCode()和equals()[可以重写hashCode()和equals()],为了优化HashMap空间的使用,您可以自定义初始容量和负载因子到最佳状态,适用于在Map中插入、删除和定位元素
下面是一个简单的例子:
package collection;
import java.util.HashMap;
import java.util.Iterator;
public class HashMapDemo {
public static void main(String[] args) {
//<K,V>K,V表示的是类类型不是数据类型
HashMap<Integer, Student2> hashMap=new HashMap<Integer, Student2>();
Student2 stu1=new Student2("张三",21);
Student2 stu2=new Student2("张三",20);
Student2 stu3=new Student2("张三",22);
hashMap.put(21, stu1);
hashMap.put(20, stu2);
hashMap.put(22, stu3);
Iterator<Integer> it=hashMap.keySet().iterator();
while(it.hasNext()){
System.out.println(hashMap.get(it.next()));
}
}
}
class Student2{
private String name;
private int age;
public Student2(String name,int age) {
this.name=name;
this.age=age;
}
public String toString(){
return this.name+"今年"+this.age+"岁了!";
}
}
hashMap比较简单,此处不给出具体的操作和说明了,最好是通过API将其中的方法练习即可。
TreeMap:适用于按自然顺序或自定义顺序遍历键(key)。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator
进行排序,具体取决于所定义的排序规则,即使需要被添加的类实现Comparator
接口,然后重写该接口的comparaTo()方法 。
下面是一个简单的例子,具体的用法查看API练习就可以了。
package collection;
import java.util.Iterator;
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
TreeMap<Integer,Student3> treeMap=new TreeMap<Integer,Student3>();
Student3 stu1=new Student3("张三",21);
Student3 stu2=new Student3("张三",20);
Student3 stu3=new Student3("张三",22);
treeMap.put(21, stu1);
treeMap.put(20, stu2);
treeMap.put(22, stu3);
Iterator<Integer> it=treeMap.keySet().iterator();
while(it.hasNext()){
System.out.println(treeMap.get(it.next()));
}
}
}
class Student3{
private String name;
private int age;
public Student3(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
return this.name+"今年"+this.age+"岁了!";
}
}