JAVA集合框架
基础概念
集合: 具有相同性质的一类事物,汇成的一个整体
接口框架:
概念: 为了表示和操作集合而规定的一种同一标准的体系结构
内容: 接口,接口的实现类,对集合运算的算法。
- 接口: 表示集合的抽象数据类型。接口中声明了抽象方法,提供了对集合中的内容进行操作的可能性。
- 实现类: 集合框架中接口的具体实现,是可复用的数据结构。
- 算法: 在集合框架接口的实现类对象上完成有用的计算的方法
-
- 如:查找,排序。通常是多态的,被不同类实现时,相同的方法有不同的表现。
注意:
Java中的集合框架所涉及的接口和类,大都是泛型接口和泛型类。
集合框架图
简图1
简图2
知识:
集合的包在java.util下
集合框架的顶层接口:java.util.Collection和Map
迭代器接口:Java.util.Iterator;
带有Linked,就表示底层用的是链表来进行的存储。
编译器技巧
输入数据后,按下 Ctrl+1 ->回车键 会自动补全需要的
例如:
输入:map.values();
按下:Ctrl+1 ->回车键
自动生成:Collection<String> values3 = map.values();
JAVA.util.Collection接口
常用子接口:
List(序列),Queue(队列),Set(集)
方法:
增删改查
特性:
拥有迭代器:继承迭代器的接口lterable,提供对容器向前遍历的方法
Collenction.sort
排序代码:
Collections.sort(集合名);
如果不是自定义类:
一般用Tree开头的集合(会自动排序)
如果是自定义的类注意
继承Comparable接口,并重写compareTo方法
演示代码
import java.util.*;
/*********************继承接口********************/
class Stu implements Comparable<Stu>{
String num;
String name;
int age;
char x;
public Stu(String num,String name,int age,char x) {
this.num=num;
this.name=name;
this.age=age;
this.x=x;
}
public String toString() {
return num+" "+name+" "+age+" "+x;
}
/********************排序规则**************************/
public int compareTo(Stu o) {
// TODO Auto-generated method stub
return this.num.compareTo(o.num);
}
}
public class Main {
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
ArrayList<Stu> st=new ArrayList<Stu>();
int n=sc.nextInt();
for(int i=0;i<n;i++) {
Stu t=new Stu(sc.next(),sc.next(),sc.nextInt(),sc.next().charAt(0));
st.add(t);
}
/********************排序****************************/
Collections.sort(st);
System.out.println(st.size());
for(Stu t:st) {
System.out.println(t);
}
sc.close();
}
}
JAVA.util.List接口
定义:
List是元素有序并且可以重复的集合(类似于数组)
特点:
List中每个元素都有其对应的顺序索引,可以通过索引来访问指定位置的集合元素。
从而精准 控制每个元素的插入位置/删除某个位置的元素。
方法:
增:
void add(E element) //直接在后面添加元素
void add(int index, E element) //在列表的指定位置插入指定元素
实现类:
ArrayList和Vector类
特点:(动态数组)
- 底层是由数组实现的,因此对元素的随机访问速度极快。
- 数组的长度可以动态改变。
缺点:
和数组一样,不适合在线性表中间频繁的插入删除
访问形式:
索引位置,fireach循环,迭代器
Vector类
线程安全的ArrayList类
基本操作
import java.util.Iterator;
import java.util.*;
import java.util.Scanner;
public class Main {
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
//List Arrays.List
List list=new ArrayList();
//不指定类型默认为List<Object> list=new ArrayList<Object>();
//可以存放任何类型元素
list.add("fsf");//添加元素
//输出 1
System.out.println(list1);
//输出 2
int n=list1.size();
for(int i=0;i<n;i++){
System.out.println ( list1.get(i) );
}
//输出 3
for(Object t:list1) {
System.out.print(t+" ");
}
System.out.println();
//利用迭代器输出
Iterator it=list.iterator();
while(it.hasNext()) {
Object object=it.next();
System.out.println(object);
}
sc.close();
}
}
小知识:
- 如果在初始化ArrayList的时候没有指定初始化长度的话,默认的长度为10.
- ArrayList在增加新元素的时候如果超过了原始的容量的话,ArrayList扩容ensureCapacity的方案为“ 原始容量*3/2+1
- Vector是允许设置默认的增长长度,Vector的默认扩容方式为原来的2倍。
LinkeList类
LinkedList底层是基于双向循环链表的结构实现,适合频繁的在中间插入删除数据。
在LinkedList中有一个类似于c语言中结构体的Entry内部类。
在Entry的内部类中包含了前一个元素的地址引用和后一个元素的地址引用类似于c语言中指针*
缺点:
随机访问速度较慢
线程不安全
基本操作:
import java.util.LinkedList;
import java.util.List;
public class LinkedListDemo {
public static void main(String[] args) {
List<String> list = new LinkedList<String>();
list.add("小小酥");
list.add("小张");
list.add("abc");
//使用foreach遍历LinkedList
for(String str : list) {
System.out.println(str);
}
//使用数组遍历
String[] strArray = new String[list.size()];
list.toArray(strArray);
for(String str1 : strArray) {
System.out.println(str1);
}
//还有其他的方法的话我没去研究了
}
}
Stack类
Stack继承自Vector,是一个后进先出的堆栈。
JAVA.util.Set接口
定义:
Set是元素无序不可重复的的集合
无序是指:元素插入的顺序与输出的顺序不一致
虽然Set中元素没有顺序,但是元素在set中的位置是由该元素的HashCode决定的,其具体位置其实是固定的。
特点:
- 没有索引
- 不允许有重复的元素
- 最多允许一个null元素对象。(还是不可重复导致的)
实现类
:实现了Set接口的所有特性
HashSet类
(最常用)
底层基于基于HashMap实现,因此元素无序,但具有了很好的存取和查找性能。
注意
- HashSet中允许存放null值(但是在HashSet中仅仅能够存入一个null值)
- HashSet中存储的元素虽然无序,但是位置是固定的(原因同Set接口)
基本操作
import java.util.Iterator;
import java.util.*;
import java.util.Scanner;
public class Main {
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
//创建
Set set=new HashSet();
//添加
set.add("add");
set.add(123);
set.add(123);
set.add(1.5);
//判断是否含有某元素
System.out.println(set.contains("apple"));
//输出: false
//遍历输出
Iterator it=set.iterator();
while(it.hasNext()) {
Object object=it.next();
}
sc.close();
}
}
LinkedHashSet类
LinkedHashSet底层基于LinkedHashMap实现,从而具有set集合不重复的特点,和有序的特点。
有序的原因:
概述
底层数据结构由哈希表和链表组成。
哈希表保证元素的唯一性。
链表保证元素有素。(存储和取出是一致)
点击查看具体原因
- 哈希表是无序的,因此存进的元素都是随机的。而LinkedHashSet同时存入:元素数据+指针,
- 并且访问的时候利用指针顺序访问元素,
就可以保证有序了
即因为速度快,存的时候用哈希表。为了有序,访问的时候用链表访问。
上关系: LinkHashSet不仅是Set接口的子接口而且还是上面HashSet接口的子接口。
TreeSet类
TreeSet 底层算法是基于TreeMap实现的,是一种排序二叉树。存入Set集合中的值,会按照值的大小进行相关的排序操作。
注意:
- TreeSet非线程安全
- TreeSet集合不是通过hashcode和equals函数来比较元素的.
- 它是通过compare或者comparaeTo函数来判断元素是否相等.compare函数通过判断两个对象的id,相同的id判断为重复元素,不会被加入到集合中。
JAVA.util.Map接口
定义:
Map接口是一组无序的Key-Value的键值对的组合。
特点:
- Map中的每个成员方法由一个关键字(key)和一个值(value)构成。
- 键key不能重复,值value不受限制
- 每个键只能与一个成员元素相对应。
注意:
- Map接口不直接继承于Collection接口
- Map中的键-值对以Map.Entry类型的对象存在
- 支持泛型Map<K,V>
访问方法:
键集合,值集合,Entry集合
实现类
HashMap和Hashtable类
HashMap基于Hash数组(Entry[] table)实现,查询速度快,
若Key的Hash值相同,则通过散列链表的形式将所有相同Hash值的元素串起来。
上关系:
HashMap实现了Map、CloneMap、Serializable三个接口,并且继承自AbstractMap类。
注意:
- 新建一个HashMap时,默认的话会初始化一个大小为16,负载因子为0.75的空的HashMap
- 线程不安全
- 可以在列表中放置一个key为null的元素,也可以多个value为null的元素
Hashtable:
线程安全,不允许键和值有null的元素。
基本操作
import java.util.Iterator;
import java.util.*;
import java.util.Scanner;
public class Main {
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
//建立
Map map=new HashMap();
//添加元素
map.put(1, "abc");
map.put(false, 100);
map.put(200, '1');
// 修改元素
map.replace(1, "new");
// 删除元素
map.remove(200);
// 查询元素
String f = (String)map.get(1);//如果定义泛型,则无需强转
System.out.println("F的值为:" + f);
// 输出结果:F的值为:abc
//查询是否有该键值
System.out.println(map.containsKey(1));
//输出结果:true
//遍历:foreach
for(Entry en:map){//例样代码,不一定对
System.out.println(en);
}
//遍历:用迭代器
// 遍历key
Set keySet =map.keySet();
Iterator it1=keySet.iterator();
while(it1.hasNext()) {
Object key=it1.next();
Object value=map.get(key);
System.out.println(key+"-"+value);
}
System.out.println("------------------");
//遍历value
Collection values = map.values();
Iterator it2=values.iterator();
while(it2.hasNext()) {
Object value =it2.next();
System.out.println(value);
}
System.out.println("====================");
//遍历entry
Set entrySet=map.entrySet();
Iterator it3=entrySet.iterator();
while(it3.hasNext()) {
Map.Entry entry=(Map.Entry)it3.next();
Object key=entry.getKey();
Object value=entry.getValue();
System.out.println(key+"--"+value);
}
// 遍历map-forEach方法(Java8新特性)
map.forEach((k,v)->
System.out.println("key : " + k + "; value : " + v)
);
sc.close();
}
}
LinkedHashMap类
linkedHashMap底层依靠双向链表和Hash表来实现的,是有序的。
LinkedHashMap类维护着一个运行于所有条目的双重链接列表
注意:
- 允许使用null值和null键
TreeMap类
TreeMap基于红黑树(Red-Black tree)实现(每一个key-value节点作为红黑树的一个节点),是一个自动排序的key-value集合,非同步。
因此它便有一些扩展的方法:
firstKey(),lastKey()等,你还可以从TreeMap中指定一个范围以取得其子Map。
排序扩展
对于自然排序:TreeMap中所有的key必须实现Comparable接口,并且所有的key都应该是同一个类的对象,否则会报ClassCastException异常。
对于定制排序:定义TreeMap时,创建一个comparator对象,该对象对所有的treeMap中所有的key值进行排序,采用定制排序的时候不需要TreeMap中所有的key必须实现Comparable
如果使用自定义的类来作为TreeMap中的key值,且想让TreeMap能够良好的工作,则必须重写自定义类中的equals()方法,TreeMap中判断相等的标准是:两个key通过equals()方法返回为true,并且通过compareTo()方法比较应该返回为0。
Iterator 与 ListIterator
Iterator
定义:
public interface Iterator<E> {}
作用:
Iterator是一个接口,它是集合的迭代器。集合可以通过Iterator去遍历集合中的元素。
提供的API接口:
- boolean hasNext():判断集合里是否存在下一个元素。如果有,hasNext()方法返回 true。
- Object next():返回集合里下一个元素。
- void remove():删除集合里上一次next方法返回的元素。
示例:
public class IteratorExample {
public static void main(String[] args) {
ArrayList<String> a = new ArrayList<String>();
a.add("aaa");
a.add("bbb");
a.add("ccc");
System.out.println("Before iterate : " + a);
Iterator<String> it = a.iterator();
while (it.hasNext()) {
String t = it.next();
if ("bbb".equals(t)) {
it.remove();
}
}
System.out.println("After iterate : " + a);
}
}
/*输出结果如下:
*Before iterate : [aaa, bbb, ccc]
*After iterate : [aaa, ccc]
*/
注意:
- Iterator只能单向移动。
- Iterator.remove()是唯一安全的方式来在迭代过程中修改集合;如果在迭代过程中以任何其它的方式修改了基本集合将会产生未知的行为。而且每调用一次next()方法,remove()方法只能被调用一次,如果违反这个规则将抛出一个异常。
ListIterator
ListIterator是一个功能更加强大的迭代器, 它继承于Iterator接口,只能用于各种List类型的访问。
ListIterator接口定义:
public interface ListIterator<E> extends Iterator<E> {
boolean hasNext();
// 当前光标位置的右面如果有元素,则返回true;没有元素,则返回false。
E next();
//向后移动(向后遍历)
E previous();
//向前移动(向前遍历)
int nextIndex();
//产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引.
int previousIndex();
//产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引.
void remove();
//从列表中删除最后一次执行next()或previous()方法返回的元素。
void set(E e);
//替换它访问过的最后一个元素.
void add(E e);
//在next()方法返回的元素之前或previous()方法返回的元素之后插入一个元素.
}