Java集合总结
一.集合概述
由于数组长度固定,当添加的元素超过了数组的长度时,需要对数组重新定义,故Java提供集合,能储存任意对象,随着元素的改变而改变。
数组和集合的区别:
1>.数组既可以存储基本数据类型,又可以储存引用数据类型,基本数据类型储存的是值,引用数据类型储存的是地址值。集合只能储存引用数据类型,集合在存储基本数据类型的时会自动装箱变成对象,故集合只能存储引用数据类型。
2>.数组的长度是固定,不能自动增长;而集合的长度是可变的,根据元素的改变而改变。
二.集合框架
Java的集合大致可以分为四个体系,Set,List,Map,Queue;Set代表无序,不可重复的集合;List代表有序,重复的集合;Map代表具有映射关系的集合,Queue代表一种队列集合的体现。
三.Collection体系(单向)
Set与List接口是Collection接口派生的两个子接口,故Collection具有的方法两者均含有。
1.方法:(不带All)
boolean add (E,e) //添加元素,如果集合对象被添加操作改变了则返回true
boolean remove(Object o) //删除指定元素,当集合中包含一个或多个元素被删除,该方法将返回true
void clear() //清空集合,使集合长度变为0.
boolean contains(Object o) //查看集合里是否包含指定元素
boolean isEmpty() //判断是否为空,长度为0时返回true,否则返回false
int size //获取集合中元素的个数
add方法如果是List集合,会一直返回true,因为List集合是可以储存重复元素的,而如果是set集合,当储存重复元素是会返回false
带All:
举个栗子
public static void main(String[] args)
{
Collection c1=new ArrayList();
c1.add("a");
c1.add("b");
c1.add("c");
c1.add("d");
Collection c2=new ArrayList();
c2.add("a");
c2.add("b");
boolean b1=c1.removeAll(c2)//删除的是交集
// boolean b1=c1.containsAll(c2)//判断调用的集合是否包含传入的集合
// boolean b1=c1.retainAll(c2);//取交集,如果调用的c1集合改变就返回true,不变就返回false
System.out.println(b1);
c1.addAll(c2);//将c2添加到c1中,输出结果是[a,b,c,d,a,b]
// c1.add(c2);//将c2当成一个元素添加到c1中,输出结果是[a,b,c,d,[a,b]]
System.out.println(c1);
}
2.集合的遍历:依次获取集合中的每一个元素。
法一:利用for循环遍历
代码如下
public static void main(String[] args)
{
Collection c=new ArrayList();
c.add("a");
c.add("b");
c.add("c");
c.add("d");
/*转化成数组遍历*/
Object[] arr = c.toArray();//将集合转化成数组
int i;
for(i=0;i<arr.length;i++)
{
System.out.println(arr[i]);
}
}
法二:迭代(遍历)
举个栗子
public static void main(String[] args)
{
Collection c=new ArrayList();
c.add("a");
c.add("b");
c.add("c");
c.add("d");
/*对集合中的元素迭代*/
Iterator it = c.iterator();//获取迭代器
while(it.hasNext())//判断集合中是否有元素,有就返回true
{
System.out.println(it.next());//相当于指针,每次向后移动一个
}
}
四.List
List中特有的方法
void add(int index,Object element);//在指定位置添加元素
boolean addAll(int index,Collection c);//将集合中c所包含的所有元素都插在List集合的index处
remove(int index);//通过索引删除元素,并返回剩余的元素
get(int index);//通过索引获取元素
set(int index,Object element);//修改指定位置的元素返回新元素
除过iterator()f方法外,List还提供了一个listIterator()方法,该方法返回一个listIterator(),继承了Iterator接口。
举个栗子:
public static void main(String[] args)
{
List list =new ArrayList();//父类引用指向子类对象
list.add("a");
list.add("b");
list.add("world");
list.add("c");
list.add("d");
list.add("e");
ListIterator lit =list.listIterator();
while(lit.hasNext())
{
String str=(String)lit.next();
if("world".equals(str))
{
lit.add("javaee");
}
}
System.out.println(list);
}
在原基础上,ListIterator还增加了如下方法
Boolean hasPrevious()//返回该迭代器关联的集合是否还有上一个元素
Object previous()//返回迭代器的上一个元素
void add()//在指定位置插入一个元素
例如:
ListIterator lit =list.listIterator();
while(lit.hasNext)//正向遍历
{
System.out.println(lit.next());
}
while(lit.hasPrevious())//逆向遍历
{
System.out.println(lit.previous());
}
逆向遍历必须与正向遍历配套使用,因为,逆向遍历是指针向前移动,只使用逆向遍历时,会指向首元素的前一个位置,由于未储存元素,所以循环不会进行,即无法遍历
(一).ArrayList与Vector(数组实现)
这两个的用法基本一样,后者已经被前者替代。Vector较为古老,方法名较长,Java改写了其中的方法,除此之外,Vector还有许多缺点,通常尽量少用Vector。
ArrayList与Vector的显著区别:
ArrayList的线程不安全,但效率高;而Vector的线程比较安全,但其效率较低
(二).LinkedList(链表实现)
特有的方法:
void addFirst(Object e)及addLast(Object e)//添加第一个,最后一个
getFirst()及getLast()//得到第一个,最后一个
removeFirst()及removeLast()//删除第一个,最后一个
get(int index)//找到索引的元素
小结:
List的三个子类的特点:
ArrayList :底层数据结构是数组,查询快,增删慢。线程不安全,效率高。
Vector:底层数据结构是数组,查询快,增删慢。线程安全,效率高。
LinkList:底层数据结构是链表,查询慢,增删快。线程不安全,效率高。
查询多,用ArrayList;增删多,用LinkedList。
五.Set接口
Set集合与Collection基本完全一样,没有提供额外的方法,实际上Set就是Collection,只是行为不同(Set不允许包含重复元素)
Set中比较元素是否相等不是使用运算符==,而是equals进行判断,如果两个元素相等,就会返回true,Set则就不会再添加该元素,若为false则会添加
(一).HashSet类
HashSet是按照Hash算法来储存集合中的元素,故具有很好的存取和查找功能。
1.HashSet的特点
1>.不能保证元素的排列顺序,顺序有可能发生变化。
2>.集合元素值可以是null。
2.存储不会出现重复元素的原因:
当向HasSet集合中储存元素时,它会调用hashCode()方法来得到该对象的hashCode值,然后根据HashCode的值来来决定该对象在HashCode中储存的位置。如果两个元素通过equals方法比较返回true,但他们的hashCode()方法返回值不同,HashSet将会把他们储存在不同位置,也可以添加成功。
简单来说,判断的标准是两个对象通过equals方法比较相等,并且对象的hashCode值返回也相等
3.hashCode方法重写方式
Java中如果hashCode的返回值相等,但equals的返回值为false,这时在“桶”里放多个元素,(HashSet中能储存元素的槽位,通常称为“桶”)这会导致性能下降。
重写基本规则:
对象内每个有意义的属性f(即每个用作equals()比较标准的属性)计算出一个int类型的hashCode值
用计算出来的多个hashCode组合计算出一个hsahCode值返回。
栗子:
return f1.hashCode() + (int)f2;
为了直接避免相加产生偶然相等,可以通过各属性乘任意一个质数,再相加。
栗子:
return f1.hashCode()*31+(int)f2*31
也可以对equals方法进行重写
补充:linkedHashSet
特点
底层是链表实现的,是Set集合中唯一一个能保证怎么存就怎么取的集合对象
因为是HashSet的子类,所以也是保证元素唯一的,与HashSet的原理一样
(二)TreeSet:
特有方法:
Comparator comparator():返回当前Set使用的Comparator,或者返回null,表示以自然方式排序
Object first():返回集合中的第一个元素
Object last():返回集合中的最末一个元素
Object lower(Object e):返回集合中位于指定元素之前的元素
Object higher(Object e):返回集合中位于指定元素之后的元素
可以保证集合元素处于排序状态的机制
举个栗子:
由上的结果可以看出,TreeSet并不是根据元素的插入顺序进行排序,而是根据元素的实际值进行排序,采用二叉树进行排序,支持两种排序方式:自然排序和定制排序,默认情况下支持自然排序。
二叉树:小的储存在左边(负数),大的储存在右边(正数),相等就不存(0),在TreeSet集合中,如何储存元素取决于compareTo方法的返回值
六.Map(映射,双向)
Map用于保存具有映射关系的数据,因此Map集合里保存着两组值,一组值用于保存Map里的key,另一组值用于保存Map里的value,这两者可以是任何引用类型的数据,但key不允许重复。
key与value之间存在单向的一对一关系。若将Map里的所有key放在一起,它们就组成了一个Set集合,(所有的key没有顺序,key与key之间不能重复)。若将所有value放在一起,它们又类似于一个List,即元素与元素之间可以重复,每个元素可以根据索引来查找,如果需要从Map中取出元素,需要提供该元素的key索引。
1.小结:
Map与Collection的区别:
Map是双列的,Collection是单列的;
Map的键是唯一的,Collection的子体系Set是唯一的;
Map集合的数据结构值针对键有效,跟值无关;Collection集合的数据结构是针对元素有效
2.提供的方法
//添加功能
put(K key,V value)//添加元素
//如果键是第一次储存,就直接储存元素,返回null
//如果不是第一次存在,就用值把以前的值替换掉,返回以前的值
//删除功能
void clear();//移除所有的键值对元素
remove(Obeject key);//根据键删除键值对元素,并把值返回
//判断功能
boolean containsKey(Object key);//判断集合是否包含指定的键
boolean containsValue(Object value)//判断集合是否包含指定的值
boolean isEmpty()//判断集合是否为空
//获取功能
Set <Map.Entry<K,V>> entrySet()
V get(Object key)//根据键获取值
Set<k> keySet()//获取集合中所有键的集合
Collection<V> values()//获取集合中所有值的集合
//长度功能
int size()//返回集合中键值对的个数
3.集合的遍历
法一:迭代器
public static void main(String[] args)
{
Map<String, Integer> map =new HashMap<>();
map.put("张三",23);
map.put("李四",24);
map.put("王五",25);
map.put("赵六",26);
Integer i=map.get("张三");//根据键获取值
System.out.println(i);
//获取所有键
Set<String> keySet = map.keySet();//获取所有键的集合
Iterator<String> it=keySet.iterator();//获取迭代器
while(it.hasNext())//判断集合中是否又元素
{
String key=it.next();//获取每个键
Integer value = map.get(key);//根据键获取值
System.out.println(key+"="+value);
}
}
法二:增强for循环
for(String key : map.keySet())//map.keySet()是所有键的集合
{
System.out.println(key+"="+map.get(key));
}
(一).HashMap
HashMap 非线程安全
HashMap:基于哈希表实现。使用HashMap要求添加的键类明确定义了hashCode()和equals()[可以重写hashCode()和equals()].
HashMap:适用于Map中插入、删除和定位元素。
(二).TreeMap
TreeMap:非线程安全基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
七.总结:
Collection
List(存取有序,有索引,可以重复)
ArrayList:底层是数组实现,线程不安全,查找和修改快,增删比较慢
LinkedList:底层是链表实现,线程不安全,增删比较快,查找和修改比较慢
Vector:底层是数组实现,线程安全,无论增删改查都慢
如果查找和修改多,用ArrayList;
如果增和删多,用LinkedList;
如果都多用ArrayList.
Set(存取无序,无索引,不可以重复)
HashSet:底层是哈希算法实现
LinkedHashSet:底层是链表实现的,但也是可以保证元素唯一,和HashSet原理一样
TreeSet:底层是二叉树算法实现。
Map
HashMap:底层是哈希算法,针对键
LinkedHashMap:底层是链表,针对键
TreeSet:底层是二叉数算法,针对值