集合类
集合类的由来
对象用于封装特有数据,对象多了需要存储;如果对象的个数不确定,就使用集合容器进行存储。
集合特点
1. 用于存储对象的容器。
2. 集合的长度是可变的。
3. 集合中不可以存储基本数据类型值。
集合容器因为内部的数据结构不同,有多种具体容器。
不断的向上抽取,就形成了集合框架。
数组和集合类区别
数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。
数组中可以存储基本数据类型,集合只能存储对象。
集合框架的构成及分类:
Collection 接口
集合框架的顶层Collection接口
Collection 的常见方法
添加
boolean add(Object obj);
boolean addAll(Collection coll);删除
boolean remove(Object obj);
boolean removeAll(Collection coll);
void clear();判断
boolean contains(Object obj);
boolean containsAll(Collection coll);
boolean isEmpty();获取
int size();
Iterator iterator(); 获取迭代器其他
boolean retainAll(Collection coll);取交集
Object toArray();将集合转成数组
Collection
|–List:有序(存入和取出的顺序一致),元素都有索引(角标),允许重复元素。
|–Set:元素不能重复,无序。
List
List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引。元素可以重复。
|–Vector:内部是数组数据结构,是同步的。增删,查询都很慢。
|–ArrayList:内部是数组数据结构,是不同步的,替代了Vector,查询的速度快。
|–LinkedList:内部是链表数据结构,是不同步的。增删元素的速度很快。
List 特有的常见方法有一个共性特点就是都可以操作角标
添加
void add(index,element) 在指定的索引位插入元素。
void addAll(index,collection) 在指定的索引位插入一堆元素。删除
Object remove(index) 删除指定索引位的元素。 返回被删的元素
修改
Object set(index,element) 对指定索引位进行元素的修改
获取:
Object get(index) 根据角标获取元素
int indexOf(object) 根据元素获取角标,从前往后查找
int lastIndexOf(object) 根据元素获取角标,从后往前查找
List subList(from,to) 截取一段集合List集合可以完成对元素的增删改查。
import java.util.ArrayList;
import java.util.List;
public class ListDemo{
public static void main(String[] args){
List list = new ArrayList();
show(list);
}
public static void show(List list){
//添加元素
list.add( "abc1" );
list.add( "abc2" );
list.add( "abc3" );
System.out.println(list);
//插入元素
list.add(1, "abc2" );
//删除元素
System.out.println( "remove:" + list.remove(2));
//修改元素
System.out.println( "set:" + list.set(1,"abc8" ));
//获取元素:
System.out.println( "get:" + list.get(0));
//获取子列表
System.out.println( "sublist:" + list.subList(1,2));
System.out.println(list);
}
}
在迭代器(Iterator)获取数据的过程中,不要使用集合操作元素,会出现异常,可以使用 Iterator 接口的子接口ListIterator 来实现在迭代过程中完成对元素的增删改查,只有 list 集合具备该迭代功能。
Set
Set 中元素不可以重复,是无序。
Set接口中的方法和Collection 一致。
|–HashSet:内部数据结构是哈希表,是不同步的。
|–LinkedHashSet:有序,hashset的子类。
|–TreeSet:可以对Set集合中的元素进行排序,是不同步的。
HashSet
HashSet 集合保证元素唯一性是通过元素的hashCode方法,和equals方法完成的。
当元素的hashCode值相同时,才继续判断元素的equals是否为true。 如果为true,那么视为相同元素,不存。如果为false,那么存储。 如果hashCode值不同,那么不判断equals,从而提高对象比较的速度。
哈希表的原理:
- 对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值 称为哈希值。
- 哈希值就是这个元素的位置。
- 如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就存储,在原来对象的哈希值基础 +1顺延。
- 存储哈希值的结构,我们称为哈希表。
- 既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象的关键字是唯一的。 这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。
对于ArrayList集合,判断元素是否存在,或者删元素底层依据都是equals方法。
对于HashSet集合,判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法。
import java.util.HashSet;
import java.util.Iterator;
class Person{
public String name;
public int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public int hashCode(){
return name.hashCode() + age * 39;
}
public boolean equals(Object obj){
if(this == obj)
return true ;//同一个对象放两次,直接返回true
if(!(obj instanceof Person))
throw new ClassCastException("类型错误");
Person p = (Person)obj;
return this .name.equals(p.name) && this.age == p.age;
}
}
public class HashSetTest{
public static void main(String[] args){
HashSet hs = new HashSet();
hs.add( new Person("lisi4" ,24));
hs.add( new Person("lisi7" ,27));
hs.add( new Person("lisi1" ,21));
hs.add( new Person("lisi9" ,29));
hs.add( new Person("lisi7" ,27));
Iterator it = hs.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println(p.getName() + "..." + p.getAge());
}
}
}
TreeSet
TreeSet 用于对 Set 集合进行元素的指定顺序排序,排序需要依据元素自身具备的比较性。
TreeSet 集合的底层是二叉树进行排序的。
TreeSet方法保证元素唯一性的方式是参考比较方法的结果是否为0,如果是 0,视为两个对象重复,不存储。
如果元素不具备比较性,在运行时会发生ClassCastException异常。
TreeSet 对元素进行排序有两种方式
1.让元素自身具备比较功能
元素就需要实现Comparable接口,覆盖compareTo方法。
import java.util.Iterator;
import java.util.TreeSet;
class Person implements Comparable{
public String name;
public int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public int hashCode(){
return name.hashCode() + age * 39;
}
public boolean equals(Object obj){
if(this == obj)
return true ;
if(!(obj instanceof Person))
throw new ClassCastException("类型错误");
Person p = (Person)obj;
return this .name.equals(p.name) && this.age == p.age;
}
public int compareTo(Object o){
Person p = (Person)o;
//先按照年龄排序,再按照年龄排序,以免年龄相同的人,没有存进去。
int temp = this.age - p.age;
return temp == 0?this.name.compareTo(p.name):temp;
}
}
public class TreeSetDemo{
public static void main(String[] args){
TreeSet ts = new TreeSet();
//以Person对象年龄进行从小到大的排序
ts.add( new Person("zhangsan" ,28));
ts.add( new Person("wangwu" ,23));
ts.add( new Person("lisi" ,21));
ts.add( new Person("zhouqi" ,29));
ts.add( new Person("zhaoliu" ,25));
Iterator it = ts.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println(p.getName() + ":" + p.getAge());
}
}
}
2.让集合自身具备比较功能
定义一个类实现Comparator接口,覆盖compare方法,将该类对象作为参数传递给TreeSet集合的构造函数。
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
//创建了一个根据Person类的name进行排序的比较器。
class ComparatorByName implements Comparator{
public int compare(Object o1,Object o2){
Person p1 = (Person)o1;
Person p2 = (Person)o2;
int temp = p1.getName().compareTo(p2.getName());
return temp == 0?p1.getAge()-p2.getAge() : temp;
}
}
public class TreeSetDemo{
public static void main(String[] args){
TreeSet ts = new TreeSet(new ComparatorByName());
//以Person对象年龄进行从小到大的排序
ts.add( new Person("zhangsan" ,28));
ts.add( new Person("wangwu" ,23));
ts.add( new Person("lisi" ,21));
ts.add( new Person("zhouqi" ,29));
ts.add( new Person("zhaoliu" ,25));
Iterator it = ts.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println(p.getName() + ":" + p.getAge());
}
}
}
如果自定义类即实现了Comparable接口,并且TreeSet的构造函数中也传入了比较器,那么将以比较器的比较规则为准。
Map 集合
Map:一次添加一对元素,Collection一次添加一个元素。
Map也称为双列集合,Collection集合称为单列集合。
其实Map集合中存储的就是键值对。
map集合中必须保证键的唯一性。
Map常用方法
1、添加
value put(key,value):返回前一个和key关联的值,如果没有返回null。
2、删除
void clear():清空map集合。
value remove(Object key):根据指定的key删除这个键值对。
3、判断
boolean containsKey(key);
boolean containsValue(value);
boolean isEmpty();
4、获取
value get(key):通过键获取值,如果没有该键返回null。当然可以通过返回null,来判断是否包含指定键。
int size():获取键值对个数。
把map集合转成set的方法:
Set keySet();
Set entrySet();//取的是键和值的映射关系。
对应了两种map取值的方式。
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapDemo{
public static void main(String[] args){
Map<Integer,String> map = new HashMap<Integer,String>();
method(map);
}
public static void method(Map<Integer,String> map){
map.put(8, "王五");
map.put(2, "赵六");
map.put(7, "小强");
map.put(6, "旺财");
//取出map中的所有元素,有两种方式。
//第一种方式,通过keySet方法获取map中所有的键所在的set集合
//在通过set的迭代器获取到每一个键。
//再对每一个键通过map集合的get方法获取其对应的值即可。
Set<Integer> keySet = map.keySet();
Iterator<Integer> it = keySet.iterator();
while(it.hasNext()){
Integer key = it.next();
String value = map.get(key);
System.out.println(key + ":" + value);
}
//第二种方式
//Iterator<Map.Entry<Integer,String>> it = map.entrySet().iterator();
//while(it.hasNext()){
// Map.Entry<Integer,String> me = it.next();
// Integer key = me.getKey();
// String value = me.getValue();
// System.out. println(key + ":" + value);
//}
}
}
Map常用的子类:
|–Hashtable:内部结构是哈希表,是同步的。不允许null作为键,null作为值。
|–Properties:用来存储键值对型的配置文件的信息,可以和IO技术相结合。
|–HashMap:内部结构式哈希表,不是同步的。允许null作为键,null作为值。替代了Hashtable.
|–TreeMap:内部结构式二叉树,不是同步的。可以对Map结合中的键进行排序。
import java.util.HashMap;
import java.util.Iterator;
class Student {
public String name;
public int age;
public Student(){
}
public Student(String name,int age){
this.name = name;
this.age = age;
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
public boolean equals(Object obj) {
if (this == obj)
return true ;
if (obj == null)
return false ;
if (getClass() != obj.getClass())
return false ;
Student other = (Student) obj;
if (age != other.age)
return false ;
if (name == null) {
if (other.name != null)
return false ;
} else if (!name.equals(other.name))
return false ;
return true ;
}
}
public class HashMapDemo{
public static void main(String[] args){
//将学生对象和学生的归属地通过键与值存储到map集合中
HashMap<Student,String> hm = new HashMap<Student,String>();
hm.put( new Student("lisi" ,38),"北京");
hm.put( new Student("zhaoliu" ,24),"上海");
hm.put( new Student("xiaoqiang" ,31),"沈阳");
hm.put( new Student("wangcai" ,28),"大连");
hm.put( new Student("zhaoliu" ,24),"铁岭");
Iterator<Student> it = hm.keySet().iterator();
while(it.hasNext()){
Student key = it.next();
String value = hm.get(key);
System.out.println(key.getName() + ":" + key.getAge() + "---" + value);
}
}
}
LinkedHashSet,LinkedHashMap 这两个集合可以保证哈希表有存入顺序和取出顺序一致,保证哈希表有序。
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapDemo{
public static void main(String[] args){
HashMap<Integer,String> hm = new LinkedHashMap<Integer,String>();
hm.put(7, "zhouqi");
hm.put(3, "zhangsan");
hm.put(1, "qianyi");
hm.put(5, "wangwu");
Iterator<Map.Entry<Integer,String>> it = hm.entrySet().iterator();
while(it.hasNext()){
Map.Entry<Integer,String> me = it.next();
Integer key = me.getKey();
String value = me.getValue();
System.out. println(key + ":" + value);
}
}
}
使用集合的技巧:
- 看到Array就是数组结构,有角标,查询速度很快。
- 看到link就是链表结构:增删速度快,而且有特有方法。
- 看到hash就是哈希表,就要想要哈希值,就要想到唯一性,就要想到存入到该结构的中的元素必须覆盖hashCode,equals方法。
- 看到tree就是二叉树,就要想到排序,就想要用到比较。
- 存储的是一个元素时,就用Collection
- 存储对象之间存在着映射关系时,就使用Map集合。
- 保证唯一,就用Set
- 不保证唯一,就用List。
Collections
Collections 是一个工具类,内部提供的都是静态方法。它的出现给集合操作提供了更多的功能。
Collections.sort(list);//list集合进行元素的自然顺序排序。
Collections.sort(list,new ComparatorByLen());///按指定的比较器方法排序。
Collections.max(list); //返回list中字典顺序最大的元素。
Collections.binarySearch(list,"zz");//二分查找,返回角标。
Collections.reverseOrder();//逆向反转排序。
Collections.shuffle(list);//随机对list中的元素进行位置的置换。
Collection 和 Collections的区别
Collections 是个 Java.util 下的类,是针对集合类的一个工具类,提供一系列静态方法,实现对集合的查找、排序、替换、线程安全化(将非同步的集合转换成同步的)等操作。
Collection 是个 java.util下的接口,它是各种集合结构的父接口,继承于它的接口主要有Set和List,提供了关于集合的一些操作,如插入、删除、判断一个元素是否其成员、遍历等。
数组转集合:
//将arr数组转成list集合。
//可以通过list集合中的方法来操作数组中的元素:isEmpty()、contains、indexOf、set
Arrays.asList(arr);
集合转数组:
Collections.toArray();