JAVA基础之路——集合(上)

集合之集合框架

对于集合中某些底层实现来说,实现和接口是分离的,某些共同的方法,java把他们提取了出来放在一个共同的接口中去。

Collection接口

在java中,集合类的基本接口就是Collection接口,这个接口又两个基本方法:

add方法:用于向集合中添加元素。
Iteratro方法:用于返回一个实现了iterator接口的对象,可以用来遍历集合元素。

迭代器

Collection接口继承了java.lang.Iterable接口,
Iterable接口中包含了Iterator方法,
该方法返回java.util.Iterator对象
该对象就是迭代器。

迭代器是用于迭代(循环、遍历)集合的
其中又hasNext和next方法,分别表示有没有后续元素和取得后续元素
forEach循环的后台实现用的就是迭代器

在java当中迭代器应该一直指向的是元素和元素之间。
(如果要调用remove(删除元素)方法,就要先用.next方法将再删除)
通过反复调用next方法,来获取集合中的元素。
如果到了末尾,就会报出一个错误。因此,在调用next方法之前 应该先调用hasNext方法来确认是否有下一个元素。
例子:

Collection<String> c =new ArrayList<>();
c.add("Tom");
c.add("Jerry");
Iterator<String> liss = c.iterator();
liss.next();   //现在迭代器在"Tom""Jerry"中间。
liss.remove();//删掉了"Tom"
System.out.println(c);//打印集合

注意,在List接口中有一个previous方法,这个方法让迭代器饭返回上一个元素。k 和next方法相反。

List<String> lists = new ArrayList<>();
lists.add("Tom");
lists.add("Jerry");
ListIterator<String> lis = lists.listIterator();
lis.next();//现在迭代器在"Tom""Jerry"中间。
System.out.println(lis.next());//这时迭代器指向"Jerry"后面
System.out.println(lis.previous());//迭代器返回上一个元素,跨过"Jerry" 并且将之处理

**问:为什么要用集合体系接口
答案:设置了许多共同的接口 将共同方法放到其中,这样 变换底层实现的话 不会影响到代码运行。**

泛型使用方法

由于Collection与Iterator都是泛型接口,可以编写操作任何集合类型的使用方法。

例如:

class A{
    public static void main(String[] args) {
        ArrayList<String> str = new ArrayList<>();
        str.add("Tom");
        str.add("Jerry");
        System.out.println(str.contains("Tom"));
    }
    public static <E> boolean contains(Collection<E> c,Object obj){
        for (E element : c)
            if (element.equals(obj))
                return true;
        return false;
    }
}

这是一个检测任意集合是否包含指定元素的泛型方法。

集合框架中的接口

集合有两个基本接口:Collection和Map

Collection下的接口中:

List是一个有序集合,元素会按照顺序添加到集合中,有两种方式访问元素:

1) 使用迭代器,这样必须按照顺序访问元素。
2) 使用一个整数索引来访问,这种方法被称为随机访问,
ListIterator接口是Iterator的一个子接口,它定义了一个方法用于在迭代器位置前面增加一个元素:void add(E element)
数组集合适合用上面的第二个方法 提供一个整数索引来访问这样快一点
链表随机访问很慢,所以推荐用迭代器进行访问。

Set:

Set等同于Collection接口,set的add方法不允许增加重复的元素,比较严谨。

具体的集合

链表(List)

List是线性的,元素有序(放置顺序有序)且允许重复。

List的两个实现
ArrayList插入和删除速度慢,按下标查找速度快
LinkedList在起始和结束处插入和删除速度快,按下标(查第几个)查找速度慢。

Set

散列集(HashSet)
Hash、哈希、散列 指的都是散列。

散列表
一个数组,里面的每个元素都是链表。
散列函数:
参数是对象的散列码,返回值是对象存在散列表中的地址

int hashFun(int hashCode) {
    return hashCode % xx.length(散列表的长度)
}

散列函数一定会有冲突,(就是说如果两个散列码求出来的值都指向一个地方,那么就要往后放链表了)而链表就是为了解决那个冲突的
散列冲突:
有时候会遇到桶被占满的情况,这种现象就被称作散列冲突。

Java会通过某种算法,给字符串生成一串散列码,

散列表用链表数组实现,每个列表被称为桶,想要查找表中对象的位置,就要先计算他的散列码,然后与桶的总数取余,所得到的结果就是保存这个元素的桶的索引,
那为什么要搞这个结构呢?
这个结构不同于数组与链表,虽然散列是无序的,但是它寻找元素(就是通过计算散列码找)的速度比前两者更快
注:如果桶满了(就是说如果桶的总数是128,然后这个链表中存入元素的散列码是128\256\384\512\640\1024…,)那么这时,链表就会变成平衡二叉树。

如果想要更好的控制散列的性能,那么就需要指定一个初始的桶数量,这个数量大概就估计为:预计元素个数的75%-150%。
有的时候会预估错误,导致预估数量少于实际个数(具体的是超过75%(装填因子)),那么就需要再散列,创建一个更大的散列表,这个更大的散列表是原表的两倍大

注意:Set集合是没有get方法的,因为get方法是需要下标来查找的。所以一般用迭代器来查找、迭代。
最后,如果确定你要用的元素之中没有重复的,那么一定要用散列表。

树集(TreeSet)

TreeSet类与散列集相似,树集是个有序集合,可以以任意顺序将元素插入到集合中。

在对集合进行遍历的时候,每个值将自动的按照排序后的顺序呈现,
和hasSet相比,
TreeSet 有序(字符按照字典顺序,数字按照从小到大排序) 不能重复
HasSet 无序 不能重复

LinkedHashSet
与TreeSet和HashSet相比,这个结构的顺序是按照插入顺序排序的

队列与双端队列

队列,先进先出,Queue
Queue<String> queue = new LinkedList<>();
queue.offer("a"); //从最后面开始入队列
queue.poll();//让最前面的元素出队列
queue.peek();//展示最前面的元素,但是不让它出队列

Queue又有PriorityQueue接口,是一个优先级队列。

Queue<String> queue = new PriorityQueue<>();
queue.offer("ssss"); //插入三个元素
queue.offer("tttt");
queue.offer("aaaa");
System.out.println(queue.poll());//"aaaa"
System.out.println(queue.peek());//"ssss"
//是把元素按照字典顺序排列的队列。

以上所学为个人总结。难免不严谨,见谅!

猜你喜欢

转载自blog.csdn.net/weixin_42825755/article/details/82383828
今日推荐