0

0

java集合(二)—集合框架与算法详解

黄舟

黄舟

发布时间:2017-03-01 11:56:28

|

1702人浏览过

|

来源于php中文网

原创

java集合(一)——数据结构详解:http://www.php.cn/java-article-354226.html

框架是指一个类的集,在集中有很多超类和接口,这些超类中实现了很多高级的机制、功能和策略。框架的使用者可以创建子类来实现和扩展超类,而不用来重新创建这些基本的机制。在日常工作中,我们用到的技术基本都是框架,我们去使用那些包,去调用那些函数时都会用到这种框架的思想。在集合(一)中分析完集合的数据结构,今天我们就一起来继续讨论一下集合的框架。

(一)集合数据结构回顾

基本 类型 实现接口 说明
List 链表LinkedList Deque,List,Queue 通过存放前后结点的引用,实现双向链表
数组列表ArrayList List,RandomAccess 数据传入动态数组中,自动扩充数组大小
Set 散列集HashSet Set 哈希法存储数据,无序但查找时效率高
树集TreeSet NavigableSet,Set,SortedSet 按照一定方法排序,输出有顺序的集合
Queue 优先级队列PriorityQueue Queue 按照堆排序的方法排序的队列树
双端队列ArrayDeque Deque, Queue 可以在两端添加和删除,不能操作中间的队列
Map 散列表HashMap Map 用哈希法存放的,键值映射的表
树表TreeMap Map,NavigableMap,SortedMap 将键按照一定方法排序的表
注:前六种(不包括Map)都实现了Collection和Iterator接口,因为篇幅限制没有写出。

(二)视图

在集合类库中,我们已经用了非常大的比例来构建实现类的接口,那么这些接口有什么用呢?如果我们直接把接口中方法写在实现类中不也起到一样的效果么?实际情况远非我们想的这么简单,有很多复杂的东西需要我们通过这些接口来操作。比如,我们把某些类的公有接口类型的对象称为视图对象。这些对象的类型并不是具体的某个实现类,而是一些实现类的公有接口。视图有很多作用,主要的有以下这几点:

1. 视图是轻量级的集包装器

我们可以通过方法,将普通数组包装成类型为List的视图对象。这个视图对象的类型是List,这听上去可能有些不可思议,因为List是一个接口,并不能实例化。但这就是视图对象的优势,这个视图对象可以通过一定的方法被赋予到任何实现了List接口的集合类中,比如常见的ArrayList、LinkedList等等,从而达到我们将一个普通类包装成集合类的目的。

package SetViews;import java.util.Arrays;import java.util.Collections;import java.util.LinkedList;/**
 * 
 * @author QuinnNorris
 * 视图是一个轻量级的集包装器,下面有两个例子
 */public class Views {

    /**
     * @param args
     */
    public static void main(String[] args) {        // TODO Auto-generated method stub
        //-----------------------例1----------------------
        int[] arr = new int[10];        //创建一个普通的int数组
        Arrays.asList(arr);        //通过asList方法,我们将一个普通的数组转换成List类型的视图对象。

        //-----------------------例2-----------------------
        List ll = new LinkedList<>(); 
        //创建一个LinkedList对象ll。
        ll.addAll(Collections.nCopies(10, "ok"));        
        //nCopies是Collections类的静态方法,可以将“ok”复制10次,并返回一个List类型的视图对象。
        //在这里我们不可以直接把Collections.nCopies的类型强转成LinkedList,因为语法不能上转下
        //我们通过addAll方法将这个内容填充到LinkedList对象ll中。

        ll.set(2, "no");        //我们看看它是否能正常工作,我们试着将第三个链表中的String换成no。
        //请注意,链表最好不要使用get和set方法,这里只是为了实验。
        for(String s : ll){
            System.out.println(s);
        }        //输出结果第三个是no,其他全是ok,没有任何问题。
    }

}

这就是视图的一大优点,它是一个轻量级的数组包装器,将数组包装成集合类库中的类对象。同样的,我们可以把那些键值对、需要存放到Set中的数据…都通过视图包装起来传入相应的类中。所以,我们把这个视图的功能叫做轻量级的集包装器。

立即学习Java免费学习笔记(深入)”;

2.通过视图分离出类中的子范围

可以为很多集合建立子范围视图,这些子范围是原有集合的一个引用,如果修改了这些子范围会影响到原有集合。如果不想有影响,我们需要用其他类似addAll的方法来做复制。在列表中,分例子范围的方法很简单。

package SetViews;import java.util.ArrayList;import java.util.Collections;import java.util.List;/**
 * 
 * @author QuinnNorris
 * 在列表中分例子范围,并进行操作
 */public class SubViews {

    /**
     * @param args
     */
    public static void main(String[] args) {        // TODO Auto-generated method stub

        List al = new ArrayList<>();        //创建ArrayList对象al
        al.addAll(Collections.nCopies(15, 1));        //在al中设置15个1
        List subal = al.subList(5, 10);        
        //subList取出从第6个元素到第10个元素作为一个子范围,返回一个视图对象,我们将它存放到subal中。
        subal.set(0, 0);        //第6个数字改成0

        for(Integer i :al)
            System.out.println(i);        //除了第6个数字为0其他全为1

        subal.clear();//清除子范围

        for(Integer i :al)
            System.out.print(i);        //al列表中只有10个1,中间的五个被清除了
    }

}

除此之外,在其他的有序集和映射表中,我们可以使用排序顺序而不是元素位置来创建子范围。这些方法在SortedSet和SortedMap中有声明。

SortedSet headSet(E toElement)  
           返回此 set 的部分视图,其元素严格小于 toElement。

SortedSet subSet(E fromElement, E toElement)  
           返回此 set 的部分视图,其元素从 fromElement(包括)到 toElement(不包括)。

SortedSet tailSet(E fromElement)  
           返回此 set 的部分视图,其元素大于等于 fromElement。

上面的三个方法是在SortedSet中声明的方法,我们在TreeSet中是可用的。同理,如果把方法中所有的Set换成Map,我们就可以在TreeMap中使用类似的这三个方法,要注意的是,Map中所有的操作都是用键来进行的,而不是值。

3.不可修改的安全视图

在现实生活中,如果你把你的集合对象传入到你同事的方法中,结果发现他错误的把你的对象修改了,这一定会让你恼火不已。那么,我们如何去解决这类问题,让我们的数据结构更加安全呢?在视图中,我们可以用不可修改视图来给我们的对象上锁,如果发现试图对集合进行修改,就抛出一个异常,同时将这个集合还原回没修改的状态。

在Collections类中,为我们提供了这么几种获得不可修改视图的方法:

unmodifiableCollection   : 返回指定 collection 的不可修改视图(下同)。  

   unmodifiableList  

   unmodifiableMap  

   unmodifiableSet 

   unmodifiableSortedMap  

   unmodifiableSortedSet

上面这些方法非常简单清晰,我们来看一个具体的例子,看这些方法是如何工作的。

package SetViews;import java.util.ArrayList;import java.util.Collections;import java.util.List;/**
 * 
 * @author QuinnNorris
 * 不可修改的安全视图举例
 */public class UnmodifaiableViews {

    //这个是调用列表的方法
    private static void changeList(List al) {
        al.set(0, "change");        //error Exception in thread "main" java.lang.UnsupportedOperationException
    }    public static void main(String[] args) {        // TODO Auto-generated method stub

        List al = new ArrayList<>();        //创建ArrayList对象al
        al.addAll(Collections.nCopies(10, "final"));        //前十个元素填充“final”字符串
        changeList(al);        //先直接调用changeList方法,没问题
        changeList(Collections.unmodifiableList(al));        
        //报错,说明在changeList中对al进行了修改,被阻止了,而且抛出了异常
    }

}

不可修改并不是指集合对象再也不能修改,而是当它在套用Collections的静态方法时是不能被修改的。但是这样有个隐含的问题,因为使用了静态方法后,他的类型变成了视图类型,这样导致一些更加细节的方法不能被使用。比如,一个ArrrayList对象在通过Collections.unmodifiableList( )包装后,类型变为List,有一部分ArrayList特有的方法将不能被使用,这是需要注意的一点。

4.同步视图

多线程在我们的日常工作中十分常见,如果由多个线程访问集合,就必须确保集合不会被意外的破坏。在这里也不想过多讨论多线程的问题。在集合类库中,设计者使用了视图机制来保证常规集合的线程安全。比如Collecions类的静态方法synchronizedMap就可以将作为参数传入的Map实现类的对象变为线程安全的Map。

Sylius开源电子商务平台
Sylius开源电子商务平台

Sylius开源电子商务平台是一个开源的 PHP 电子商务网站框架,基于 Symfony 和 Doctrine 构建,为用户量身定制解决方案。可管理任意复杂的产品和分类,每个产品可以设置不同的税率,支持多种配送方法,集成 Omnipay 在线支付。功能特点:前后端分离Sylius 带有一个强大的 REST API,可以自定义并与您选择的前端或您的微服务架构很好地配合使用。如果您是 Symfony

下载
Map map = Collections.synchronizedMap(new HashMap());

相似的方法还有一大堆,和第三点中的不可修改视图是类似的,在这里就不多讨论了。

5.检查视图

有的时候,我们在使用类似ArrayList等数据结构时并不使用泛型,从而会导致一些难以发现的类型错误。这个时候,如果我们使用了视图机制,用一种方法来不断地检查我们的代码就可以直接判断出错误的原因。

package SetViews;import java.util.ArrayList;import java.util.Collections;import java.util.Date;import java.util.List;/**
 * 
 * @author QuinnNorris
 * 动态类型安全视图是如何避免错误的发生举例
 */public class CheckViews {

    /**
     * @param args
     */
    public static void main(String[] args) {        // TODO Auto-generated method stub

        //--------------------发生错误的例子-----------------------

        ArrayList al = new ArrayList<>();        //创建ArrayList对象al
        ArrayList errList = al;        //声明一个没有泛型的ArrayList,并把al赋值给它
        errList.add(new Date());        //这个列表本应该是String类型的,但是现在增加一个Date类型数据在编译运行时都不报错。
        //只有当对内部的数据进行操作时,编译器才有可能发现这个错误并抛出异常

        //-----------------动态类型安全视图机制----------------------

        List safeAl = Collections.checkedList(al, String.class); 
        //调用Collections的静态方法checkedList,第一个参数是列表名,第二个参数是类型
        //这个方法返回一个List视图对象,如果要进行错误的操作,会抛出异常
        List errSafeAl = safeAl;        //再用无泛型的列表去引用检查视图的对象,因为al原本是ArrayList
        errSafeAl.add(new Date());        //现在运行时会报错,Attempt to insert class java.util.Date element into collection 
        //with element type class java.lang.String

    }

}

视图是个好机制,它为我们提供了很多方便快捷的转换,安全等方面的操作,让我们对整个集合类库的构架有了个初步的理解。那么谈完了宏观的概念,我们来看一下实际操作中集合框架的一些细节的特性和机制。

(三)批操作

集合就是许许多多的数据在一起构成的。在实际应用中,处理这些海量的数据让我们非常的头痛,而且一旦需要操作的复杂一些,几遍for循环的时空复杂度直接以次方形式增长,这是我们绝对不想看到的。为了方便集合类中数据的操作,集合框架提供类一种叫做批操作的概念。

package SetViews;import java.util.HashSet;import java.util.Set;/**
 * 
 * @author QuinnNorris
 * 批操作查找两个集合的交集
 */public class BulkViews {

    /**
     * @param args
     */
    public static void main(String[] args) {        // TODO Auto-generated method stub

        Set setA = new HashSet<>();
        Set setB = new HashSet<>();        //创建集合A和集合B这是我们要比较的两个集合

        Set result = new HashSet<>(setA);        //声明集合result存放结果,先用集合A来实例化这个集合

        result.retainAll(setB);        //调用retainAll方法,将B中与A相同的所有元素留下,达到查找交集的目的
    }

}

这是一个比较简单的例子,它省略了for循环,而是采用这种批操作的概念来完成交集的查找。但是方法毕竟有限,我们能处理的问题还是在少数,如果真的想广泛的运用批操作,那么结合视图机制是必须的。因为视图机制可以在一定程度上,可以非常简单的进行类型的转换,通过子视图等方法在复杂度较低的情况下达到自己的目的。

(四)集合类的类型转换

1.集合与数组之间的转换

由于java平台API中的大部分内容都是在集合框架创建之前设计的,所以,有的时候的确需要在传统的数组和现代的集合之间进行转换。我们可以通过asList方法和toArray方法来解决这个问题。

package SetViews;import java.util.Arrays;import java.util.HashSet;/**
 * 
 * @author QuinnNorris
 * 集合与数组之间的转换
 */public class TypeChange {

    /**
     * @param args
     */
    public static void main(String[] args) {        // TODO Auto-generated method stub

        //---------------------数组转集合---------------------------

        String[] values = {"a","b"};        //创建一个普通数组
        HashSet hsValues = new HashSet<>(Arrays.asList(values));        
        //通过Arrays类中静态方法asList,将普通数组转换成List类型的视图对象并实例化

        //---------------------集合转数组---------------------------

        HashSet hsValue = new HashSet<>();        //创建一个集合
        Object[] objValues = hsValue.toArray();        
        //如果调用无参toArray方法,则返回一个Object数组,此时不能类型强转否则出错
        String[] strValues = hsValue.toArray(new String[0]);        
        //有参数的toArray方法如果参数数组的长度小于所需长度的话,重新分配一个能放得下大小的数组
        //我们通过有参数的toArray方法巧妙的将集合对象转换成相应类型的
    }

}

2.Map和Set之间的转换

集合框架并没有把Map作为一个集合来看待,然而,我们可以获得映射表的视图,这个视图是一组实现了Collection接口的对象。大家都知道,Collection和Map是两个不相干的接口,如今Map的视图是Collection的对象,无疑是更加方便了我们的操作。Map接口为我们提供了三个方法,这三个方法返回三个不同的视图:

Set> entrySet()  
           返回此映射中包含的映射关系的 Set 视图。  
  Set keySet()  
           返回此映射中包含的的 Set 视图。  
  Collection values()  
           返回此映射中包含的的 Collection 视图。

这其中值得注意的是Map.Entry,很显然这是一个静态内部接口,这个接口中有几个最简单的方法:

K getKey()  
           返回与此项对应的键。  
  V getValue()  
           返回与此项对应的值。  
  V setValue(V value)  
           用指定的值替换与此项对应的值。

看完了这些方法,我们也就知道如何去将Map转型为其他,或者如何用V来获取K。

package SetViews;import java.util.HashMap;import java.util.Map;import java.util.Set;/**
 * 
 * @author QuinnNorris
 * 集合和映射表之间的转换
 */public class SetMap {

    /**
     * @param args
     */
    public static void main(String[] args) {        // TODO Auto-generated method stub

        Map map = new HashMap();        //创建一个Map对象
        Set set = map.keySet();        //set是包含着map中所有键的内容的集合

        Set> entrySet = map.entrySet();        
        //entrySet是包含着Map中静态内部接口Entry的类对象的集合

        for (Map.Entry es : entrySet)
            System.out.println(es.getKey() + ":" + es.getValue());        
            //循环输出,或者也可以进行,按照Key查Value的操作
    }

}

(五)算法与Collections类

一提到算法大家想到的可能是c语言中各式各样的排序,查找,二分等算法。但是在java集合类库中,并不需要这么麻烦。我们在Collections这个类中实现了几乎所有的简单算法,为了让程序员不会因为每次要实用算法时,都要自己编写一遍而感到苦恼。Collections这个类在上面也多次出现过了,这个类全部都是静态方法,而且它也确实只是在做一些包装性质的工作。这个类和视图密不可分。我们就来看一下Collections中的方法。

static  Queue 
 asLifoQueue(Deque deque) 
//以后进先出 (Lifo) Queue 的形式返回某个 Deque 的视图。 static  int 
 binarySearch(List list, T key, Comparator c) 
//使用二分搜索法搜索指定列表,以获得指定对象。 如果没有找到对象,则返回一个i,应该插入的位置是-i-1static  void 
 copy(List dest, List src) 
//将第二个参数列表的内容复制到第一个参数列表中,要保证第一个参数列表的长度是足够的static boolean disjoint(Collection c1, Collection c2) 
//如果两个指定 collection 中没有相同的元素,则返回 true。 static  void 
 fill(List list, T obj) 
//使用指定元素替换指定列表中的所有元素。 static int frequency(Collection c, Object o) 
//返回指定 collection 中等于指定对象的元素数。 static int indexOfSubList(List source, List target) 
//返回指定源列表中第一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。 static int lastIndexOfSubList(List source, List target) 
//返回指定源列表中最后一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。 static  T max(Collection coll, Comparator comp) 
//根据指定比较器产生的顺序,返回给定 collection 的最大元素。 static  T min(Collection coll, Comparator comp) 
//根据指定比较器产生的顺序,返回给定 collection 的最小元素。 static  List nCopies(int n, T o) 
//返回由指定对象的 n 个副本组成的不可变列表。 static  boolean replaceAll(List list, T oldVal, T newVal) 
//使用另一个值替换列表中出现的所有某一指定值。 static void reverse(List list) 
//反转指定列表中元素的顺序。 static  Comparator reverseOrder(Comparator cmp) 
//返回一个比较器,它强行逆转指定比较器的顺序。 static void shuffle(List list) 
//使用默认随机源对指定列表进行置换。 static  void sort(List list, Comparator c) 
//根据指定比较器产生的顺序对指定列表进行排序。 static void swap(List list, int i, int j) 
//在指定列表的指定位置处交换元素。

(六)总结

两篇集合的文章,从前到后系统的总结了一遍java集合类库的林林总总,感觉学习了很多。尤其是java这种框架的概念,框架把原本分散的一些有关联的东西整合起来,并且给了很多实用的方法,整体上给人一种有血有肉很饱满的感觉。我们在日常使用框架的时候也很有必要去研究一下框架是如何搭建起来的,不仅可以让我们更加熟练的运用,而且能学到设计者的一些优秀的思想。

 以上就是java集合(二)—集合框架与算法详解的内容,更多相关内容请关注PHP中文网(www.php.cn)!

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

20

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

6

2026.01.26

苹果官方查询网站 苹果手机正品激活查询入口
苹果官方查询网站 苹果手机正品激活查询入口

苹果官方查询网站主要通过 checkcoverage.apple.com/cn/zh/ 进行,可用于查询序列号(SN)对应的保修状态、激活日期及技术支持服务。此外,查找丢失设备请使用 iCloud.com/find,购买信息与物流可访问 Apple (中国大陆) 订单状态页面。

20

2026.01.26

npd人格什么意思 npd人格有什么特征
npd人格什么意思 npd人格有什么特征

NPD(Narcissistic Personality Disorder)即自恋型人格障碍,是一种心理健康问题,特点是极度夸大自我重要性、需要过度赞美与关注,同时极度缺乏共情能力,背后常掩藏着低自尊和不安全感,影响人际关系、工作和生活,通常在青少年时期开始显现,需由专业人士诊断。

3

2026.01.26

windows安全中心怎么关闭 windows安全中心怎么执行操作
windows安全中心怎么关闭 windows安全中心怎么执行操作

关闭Windows安全中心(Windows Defender)可通过系统设置暂时关闭,或使用组策略/注册表永久关闭。最简单的方法是:进入设置 > 隐私和安全性 > Windows安全中心 > 病毒和威胁防护 > 管理设置,将实时保护等选项关闭。

5

2026.01.26

2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】
2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】

铁路12306提供起售时间查询、起售提醒、购票预填、候补购票及误购限时免费退票五项服务,并强调官方渠道唯一性与信息安全。

29

2026.01.26

个人所得税税率表2026 个人所得税率最新税率表
个人所得税税率表2026 个人所得税率最新税率表

以工资薪金所得为例,应纳税额 = 应纳税所得额 × 税率 - 速算扣除数。应纳税所得额 = 月度收入 - 5000 元 - 专项扣除 - 专项附加扣除 - 依法确定的其他扣除。假设某员工月工资 10000 元,专项扣除 1000 元,专项附加扣除 2000 元,当月应纳税所得额为 10000 - 5000 - 1000 - 2000 = 2000 元,对应税率为 3%,速算扣除数为 0,则当月应纳税额为 2000×3% = 60 元。

9

2026.01.26

oppo云服务官网登录入口 oppo云服务登录手机版
oppo云服务官网登录入口 oppo云服务登录手机版

oppo云服务https://cloud.oppo.com/可以在云端安全存储您的照片、视频、联系人、便签等重要数据。当您的手机数据意外丢失或者需要更换手机时,可以随时将这些存储在云端的数据快速恢复到手机中。

26

2026.01.26

抖币充值官方网站 抖币性价比充值链接地址
抖币充值官方网站 抖币性价比充值链接地址

网页端充值步骤:打开浏览器,输入https://www.douyin.com,登录账号;点击右上角头像,选择“钱包”;进入“充值中心”,操作和APP端一致。注意:切勿通过第三方链接、二维码充值,谨防受骗

6

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.9万人学习

C# 教程
C# 教程

共94课时 | 7.6万人学习

Java 教程
Java 教程

共578课时 | 51.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号