美文网首页
Java基础day17笔记:Collecitons-sort/m

Java基础day17笔记:Collecitons-sort/m

作者: 楠楠喜欢泡枸杞 | 来源:发表于2019-01-03 21:40 被阅读0次

        10-集合(Collections-sort)

            集合框架我们基本都讲完了,就剩下了这一部分,工具类:

            首先说一下Collections,它的出现有什么特点呢?

            作为一个工具类,首先它里面的方法都是静态的。

            它没有对外提供构造函数,是不需要创建对象的,因为它的对象当中并未去封装特有数据,都是共享型的情况下,定义成静态最方便。

            它的里面有一堆方法,都有什么用呢?

            我现在有一堆元素,不需要保证唯一,用哪个集合?List。

            可是我又想对这里面的元素进行排序。但Tree是Set集合中的,List集合中没有直接排序的方式。

            那么集合框架也想到了,它为我们提供了这样一个工具来完成这个动作。

            Colletions这个工具类是专门用来对集合进行操作的。

            那么,它里面是由n多静态方法所组成的,其中有一个看上去就很爽:

            它可以对List集合进行排序。

            我们先分析一下红框这一部分:

            1.4版本的写法:

            1.5开始,就带泛型了:

            List集合中的元素想要排序是不是需要进行比较?

            所以这个T必须是Comparable的子类:

            Comparable这个接口也带泛型,所以写个T:

            但是为了扩展性更强一些,里面传T的父类也可以:

            OK,现在整体都理解了。

            接下来我们来用一下。

            代码:

            结果:

            List是数组结构,数组结构出现重复元素后依然可以排序,因为它有索引,例:

            接下来我们想改一下排序规则,想对集合中的字符串进行长度排序。

            我们发现还有一个带比较器的sort方法:

            代码实现: 

        11-集合(Collections-max)

            接下来我们看一下Collections中的max方法:        

            试一下:

            上面这个是按自然顺序排。

            下面这个是按照自定义的长度顺序排:

        12-集合(Collections-binarySearch)

            试一下:

            试着找一下集合中不存在的"aaaa":

            这个2是什么呢?

            我们点进binarySearch方法中看一下:

            所以这里返回的是-1-1=-2。

            下面写一下binarySearch的原理:

            验证一下,找一下"aaa":

            再试着找一下"aaaa":

            我们的返回值不够专业,修改一下,返回-(插入点)-1:

            OK啦:

            如果元素不具备比较性怎么办?

            那就用这个方法,具有比较器的:

            这个方法的原理,将上面写的那部分原理代码拿下来,做两处修改即可:

            做这两处修改是因为,原先是str.compare....,但是str有可能不具备比较性,或者它的比较方式不是我们所需要的,这个时候就指定了一个比较器cmp,cmp中有一个compare方法,用这个方法来对str和key做比较。

            而比较器的compare方法就是之前写的按长度来比的:

            现在试一下使用它:

        13-集合(Collections-替换反转)

            接下来演示一下fill方法:

            演示:

            这个方法将集合中的元素全部都替换成了指定的元素。

            接下来做一个小练习:fill方法可以将list集合中的所有元素替换成指定元素,我们现在来实现一下将list集合中的部分元素替换成指定元素。

            思路:

            接下来看一下replaceAll方法:

            演示: 

        14-集合(Collections-reverseOrder)

            用迭代器打印出TreeSet集合中的元素:

            现在我们想将它倒序打印出来,是不是不再用它默认的比较方式,而是传一个比较器。

            比较器:

            但是老需要这么写还是很麻烦,我们要想一想,集合框架中是否提供了这样的方法?没有的话我们才需要自己手动来写。

            在Collections中就有这样一个方法:

            所以我们直接把这个逆向比较器传入就可以了:

            实现了元素的逆序输出:

            我们之前写了一个按长度来排序的比较器,排序出来的结果是从短到长,我们现在想实现从长到短的排序,该怎么做呢?

            Collections中还有一个方法,可以将一个现有的比较器强行逆转,就是刚刚那个逆向比较器的重载方法,刚刚那个逆向比较器没有参数,而这个方法可以传一个比较器:

            这样即可:

            OK了:

        15-集合(Collections-SynList)

            集合中那么多的对象,它们都有一个共同的特点:线程不安全。万一真的被多线程操作了,就会出问题。

            那该怎么办呢?

            自己加锁?

            很麻烦的。

            添加有一个方法,删除有一个方法,我们需要将添加和删除封装到同一个锁里面去,也就是说,在某一时刻,只能有一个线程进行添加或者删除。

            怎么办呢?

            Collecitons就替我们想到了解决方法:

            我们只要将不安全的集合给它,它就会给我们安全的集合。

            这个不需要演示,我们更想知道它底层是怎么实现的。

            下面要介绍源码:

            这里有个SynchronizedList类,我们来看一下:

            我们找到它的添加和删除方法:

            这就是它的实现原理。添加和删除是两个动作,这两个动作要放在一个锁里面才行。

            顺便再说一下swap方法:

            reverse方法在反转的时候需要调换元素在集合中的位置,其实调换的时候就是调用的swap方法来完成。

            将它暴露出来,就可以直接置换List集合中两个元素的位置。

            演示一下:

            顺便再提一下shuffle这个方法:

            对列表中元素位置进行随机置换,听起来很厉害的样子,我们试一下:

            两次运行的结果是不同的,都是随机的。

            其实和洗牌、摇色子一样,以后写相关的代码可以用到。

        16-集合(Arrays)

            Arrays:用于操作数组的工具类。

            里面都是静态方法。

            接下来演示一些方法。

            将数组变成字符串:

            将数组变成List集合(传进来一个数组,返回的是List):

            演示:

            把数组变成List集合有什么好处?

            以前我们要判断一个元素在数组中是否存在,需要遍历这个数组,然后写判断方式,自己完成这个功能就比较麻烦:

            而把数组变成集合之后,我们就可以使用集合的思想和方法来操作数组中的元素:

            数组的方法比较少,集合的方法比较多。

            但是注意,我们执行这句代码:

            运行的时候会报错,不支持的操作异常:

            为什么会这样呢?

            注意:将数组变成集合之后,不可以使用集合的增删方法,因为数组的长度是固定的。如果使用了增删方法,就会发生UnsupportedOperationException。

            我们可以使用集合中诸如contains、get、indexOf()、subList()等方法。

            我们再试一下这个:

            我们发现打印出来的是一个数组的哈希值。

            为什么把字符串往里面一扔就变成集合了呢?

            如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转换成集合中的元素。

            如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。

            我们重新试一下:

            OK了:

        17-集合(集合转成数组)

            说完了数组变集合,接下来说集合变数组。

            该用什么方法呢?

            Collection接口中的toArray方法。

            这里有两个toArray方法:

            我们该用哪一个呢?

            第一个是返回Object类型的数组,第二是返回指定类型的数组,显然第二种更方便一些,就不用强转了。

            我们演示一下:

            为什么传0呢?我们传1试一试:

            运行结果没有什么区别:

            传5试试:

            有区别了:

            总结一下:

            1,指定类型的数组到底要定义多长呢?

            当指定类型的数组长度小于集合的size,那么该方法内部会创建一个新的数组,长度为集合的size。

            当指定类型的数组长度大于集合的size,就不会新创建数组,而是使用传递进来的数组。

            所以创建一个刚刚好的数组最优。(创建短的也可以,但是内存中会多一个数组)

            2,为什么要将集合变数组?

            为了限定对元素的操作,不需要进行增删了。

        18-集合(增强for循环)

            Iterator方法虽然在以前的版本上已经做了改进和更新,方便了很多,可是这个单词也不好写,容易写错。

            接下来,Java在JDK1.5的时候,考虑到了我们的痛苦,帮我们解决了这个问题。

            1.5版本以后,Java给Collection找了个爹,它继承了Iterable接口:

            我们点进这个Iterable接口看看:

            它是1.5开始的。

            这个接口的出现,就是将迭代方法抽取出来了。

            这个接口的出现有什么好处呢?

            它不光是把这个迭代方法抽取出来提高了集合框架的扩展性(以后我们再出一个Collection2接口,只要继承这个Iterable方法,也可以具有迭代方法),另外它还给这个集合框架提供了一个新功能,就是高级for循环:

            这个foreach循环是什么东东呢?

            我们来讲一下高级for循环。

            格式:

            for(数据类型 变量名:被遍历的集合(Collection)或者数组)

            示例: 

            编译运行,也出来了:

            这个写法要比迭代器的写法简单太多。

            但是它底层的原理其实还是迭代器,只是将复杂代码编程简单代码了,这个升级是简化书写。

            s先指向“abc1”,再指向“abc2”,......,它指向的对象一直在变化。

            我们加一个小动作,看看会怎么样:

            打印结果还是原先的样子:

            所以这个循环具有局限性,它只能对集合中的元素进行取出,而不能进行修改。

            迭代器不会这样,迭代器至少还有一个remove删除,如果用列表迭代器(ListIterator),增删改查都行,所以是有区别的。

            所以简化书写虽然提供了很大方便,但是也有局限的地方。

            那么这个for循环和我们传统的for循环有区别吗?

            有的。

            传统for循环和高级for循环的区别:

            高级for有一个局限性,必须有被遍历的目标。

            举个例子,我们想将"hello world"打印100次,传统的for循环方法完全OK,但是高级for循环就无法简单粗暴的完成这个任务。

            所以,建议在遍历数组的时候,还是希望用传统for,因为传统for可以定义角标。

            新的例子:

            将HashMap中的键和值拿了出来:

            接下来我们用entrySet和高级for循环来完成:

            OK:

            另外要注意,ArrayList后面写了泛型,底下才能明确写String,如果没有写泛型,底下只能写Object。高级for循环是1.5版本出现的,泛型也是1.5版本出现的,所以上面带着泛型,下面就可以用泛型的类型。

        19-集合(可变参数)

            接下来讲另外一个JDK1.5版本出现的新特性。

            用例子来说: 

            虽然写好show方法调用它已经方便很多了,但是我们还能更方便。我们写了一个show方法,每次打印数组的时候直接调用这个方法就OK,但是,每次打印不同的数组,我们都得定义一个新的数组出来,作为实际参数,就有点麻烦了。

            1.5版本后,出现了一个新特性:

    这是一个数组

             我们还可以打印数组的长度:

            介绍一下这个特性:可变参数

            其实就是上一种数组参数的简写形式,不用每一次都手动的建立数组对象,只要将要操作的元素作为参数传递即可,隐式将这些参数封装成了数组。

            写成了...,数组不用定义了,爱传几个传几个,不传都可以: 

            这个更新简化了开发代码,提高了开发速度。

            注意:方法的可变参数在使用时,可变参数一定要定义在参数列表最后面。

            例,这里String定义在前面,“haha”匹配给了它,其他的int型数据封装给了可变参数:

            这样运行是OK的。

            而String定义在后面,int...定义在前面,会默认将所有参数都封装到可变参数中,这样就会出问题了:

        20-集合(静态导入)

            接下来讲最后一个1.5版本的新特性:静态导入。

            这里面有一个小插曲,我们先演示一下:

            接下来我们用二分法查找一下1并打印:

            我们发现,每次使用工具类的时候,都要工具类名.。。。,稍微有点麻烦。

            再回想起之前,我们不导入工具类的包,就要这样写:

            而我们导入工具类包之后,这个包名前缀就可以省略了。

            而像Arrays和Collections等等这样的类中都是静态方法,我们把这些类导入的话,方法前面的工具类名是不是也可以省略了呢?

            我们试着这样做:

            编译运行都是OK的。(图略)

            但是忘记省略Arrays.toString(arr)了呀。

            我们也将它省略掉:

            但是编译运行就报错了:

            因为StaticImport类是继承了Object类的:

            Object类中也有一个toString方法,但是这个toString方法不可以传参数,于是就报错了。

            两个包中有同样的方法,一定要加包名来指定命名空间。

            当类名重名时,需要指定具体的包名。                                                                                          当方法重名时,需要指定所属的对象或者类。

            再举个更简单的例子来说明这个问题,packa包和packb包中都有Demo类,那么将它们都导入后,new一个Demo,到底new的是哪一个包中的Demo呢:

            这个时候必须要用指定的所属包名来区分:

            而我们现在导入的包里面有多个同名方法,而且是属于不同的类,Object中有toString,Arrays中也有toString,所以这个时候一定要标明到底是谁的toString。这样就没毛病啦:

            跟你讲喔,还有更爽的呢。

            天天自己写输出语句很麻烦,在java.lang包中有一个System类,这个类中有一个out属性:

            这个属性是静态的。

            System中全都是静态方法。

            我们也将System类中所有静态成员都导入:

            (最后两句前面的System都可以删掉了)

            总结一下,导入的时候,如果import后面没有跟静态static,导入的都是类:

            导入的时候,如果import后面跟了静态static,导入的都是类中的静态成员:

    相关文章

      网友评论

          本文标题:Java基础day17笔记:Collecitons-sort/m

          本文链接:https://www.haomeiwen.com/subject/fbwzlqtx.html