黑马程序员_Java基础_集合框架工具类

  一,集合框架工具类 Collections

首先要明确CollectionsCollection是两个完全不同的概念,Collection是集合框架中的一员,它是一个根接口,他有很多子接口,其中有我们最常用的ListSet集合。Collections是集合框架的工具类,它有很多方法可以对很多集合进行操作,并且它没有构造函数,它提供的方法都是静态的,因为它能操作的集合都共享它的方法,所以将这些方法定义成静态的。

举个最简单的例子,当我们想要使用一个集合,不许要保证里面的元素唯一,所以我们只可以使用List集合,我们要对List集合排序,但是List集合没有排序功能,所以既可以使用集合框架工具类的CollectionsSort()方法,对List集合进行排序。这就是Collections的强大之处。

 

1sor有两个方法:

public static <T extends Comparable<? super T>> void sort(List<T> list)

<T extends Comparable<? super T>>的含义是:List集合里面存储的元素是未知类型,我们将这个未知类型假设为T类型,也就是泛型,使用该Sort方法,T类型需要实现Comparable接口,Comparable接口也要定义成泛型,它操作的类型是T类型,但是为了提高它的扩展性,所以允许Comparable接口的泛型定义成T或者其父类型。

 

public static <T> void sort(List<T> list,Comparator<? super T> c)

第二各参数传入的是自定义的比较器,对于没有比较性的对象,必须建立自己的比较器。

 

注意:Collections类的Sort方法是不能操作Set集合的,原因是Set集合有TreeSet子类,具有排序的方法。

 

2max()的两个方法:

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)

该方法使用来获取集合中排序后的末尾的那个元素,比如:List集合中存入字符串,使用默认的比较器,该方法会返回List集合里面的字符串按自然顺序排序后的最后一个字符串。

Collection<? extends T> coll的含义是:集合的泛型类型是T或者T的子类型。

<T extends Object & Comparable<? super T>>的含义是:T必须是Object类的子类,并且T要实现Comparable接口,Comparable接口的泛型是T或者T的父类型。

 

需求:自定义一个List集合,里面存储不同的字符串,调用sortmax方法,使用默认的比较器输出List集合中字符串结果,然后自定义一个比较器,比较字符串长度,在调用sortmax方法传入自定义比较器,输出结果。


import java.util.*;
public class CollectionsDemo1
{
    public static void main(String[] args) {
        ArrayList<String> al = new ArrayList<>();
        al.add("sda");
        al.add("ss");
        al.add("dd");
        al.add("klsfj");
        System.out.println(al);
        //字符串是具有比较性的,所以sort方法采用的是字符串自然排序
        Collections.sort(al);
        //打印字符串的自然顺序的排序结果
        System.out.println(al);
        System.out.println(Collections.max(al)); //返回自然派序的最后一个
        //使用自定义比较器,对List集合进行排序,该比较器比较的是字符串长度。
        Collections.sort(al,new myComp());
        System.out.println(al);
        
        System.out.println(Collections.max(al,new myComp()));//返回最大长度
    }
}
//定义比较字符串长度的比较器
class myComp 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);
    }
}


 3binarySearch()的两个方法:

二分查找的前提是集合的元素必须要有序。

public static <T> int binarySearch(List<? extends Comparable<? super T>> list,

                                                                        T key)

该方法是按照默认的比较器,也就是自然顺序对List集合中的元素进行二分查找。比如字符串,会按照字典顺序查找所需要的元素的角标。

 

public static <T> int binarySearch(List<? extends T> list,

                                   T key,

                                   Comparator<? super T> c)

该方法按照自定义的比较器对集合的元素进行查找。

没有比较器的二分查找的原理代码:


public static <T> int myBinarySearch(List<? extends Comparable<? super T>> list,T key) {
    int min = 0;
    int max = list.size() - 1;
    int mid = 0;
    while(min<max) {
        mid = (min + max)>>1;
        String str = list.get(mid);
        int num = str.compareTo(key); 
        if(num>0)
            max = mid -1;
        else if(num<0)
            min = mid +1;
        else
            return mid;
    }
    return -num-1;//这是Collections集合的默认原理,当找不到元素所在位置时,将该元素应该所在的位置-1
}

有自定义比较器的二分查找原理:

public static <T> int myBinarySearch(List<? extnds Comparable<? super T>> list,T key,Comparator<? super T> c) {
    int min = 0 ;
    int max = list.size()-1;
    int mid = 0;
    while(min < max) {
        mid = (min + max)>>1;
        String str = list.get(mid);
        int num = c.compare(str,key);
        if(num>0)
            max = mid - 1;
        else if(num<0)
            min = mid + 1;
        else
            return mid;
    }
    return -min-1;
}

需求:同样是对 List 集合的 String 类型的字符串元素进行操作,按照字符串长度,使用 binarySearch() ,进行二分查找。


import java.util.*;
public class CollectionsDemo2
{
    public static void main(String[] args) {
        ArrayList<String> al = new ArrayList<>();
        al.add("sda");
        al.add("ss");
        al.add("dd");
        al.add("klsfj");
        //首先集合里面的的元素必须是有顺序的
        Collections.sort(al,new myComp());
        System.out.println(al);
        //使用自定义比较器,按照字符串长度查找
        int n = Collections.binarySearch(al,"sss",new myComp());
        //如果二分查找没有索要查找元素,则返回的是:-(该插入位置)-1
        System.out.println(n);
    }
}
//自定义比较器,按照字符串长度比较
class myComp 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);
    }
}

4public static <T> void fill(List<? super T> list,T obj)

使用指定元素替换指定列表中的所有元素。

 

public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal)

List集合中的旧值替换成成指定的新值。

 

public static void reverse(List<?> list)

将集合中的元素顺序反转。


import java.util.*;
public class CollectionTest
{
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("na");
        list.add("bbb");
        list.add("sdg");
        list.add("dg");
        System.out.println(list);
        //将List集合中的所有元素替换成yyy
        //Collections.fill(list,"yyy");
        //System.out.println(list);
        //替换List集合中的一部分元素,替换角标为1——2的元素为yyy
        tihuan(list,1,3);
        
        //反转替换后的集合元素顺序
        Collections.reverse(list);
        System.out.println(list);
    }
//替换过程代码
    public static void tihuan(List<String> list,int s,int e) {
        for(int i=s;i<e;i++) {
            list.remove(i);
            list.add(i,"yyy");
        }
        System.out.println(list);
    }
}

二,CollectionsreverseOrder()方法:

reverseOrder方法是Collections集合工具类的一个重要方法,所以单独拿出来总结。

 

public static <T> Comparator<T> reverseOrder()

public static <T> Comparator<T> reverseOrder(Comparator<T> cmp)

 

该方法返回一个Comparator比较器,但是该比较器是默认比较器的逆向比较方法。

比如说字符串的默认比较方式是自然顺序,该顺序是通过实现Comparable接口,重写它的compareTo方法,来按照自然顺序比较字符串。当我们将字符串作为元素存储到List集合中时,通过Collections类的sort()方法对字符串排序,那么结果将会是自然顺序排序后的字符串,如果我们将Collections.reverseOrder()作为一个参数传递给sort方法,那么结果将和自然顺序相反。该方法是可以应用到TreeSet集合的,因为TreeSet集合允许接收一个比较器。

请看谢列需求:

需求:将不同长度的字符串作为元素传递给TreeSet集合,按照字符串的长短输出结果,反别输出字符串从长到短和从短到长的两种不同的结果。

 

按照以前的思维我们通常是定义两个比较器,按别通过返回不同的值,来确定字符串的长短,但是学习了CollectionsreverseOrder()方法后,我们可以直接返回一个与原比较器相反的比较器来进行操作。


import java.util.*;
public class CollectionsDemo3
{
    public static void main(String[] args) {
    /*  ArrayList<> list = new ArrayList<>();
        list.add("shgsj");
        list.add("asg");
        list.add("dsh");
        System.out.println("原List集合:" + list);
        Collections.sort(list);
        System.out.println("自然排序的结果:" + list);
        Collections.sort(list,Collections.reverseOrder());
        System.out.println("自然顺序的逆序:" + list);
    */
        
        //创建一个TreeSet集合,将自定义比较器的反向比较器传递给Set集合
        TreeSet<String> ts = new TreeSet<>(Collections.reverseOrder(new myC()));
        //TreeSet<String> ts = new TreeSet<>(Collections.reverseOrder());
        ts.add("fssssgdsf");
        ts.add("sfsf");
        ts.add("sgrrf");
        ts.add("sdf");
        sop(ts);
        iter(ts);  //按照长度然后进行逆序排序;
    }
    
    //对集合中的元素进行迭代输出
    public static void iter(TreeSet<String> ts) {
        Iterator<String> it = ts.iterator();
        while (it.hasNext())
        {
            sop(it.next());
        }
    } 
    public static void sop(Object obj) {
        System.out.println(obj);
    }
}
//定义一个比较器,按照字符串长度比较
class myC 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);
    }
}

三,之前我们说过Collection中的ArrayList集合几乎替代了VectorArrayListVector集合的用法是一模一样的,虽然Vector集合比ArrayList集合多了线程同步功能,但是因为它的效率低所以即使在多线程中,我们依然还是用ArrayList,然后自己加锁,其实集合框架工具类已经为我们提供了给List集合加锁的方法,我们只需要给该方法传入一个线程不同步的集合,他就能返回给我们一个线程同步的集合。

这些方法是:

public static <T> Collection<T> synchronizedCollection(Collection<T> c)

public static <T> List<T> synchronizedList(List<T> list)

public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)

public static <T> Set<T> synchronizedSet(Set<T> s)

public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)

public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s)

 

 

四,数组工具类Arrays:

Arrays类和集合框架工具类Collections一样,提供了很多直接操作数组的静态法方发,很多静态方法我们之前已经使用过。

数组和List集合之间是可以相互转换的,转换方法就是Arrays提供的asList()静态方法。

但是将数组转换成集合要注意一下几个问题:

1,数组转换成集合后,不可以对该集合进行增删操作,因为数组的长度是固定不变的,但是可以进行查询操作,包括containsindexOfgetsubList等操作;

2 ,如果数组是基本类型的数组,那么转换成集合后,集合的元素不是数组中的所有元素,而是这个数组对象。如果我们打印基本数据类型数组转换成集合后的结果,将看到的是一个地址值,也就是说转换后的集合只有一个元素。下面我们将通过一个程序进行验证。


import java.util.*;
public class ArraysDemo
{
    public static void main(String[] args) {
        //返回chs数组的字符串表示形式。没学该方法之前我们只能使用StringBuild进行这样的操作。
        /*char[] chs = {'a','d','g','r'};
        String s = Arrays.toString(chs);//静态方法引用一定不能忘了类
        sop(s);//输出:[a,d,g,r]
        */
        int[] i = {1,3,6,2,1};//如果将基本数据类型数组转换成集合那么,集合中的元素将是这个数组,而不是数组的元素
        List<int[]> list = Arrays.asList(i);
        sop(list);//打印结果是:[[I@10be6858]
        Integer[] li = {1,2,4,6,7};  //引用了数据类型的拆箱和装箱,数组中存储的元素是对象
        List<Integer> list2 = Arrays.asList(li);
        sop(list2);
        //list2.add(new Integer(6));//会抛出UnsupportedOperationException。
        sop(list2.contains("6"));
    }
    public static void sop(Object obj) {
        System.out.println(obj);
    }
}

3,既然数组可以转换成集合,那么集合也一定可以转换成数组,集合转换成数组是使用Collection集合框架中的toArray()方法。

这个方法有两种形式:

Object[] toArray()

<T> T[] toArray(T[] a)

前一个是返回Object类型的数组,后一个是返回泛型类型的数组。

 

(1)为什么要将集合变成数组呢?为了限制对集合中元素的操作,不需要进行增删操作了,可以将集合变成数组,别的用户就不能进行增删操作了。

    当将集合转成数组的时候,如果指定的数组的长度小于等于集合的size,则会生成集合size大小的数组,当指定数组的长度大于集合的size的时候,会生成指定大小的数组,这个大小比集合的size大多少,就对应生成多少个null值放入数组的空位;所以,指定数组的大小最好是集合的size的大小;


import java.util.*;
public class CollectionArrays
{
    public static void main(String[] args) {
        ArrayList<String> al = new ArrayList<>();
        al.add("dzsfg04");
        al.add("dzsfg01");
        al.add("dzsfg02");
        al.add("dzsfg03");
        //String[] st = al.toArray(new String[0]);
        String[] st = al.toArray(new String[al.size()]);
        System.out.println(Arrays.toString(st)); 
    }
    public static void sop(Object obj) {
        System.out.println(obj);
    }
}

五,总结jdk1.5的几个新特性;

我们知道jdk1.5可以说是java发展的一个重大转折点,因为在这个版本增加了很多革命性的功能,所以这是很重要的一个知识点。面试可能会被问到。

1,泛型

2,增强for循环

3,可变参数

4,静态导入

5,自动装箱和拆箱

6,枚举

7,元数据

 

泛型我们已经学习过,增强for循环也已经在java基础知识里面总结过,在这里在比较一下增强for循环和普通for有什么区别:高级for必须要有被遍历的目标;比如打印100hello world,高级for不能完成,传统for却可以。所以建议对数组进行遍历的时候采用传统的for循环,但是集合框架的遍历,高级for也可以使用。

增强的for循环:

语法:

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

{

}

重点要掌握增强for循环对List集合和对Map集合的操作:


import java.util.*;
public class EnhanceFor
{
    public static void main(String[] args) {
        ArrayList<String> al = new ArrayList<>();
        al.add("sdfg");
        al.add("sdfdf");
        al.add("sdaafa");
        
        //使用迭代器迭代List集合
        Iterator<String> it = al.iterator();
        while (it.hasNext())
        {
            System.out.println(it.next());
        }
        //使用增强for循环迭代List集合
        for (String s: al )
        {
            System.out.println(s);
        } 
        //增强for循环对Map集合的迭代
        TreeMap<Integer,String> tm = new TreeMap<>();
        tm.put(1,"fasd");
        tm.put(2,"hasd");
        tm.put(3,"kasd");
        //方法一:keySet()
        Set<Integer> st = tm.keySet();
        for (Integer num: st)
        {
            System.out.println(num + "----" + tm.get(num));
        }
        //方法二:entrySet()
        Set<Map.Entry<Integer,String>> en = tm.entrySet();
        for(Map.Entry<Integer,String> me: en)
        {
            System.out.println(me.getKey() + "======" + me.getValue());
        }
    }
}

可变参数:在Arrays数组工具类中的asList(T... args)方法上,可以就看到它的参数就是一个可变参数的。可变参数其实就是数组的简写形式,不用每一次都手动的建立数组对象,只要将要操作的元素作为参数传递即可。其实底层是JVM将这些参数封装到了一个数组中。
 

使用可变参数的时候要注意,可变参数一定要定义在最后面。


public class Kebiancanshu
{
    public static void main(String[] args) {
        show("sagj",3,5);
        show("ds",1,3,5);
        show("sda");//可变参数为空,长度为0
    public static void show(int i,int j) {
        System.out.println(i+j);
    }
    public static void show(int i,int j,int k) {
        System.out.println(i+k+j);
    }
    public static void show(String s,int... i) {
        System.out.println(i.length);
    }
}

静态导入:导入的是所用静态类或对象中的静态成员。

特别注意:(1)当类名重名时,需要导入具体的包名;(2)当方法名重名是指定具体的类或者对象。

 

静态导入示例:


import static java.util.Arrays.*;//导入了java.util.Arrays的所有静态成员;
public class StaticImportDemo
{
    public static void main(String[] args) {
        String[] arr = {"sg","sadg","stga"};
        //Arrays.sort(arr);
        //可以省略Arrays
        sort(arr);
        System.out.println(Arrays.toString(arr));//为什么这个Arrays不可以删呢?
        //那是因为StaticImportDemo类是Object的子类,Object超类有自己的toString()
        //如果不加Arrays,它会认为引用的是超类的toString方法,会抛异常。
    }
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值