反射机制

  • 概述
  • 应用
  • 参考

 

概述

“传统的” RTTI 机制在编译时就已经知道了所有类的类型;“反射”机制允许在运行时发现和使用类的信息。依靠反射机制,可以动态的创建一个类的对象和调用对象的方法。

反射的优点是增加灵活性,可以在运行时动态获取对象实例。缺点是反射的效率很低,而且会破坏封装,通过反射可以访问类的私有方法,不安全。

反射是无孔不入的,无论是私有方法还是私有内部类的方法,哪怕是匿名类的方法,也无法逃脱反射的调用。对于私有域来说也一样,只有 final 域,才不会被修改。反射可以说是给我们的程序留了一道后门,但是总的来说,从反射给我们带来的优劣对比上看,利大于弊。

Class 类和 java.lang.reflect 类库共同构成了对反射的支持,该类库主要包含了 Field, Method 以及 Constructor 类。

与Java反射相关的类如下:

类名用途
Class类代表类的实体,在运行的Java应用程序中表示类和接口
Field类代表类的成员变量(成员变量也称为类的属性)
Method类代表类的方法
Constructor类代表类的构造方法

Class 方法中有大量的方法可供调用,包括 getName()(获取类的完整路径名字)、newInstance()(创建类的实例)、getFields()(获取所有公有的属性对象)、getDeclaredMethods()(获取该类所有方法)等;

Field 类代表类的成员变量,包括 get(Object obj) (获得 obj 中对应的属性值)、set(Object obj, Object value) (设置 obj 中对应属性)等方法。

Method代表类的方法,invoke(Object obj, Object… args) (传递 object 对象及参数调用该对象对应的方法)方法。

Constructor代表类的构造方法,其中 newInstance(Object… initargs) 函数用于根据传递的参数创建类的对象。

 

应用


测试不同排序方法的时间消耗,如下所示:

package Algorithm.Sort;

import java.lang.reflect.Method;
import java.util.*;

public class TimeCostForSortTest {

    // 待排序数组长度
    private static final int N = 100000;

    // 生成随机数的最大值
    private static final int randValue = 10000;

    // 排序方法个数
    private static final int numOfSortAl = 7;

    // 各种排序的方法名
    public static final String[] sort = {"selectSort", "bubbleSort", "insertSort", "shellSort",
            "mergeSort", "quickSort", "heapSort"};

    // main 函数
    public static void main(String[] args) {
        TimeCostForSortTest t = new TimeCostForSortTest();
        // 生成待排序数组
        List<int[]> list = t.initialArrayList();
        for (int i = 0; i < numOfSortAl; i++) {
            String al = sort[i];
            int[] nums = list.get(i);
            long startTime = System.currentTimeMillis();
            try {
                // 调用某个排序方法
                t.callForSortByName(al, nums);
            } catch (Exception e) {
                e.printStackTrace();
            }
            long endTime = System.currentTimeMillis();
            // 打印出排序所用的时间
            System.out.println(al + ": " + (endTime - startTime) + "ms");
        }
    }

    /**
     * 调用指定的方法
     * @param al 方法名
     * @param nums 参数
     * @throws Exception 异常
     */
    public void callForSortByName(String al, int[] nums) throws Exception {
        if (al == null || al.length() == 0)
            throw new NumberFormatException();
        // 使用装载当前类的类装载器来装载指定的类
        Class<?> alClass = Class.forName("Algorithm.Sort.TimeCostForSortTest");
        // 获得指定的对象中的方法
        Method method = alClass.getMethod(al, int[].class);
        // 调用 this 对象的 method 方法
        method.invoke(this, new Object[]{nums});
    }



    /**
     * 生成待排序数组,数字随机
     * 列表中每一个待排序数组完全相同
     * @return 生成的数组列表
     */
    private List<int[]> initialArrayList() {
        int[] nums = new int[N];
        Random rand = new Random();
        for (int j = 0; j < N; j++)
            nums[j] = rand.nextInt(randValue) + 1;
        List<int[]> list = new ArrayList<>();
        list.add(nums);
        for (int i = 1; i < numOfSortAl; i++) {
            list.add(Arrays.copyOf(nums, nums.length));
        }
        return list;
    }

    /**
     * 选择排序
     * @param nums 待排序数组
     */
    public void selectSort(int[] nums) {
        int n = nums.length;
        for (int i = 0; i < n - 1; i++) {
            int index = i;
            for (int j = index; j < n; j++) {
                if (nums[j] < nums[index])
                    index = j;
            }
            swap(nums, i, index);
        }
    }

    /**
     * 冒泡排序
     * @param nums 待排序数组
     */
    public void bubbleSort(int[] nums) {
        int n = nums.length;
        for (int i = n; i > 0; i--) {
            for (int j = 0; j + 1 < i; j++) {
                if (nums[j] > nums[j + 1])
                    swap(nums, j, j + 1);
            }
        }
    }

    /**
     * 插入排序
     * @param nums 待排序数组
     */
    public void insertSort(int[] nums) {
        int n = nums.length;
        for (int i = 1; i < n; i++) {
            for (int j = i; j > 0 && nums[j - 1] > nums[j]; j--) {
                swap(nums, j - 1, j);
            }
        }
    }

    /**
     * shell 排序
     * @param nums 待排序数组
     */
    public void shellSort(int[] nums) {
        if (nums == null || nums.length <= 1) {
            return;
        }
        int incrementNum = nums.length / 2;
        while (incrementNum >= 1) {
            for (int i = 0; i < incrementNum; i++) {
                //冒泡排序
                for (int j = i; j < nums.length - incrementNum; j = j + incrementNum) {
                    if (nums[j] > nums[j + incrementNum]) {
                        int temple = nums[j];
                        nums[j] = nums[j + incrementNum];
                        nums[j + incrementNum] = temple;
                    }
                }
            }
            incrementNum = incrementNum / 2;
        }
    }

    /**
     * 归并排序
     * @param nums 待排序数组
     */
    public void mergeSort(int[] nums) {
        if (nums == null || nums.length == 0)
            return;
        helper = new int[nums.length];
        mergeSortHelp(nums, 0, nums.length - 1);
    }

    /**
     * 快速排序
     * @param nums 待排序数组
     */
    public void quickSort(int[] nums) {
        if (nums == null || nums.length == 0)
            return;
        quickSortHelp(nums, 0, nums.length - 1);
    }

    /**
     * 堆排序
     * @param nums 待排序数组
     */
    public void heapSort(int[] nums) {
        if (nums == null)
            return;
        for (int i = nums.length / 2 - 1; i > 0; i--)
            adjustHeap(nums, i, nums.length);
        for (int i = nums.length - 1; i > 0; i--) {
            swap(nums, 0, i);
            adjustHeap(nums, 0, i);
        }
    }

    private void swap(int[] nums, int x, int y) {
        int tmp = nums[x];
        nums[x] = nums[y];
        nums[y] = tmp;
    }

    private int[] helper;

    private void mergeSortHelp(int[] nums, int l, int r) {
        if (l < r) {
            int mid = (l + r) / 2;
            mergeSortHelp(nums, l, mid);
            mergeSortHelp(nums, mid + 1, r);
            merge(nums, l, mid, r);
        }
    }

    private void merge(int[] nums, int l, int mid, int r) {
        for (int i = l; i <= r; i++)
            helper[i] = nums[i];
        int p1 = mid;
        int p2 = r;
        int index = r;
        while (p1 >= l && p2 >= mid + 1) {
            if (helper[p1] > helper[p2])
                nums[index--] = helper[p1--];
            else
                nums[index--] = helper[p2--];
        }
        while (p1 >= l)
            nums[index--] = helper[p1--];
        while (p2 >= mid + 1)
            nums[index--] = helper[p2--];
    }

    private void quickSortHelp(int[] nums, int l, int r) {
        if (l < r) {
            int index = partition(nums, l, r);
            quickSortHelp(nums, l, index - 1);
            quickSortHelp(nums, index + 1, r);
        }
    }

    private int partition(int[] nums, int l, int r) {
        int pivot = r;
        while (l < r) {
            while (l < r && nums[l] < nums[pivot]) l++;
            while (l < r && nums[r] >= nums[pivot]) r--;
            swap(nums, l, r);
        }
        swap(nums, l, pivot);
        return l;
    }

    private void adjustHeap(int[] nums, int i, int length) {
        int temp = nums[i];
        for (int k = 2 * i + 1; k < length; k = 2 * k + 1) {
            if (k + 1 < length && nums[k] < nums[k + 1])
                k = k + 1;
            if (temp < nums[k]) {
                nums[i] = nums[k];
                i = k;
            } else
                break;
        }
        nums[i] = temp;
    }
}

用到反射的地方是 callForSortByName 方法中,根据方法名(字符串)调用具体的方法这一部分。

测试结果显示程序正常运行。希尔排序、归并排序、快速排序、堆排序效果较好。

反射在 RPC(远程过程调用)中有广泛的应用。当客户端调用的时候通过动态代理向服务提供方发送调用的信息,服务提供方收到后根据客户端需要调用的方法,调用本地方法,拿到结果组装返回。

 

参考


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值