剖析Arrays

欢迎浏览我的博客 获取更多精彩文章

https://boyn.top

剖析Arrays

  • Arrays类常用函数
  • Arrays类部分方法的设计

Arrays类常用函数

在数组的操作中,Arrays作为一个工具类,是十分好用的,我们就先来看一下,Arrays有哪些经常会用到的方法

toString(*)

这个toString方法和我们平常用的obj.toString()有一些不同,它是带参数的,一般的toString方法是对象所属类的方法,但是数组不是一个类,所以要将其转成字符串,就要使用Arrays.toString, 这个方法有9个重载类型,包括8个基本类型和一个对象类型,下面列举一个int数组和一个对象数组

public static void IntArrayToString(){
        int[] array = {1, 2, 3, 4};
        System.out.println(Arrays.toString(array));
    }
//Output: [1, 2, 3, 4]
public static void ObjArrayToString(){
        Object[] array = new Object[3];
        array[0] = new Dish("Fish");
        array[1] = new Dish("Meat");
        array[2] = new Dish("Vegetable");
        System.out.println(Arrays.toString(array));
    //Output: [Dish{name='Fish'}, Dish{name='Meat'}, Dish{name='Vegetable'}]
    }

    private static class Dish{
        private final String name;

        public Dish(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Dish{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }

如果不是调用的toString方法,而是直接将他们输出的话,就会打印他们的类型和内存地址

[I@74a14482 //int数组
[Ljava.lang.Object;@1540e19d //对象数组

排序

Arrays实现了除了布尔类型之外,其他类型(包括对象类型)的排序方法,其中,对象类型的排序需要对象类实现Comparable接口.并且,这个排序方法是原地排序,直接对数组进行操作而不是返回一个新的数组

对int数组进行排序->

public static void IntArraySort(){
        int[] array = {5, 2, 7, 4};
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));
        //Output: [2, 4, 5, 7]
    }

因为sort方法有对int类型的重载版本,所以直接使用就可以了

对String数组进行排序->

public static void StringArraySort(){
        String[] array = {"hello","i","am","boyn"};
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));
        //Output: [am, boyn, hello, i]
    }

对于String类型来说,它已经实现了Comparable接口,所以也可以直接调用

对对象数组进行排序->

如果我们的对象没有实现Comparable接口,但是又想对其进行排序,那我们可以传入一个Comparator,比较器对象来进行比较

public static void ObjectArraySort(){
        Dish[] array = new Dish[3];
        array[1] = new Dish("Meat");
        array[2] = new Dish("Vegetable");
        array[0] = new Dish("Fish");
        Arrays.sort(array, new Comparator<Dish>() {
            @Override
            public int compare(Dish o1, Dish o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });
        //Output: [Dish{name='Fish'}, Dish{name='Meat'}, Dish{name='Vegetable'}]
        System.out.println(Arrays.toString(array));
    }

当然了,如果熟悉lambda编程的小伙伴,就知道Comparator有一组静态方法叫做comparing,这是一个工厂方法,传入该对象的某个可比较的域,就可以直接返回一个根据这个域来比较的比较器对象,所以我们还可以这样写

public static void ObjectArraySort(){
        Dish[] array = new Dish[3];
        array[1] = new Dish("Meat");
        array[2] = new Dish("Vegetable");
        array[0] = new Dish("Fish");
        Arrays.sort(array,Comparator.comparing(Dish::getName));
        //Output: [Dish{name='Fish'}, Dish{name='Meat'}, Dish{name='Vegetable'}]
        System.out.println(Arrays.toString(array));
    }

这样看起来,就简单得多了

查找

在Arrays中,一般来说,查找和排序是对应的,所用的是二分查找法,binarySearch(),需要注意的是,这个方法只能够用于已排序的数组,它会返回该元素在数组中的索引,值得一提的是,如果没有找到该元素,那么就会返回一个负数,这个负数等于-(插入点+1),插入点的意思是,如果我们在这个插入点插入这个没有找到的元素,可以保持这个数组有序

那么我们来看一下用法吧

int数组中的查找

public static void IntArraySearch(){
        int[] array = {5, 2, 7, 4};
        Arrays.sort(array);
        System.out.println(Arrays.binarySearch(array,2));
        //Output: 0
    }

String数组中的查找

public static void StringArraySearch(){
        String[] array = {"hello","i","am","boyn"};
        Arrays.sort(array);
        System.out.println(Arrays.binarySearch(array,"i"));
        //Output: 3
    }

Object数组中的查找

public static void ObjectArraySearch(){
        Dish[] array = new Dish[3];
        array[1] = new Dish("Meat");
        array[2] = new Dish("Vegetable");
        array[0] = new Dish("Fish");
        Arrays.sort(array,Comparator.comparing(Dish::getName));
        System.out.println(Arrays.binarySearch(array,new Dish("Meat"),Comparator.comparing(Dish::getName)));
        //Output: 1
    }

部分函数实现原理

查找函数

在上面,我们说到了要调用查找,就要保持数组是有序的,那么为什么呢

因为在Arrays类中,所用的查找是二分查找法,他能够高效(O(log2n))地对有序元素进行查找

有关二分查找的详细知识,可以查看下面这篇wiki

二分查找法(英文)

排序函数的设计模式

在我们使用排序函数sort时,他为我们重载了多个版本 ,其中有一个版本的签名是这样的

public static <T> void sort(T[] a, Comparator<? super T> c)

这体现了一种将不变与变化相分离的思维,不变的是排序的步骤,即比较,交换的重复,但是其中,比较这个步骤是可以有不同的,可以根据我们传入不同的比较器,从而有不同的比较方法,这是一种常见的设计模式,成为策略模式,不同的比较方法就是不同的策略

排序函数的实现

对于基本类型的数组,从Java7开始,排序函数就成为了双枢轴快速排序,是一种对快速排序的优化

对于对象类型,Java采用了TimSort,是一种基于插入排序和归并排序的优化

More

在Arrays里面,封装了非常多常用的函数,但是仍然有一些操作是没有覆盖到的,这时候我们可以选用一些比较常用的开源库,如Apache基金会中的commons项目中的 commons.lang3.ArrayUtils,里面有更多的数组操作,如各种检查性的操作,判断非空,有序等等,更多可以参阅其官方文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值