Collections
是一个工具类,静态的工具类,·专门用于对集合的操作的工具类。类上没有定义泛型,方法上定义了泛型。调用该类的方法的时候不用初始化实例,直接调用就可以了。
Collections应用例子1:使用Collections给List内的内容排序
需求:List 内有几个String类型的数据,使用Collections的排序工具给List内的数据按要求排序。
package jihekuangjiagongjulei;
import java.util.*;
public class CollectionsDemo {
public static void main(String[] args) {
sortDemo();
maxDemo();
}
public static void maxDemo()
{
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("z");
list.add("kkkkk");
list.add("qq");
String maxLen = Collections.max(list,new StrLenComparator());
String max = Collections.max(list);
sop("max length= "+maxLen);
sop("max = "+max);
}
public static void sortDemo()
{
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("z");
list.add("kkkkk");
list.add("qq");
sop("version 1:"+list);
Collections.sort(list);
sop("ranging by letters :"+list);
Collections.sort(list,new StrLenComparator());
sop("ranging by length :"+list);
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
class StrLenComparator implements Comparator<String>
{
public int compare(String s1,String s2)
{
if(s1.length()>s2.length())
{
return 1;
}
if(s1.length()<s2.length())
{
return -1;
}
return s1.compareTo(s2);
}
}
输出结果是:
version 1:[abcd, aaa, z, kkkkk, qq]
ranging by letters :[aaa, abcd, kkkkk, qq, z]
ranging by length :[z, qq, aaa, abcd, kkkkk]
max length= kkkkk
max = z
sort
public static <T> void sort(List<T> list, Comparator<? super T> c)可以看出sort 内可以单纯的就写一个要比较的list集合,自带的排序会返回一个从a 到z的按字母排序的集合。
如果不想按字母顺序排序,可以自定义比较器,按自己想要的排序。
比如,如果想按照字母长度排序的话就需要重写比较器,比较器可以是T类和T的父类,自己写的比较器先比较长短,按大小返回正负1,如果长度等,比较内容,最后返还一个按照字符串长度排序的集合,输出就是[z, qq, aaa, abcd, kkkkk]。
如果想找字符串最大的那个按照自然排序就用sort的Max方法。
Collections.max(list)
给出的最大的是z
或者想找到自定义的最大的那个就在list 后写上自定义的比较器。
Collections.max(list,长度比较器);
以字符串长度比较大小的比较器给出的最大的字符串是kkkkk。
fill
public static <T> void fill(List<? super T> list, T obj)
-
使用指定元素替换指定列表中的所有元素。
此方法以线性时间运行。
fill 方法可以用列表上的obj 去替代所有的集合中的元素
使用例子:
public static void fillDemo()
{
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("z");
list.add("kkkkk");
list.add("qq");
sop(list);
Collections.fill(list, "pp");
sop(list);
}
public static void main(String[] args) {
fillDemo();
}
输出结果:
[abcd, aaa, z, kkkkk, qq]
[pp, pp, pp, pp, pp]
上面的所有的字符串都被pp替代了
replaceAll
public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal)使用另一个值替换列表中出现的所有某一指定值。更确切地讲,使用 newVal 替换 list 中满足 (oldVal==null ? e==null : oldVal.equals(e)) 的每个 e 元素。(此方法对列表的大小没有任何影响。)
使用某个元素替换掉集合中的指定元素
使用例子:
public static void replaceAllDemo()
{
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("z");
list.add("kkkkk");
list.add("qq");
sop(list);
Collections.replaceAll(list,"aaa", "pp");
sop(list);
}
输出结果:
[abcd, aaa, z, kkkkk, qq]
[abcd, pp, z, kkkkk, qq]
图上的aaa被pp替换掉了
reverseOrder 1
public static <T> Comparator<T> reverseOrder()返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的 自然顺序。(自然顺序是通过对象自身的 compareTo 方法强行排序的。)此方法允许使用单个语句,以逆自然顺序对实现了 Comparable 接口的对象 collection(或数组)进行排序(或维护)。例如,假设 a 是一个字符串数组。那么:
Arrays.sort(a, Collections.reverseOrder());将按照逆字典(字母)顺序对数组进行排序。
reverseOrder 2
public static <T> Comparator<T> reverseOrder(Comparator<T> cmp)
-
返回一个比较器,它强行逆转指定比较器的顺序。如果指定比较器为 null,则此方法等同于
reverseOrder()
(换句话说,它返回一个比较器,该比较器将强行逆转实现了 Comparable 接口的对象 collection 的 自然顺序)。返回的比较器是可序列化的(假设指定的比较器也是可序列化的或者为 null)。
reverseOrder 在TreeSet后边直接写上会把TreeSet自带的比较器顺序颠倒,如果在reverseOrder()的括号中加入自己重写的比较器比如在方法2中展示的那样
rseOrder(new StrLenComparator1())
就会颠倒自己编写的比较器。
使用例子
public static void orderDemo()
{
TreeSet<String> ts = new TreeSet<String>();//无重写比较器
//TreeSet<String> ts = new TreeSet<String>( Collections.reverseOrder());// 方法1
//TreeSet<String> ts = new TreeSet<String>(Collections.reverseOrder(new StrLenComparator1()));// 方法2
ts.add("abcde");
ts.add("aaa");
ts.add("kkk");
ts.add("ccc");
Iterator<String> it = ts.iterator();
while(it.hasNext())
{
String str = it.next();
System.out.println(str);
}
}
重写的长度比较器
class StrLenComparator1 implements Comparator<String>
{
public int compare(String s1,String s2)
{
if(s1.length() > s2.length())
{
return 1;
}if(s1.length() < s2.length())
{
return -1;
}
return s1.compareTo(s2);
}
}
TreeSet 自带的比较方法输出:
aaa
abcde
ccc
kkk
使用reverseOrder方法1,用reverseOrder 方法颠倒了TreeSet自带比较器的输出:
kkk
ccc
abcde
aaa
和自带的方法正好逆转
使用长度比较器的输出:
aaa
ccc
kkk
abcde
使用reverseOrder方法2,用reverseOrder方法颠倒了重写的长度比较器的输出:
abcde
kkk
ccc
aaa
和原先的长度比较器的方法也是逆转。
shuffle
public static void shuffle(List<?> list)随机的把List中的元素重新排列
使用例子:
public static void shuffleDemo()
{
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("z");
list.add("kkkkk");
list.add("qq");
sop(list);
Collections.shuffle(list);
sop("shuffled list :"+list);
}
输出结果:
[abcd, aaa, z, kkkkk, qq]
shuffled list :[kkkkk, qq, aaa, z, abcd]
第二次输出结果:
[abcd, aaa, z, kkkkk, qq]
shuffled list :[kkkkk, qq, aaa, z, abcd]
每一次随机排序过后都是不一样的顺序。
binarySearch
public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c)使用二分搜索法搜索指定列表,以获得指定对象。在进行此调用之前,必须根据指定的比较器对列表进行升序排序(通过
sort(List, Comparator)
方法)。如果没有对列表进行排序,则结果是不确定的。如果列表包含多个等于指定对象的元素,则无法保证找到的是哪一个。
使用例子:
通过长度比较器排序后再通过binarySearch 找到aaa。
public static void binarySearchDemo()
{
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("z");
list.add("kkkkk");
list.add("qq");
Collections.sort(list,new StrLenComparator());
sop(list);
int index = Collections.binarySearch(list,"aaa");
sop("index="+ index);
}
class StrLenComparator implements Comparator<String>
{
public int compare(String s1,String s2)
{
if(s1.length()>s2.length())
{
return 1;
}
if(s1.length()<s2.length())
{
return -1;
}
return s1.compareTo(s2);
}
}
输出结果:
[z, qq, aaa, abcd, kkkkk]
index=2
上面可以看出来我先通过自己编写的字符串长度比较器给list内的数组排序,然后找到aaa在集合的第二个位置那边。
如果找的是aaaa也就是集合中没有的数字给出的是
[z, qq, aaa, abcd, kkkkk]
index=-4
-4 的来历是这样的:
如果aaaa在集合中,应该给出的是3 这个数字但是因为没有在集合中所以给出了一个-3-1.
公式是:-(如果在集合中应该出现的位置)-1 = -(3)-1 = -4 和上边给出的吻合
把数组变成list集合的好处是:
如果定义数组的时候想判断某个元素是否在的话比较麻烦,如果放在集合中,直接利用集合中的方法和思想去操作数组中的元素。不然要自己写方法比较费时。
数组是一个对象功能比较少
因为数组的长度是固定的所以数组变成的集合不支持增删方法可以用的犯法比如
contains get indexof sublist 等
若增删,发生unsupportedoperationException
其他工具类
Arrays 工具
Arrays 也是一个数据工具类,主要操作的是数组,数组的操作方法有限,通过Arrays的方法可以有更多的方法去操作。
Arrays 可以用aslist方法把数组反回一个受指定数组支持的固定大小的集合列表(list)。
把数组变成list集合的好处是:
如果定义数组的时候想判断某个元素是否在的话比较麻烦,如果放在集合中,直接利用集合中的方法和思想去操作数组中的元素。不然要自己写方法比较费时。因为 数组是一个对象功能比较少的数据存储器。
因为数组的长度是固定的所以数组变成的集合不支持增删方法可以用的犯法比如
contains
get indexof
sublist 等
若增删,发生unsupportedoperationException
如果一个数组使用aslist 方法变成了一个list 的话,是不能做关于增加或者减少有关数组本身长度的操作,比如不能做增加(add)或者删除(remove)的操作。
除此以外数组中变成集合类的时候
如果以前数组中是基本数据类型的话aslist 方法会把整个数组作为一个元素存入集合中。
如果以前数组中是非基本数据类型的话,aslist 方法会把数组中的每一个元素原封不动的存入集合中。
package jihekuangjiagongjulei;
import java.util.*;
public class ArraysDemo
{
public static void main(String[] args) {
String [] arr = {"abc","cc","kkk"};
List<String> list = Arrays.asList(arr);
//list.remove("abc"); 会出现数组unsupportedoperationException
//list.add("bb");
sop(list);
//int[] nums = {2,3,5};
Integer [] nums = {2,3,5};
List<Integer> li = Arrays.asList(nums);//因为不是基本数据类型,所以把数组中的元素作为对象存入集合
li.add(1);
sop(li);
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
输出:
[abc, cc, kkk]
[2, 3, 5]
以上的例子删除abc 或者增加 bb在从aslist 变成的集合中使用都会产生错误
地下如果nums 数组中存入int 类型的数字2 3 5 的话输出可以但是会出现数组本身的hashcode, 如果放Integer 的类型的话就能输出2 3 5三个数字
集合变数组:
当指定类型的数组长度小于了集合size的长度,那么该方法内部会创建一个新的数组,长度为集合的size当指定类型的数组长度大于了集合的size就不会新创建数组,而是使用传递进来的数组。所以创建刚好长度的数组最好。
为啥要集合变数组:
为了限定对元素的操作,当集合是可变长度的当操作的时候可以进行增删操作,返回数组的时候就能够限定长度,使用的话就不能增删了,增加了限定性。
package jihekuangjiagongjulei;
import java.util.*;
public class ArraysDemo1 {
public static void main(String [] args)
{
ArrayList<String> al = new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add("abc3");
String [] arr = al.toArray(new String[al.size()]);
sop(Arrays.toString(arr));
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
上面的输出:
[abc1, abc2, abc3]
我们可以看见,al.toArray后面放的是一个新创建的String类型的数组,大小的话要写成集合的长度。
高级for循环
高级for循环也叫增强for循环
格式:
for(数据类型 变量名: 被变量的集合Collection 或者数组)
s 指向的对象在变化。每次给s赋值之后就是指针跳到下一个元素中,对集合进行便利只能获取元素,但是不能对集合进行操作。
迭代器
迭代器除了便利,还能进行remove集合中元素的动作。如果使用ListerIterator 还可以在便利过程中进行增删改查的操作。
传统的for循环和高级for 的区别是高级for有一个局限性,必须有一个被便利的目标,所以在便利数组的时候还是传统for好,因为传统for可以定义角标。
<pre name="code" class="java">ArrayList<String> al = new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add("abc3");
for(String s: al)
{
// s = "kk";
sop(s);
}
sop(al);
输出的是:
abc1
abc2
abc3
[abc1, abc2, abc3]
s 就是指代每一个al中的元素
如果改成了
ArrayList<String> al = new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add("abc3");
for(String s: al)
{
s = "kk";
sop(s);
}
sop(al);
输出就是:
kk
kk
kk
[abc1, abc2, abc3]
如果先给S赋值为KK,那所有的输出的s都是KK了
使用增强For循环给HashMap遍历
HashMap<Integer ,String > hm = new HashMap<Integer,String>();
hm.put(1, "a");
hm.put(2, "b");
hm.put(3, "c");
for(Map.Entry<Integer,String> me: hm.entrySet())
{
sop(me.getKey()+"-------"+me.getValue());
}
输出结果:
1-------a
2-------b
3-------c
使用增强For循环给数组遍历
int [] arr = {3,5,1};
for(int i :arr)
{
sop(i);
}
输出结果:
3
5
1
可变参数的数组
一种数组作为参数的简写形式,不用没一次都要手动建立数组对象,只要将要操作的元素作为参数传递即可,自动的将这些参数封装成了数组。
package jihekuangjiagongjulei;
public class kebiancanshu {
public static void main(String[] args) {
int [] intarr = new int[2];
show("String",2);
}
public static void show(String str,int...arr)
{
sop(str);
sop(arr);
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
输出结果:
String
[I@15db9742
可变参数的数组要放在最后,前边可以有别的参数,这里第一个输出String ,第二个输出的 [I@15db9742 代表的是数组,前边有个中括号代表的就是数组,整个输出的是数组的地址
public class kebiancanshu {
public static void main(String[] args) {
int [] intarr = new int[2];
show("String",2,33,3);
}
public static void show(String str,int...arr)
{
sop(str);
sop(arr.length);
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
输出的是:
String
3
我把show 方法中的输出改了,让他输出数组的长度,在main方法里,给show 中在string 后边传三个参数,就是说数组中有了三个参数,结果输出数组的长度就是3了。
静态导入
就是导入类中的成员变量,从而可以简化书写其中的类名字
package jihekuangjiagongjulei;
import java.util.Arrays;
import static java.lang.System.*;
public class StaticImport {
public static void main(String[] args) {
out.println("haha");
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
输出
haha
就是一个haha我们没有使用System.out.println("haha")但是效果是一样的。 静态导入的方法是首先使用
import java satatic 目标类.*;
导入了目标类之后,再使用目标类中的成员就不需要去书写目标累的名称了。