1反射机制是什么
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

2反射机制能做什么
反射机制主要提供了以下功能: 
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
生成动态代理。


3反射机制的相关API
通过一个对象获得完整的包名和类名
实例化一个类对象(使用构造函数,默认的和带参数的)
返回一个类实现的接口
取得一个类的父类
获得一个类的全部构造函数
可以通过反射调用一个类的方法
调用一个类的set和get方法
通过反射操作属性
通过反射取得并修改数组的信息
通过反射修改数组大小


就看看下面的各式各样的例子,来一步一步的看看反射都能干些什么,都能干嘛,比空谈理论强多了。

例子虽然海了去了,但是耐心看一半,估计你就赢啦。


【案例1】通过一个对象获得完整的包名和类名

package Reflect;

/**
 * 通过一个对象获得完整的包名和类名
 */
class Demo {
    //other codes...
}

class hello {
    public static void main(String[] args) {
        Demo demo = new Demo();
        System.out.println(demo.getClass().getName());
    }
}

【运行结果】:Reflect.Demo

【案例2】实例化Class类对象

package Reflect;

class Demo {
    //other codes...
}

class hello {
    public static void main(String[] args) {
        Class<?> demo1 = null;
        Class<?> demo2 = null;
        Class<?> demo3 = null;
        try {
            //一般尽量采用这种形式
            demo1 = Class.forName("Reflect.Demo");
        } catch (Exception e) {
            e.printStackTrace();
        }
        demo2 = new Demo().getClass();
        demo3 = Demo.class;
        System.out.println("类名称   " + demo1.getName());
        System.out.println("类名称   " + demo2.getName());
        System.out.println("类名称   " + demo3.getName());
    }
}

【运行结果】:


类名称   Reflect.Demo


类名称   Reflect.Demo


类名称   Reflect.Demo


【案例3】通过Class实例化其他类的对象
通过无参构造实例化对象

package Reflect;

class Person {
    private String name;
    private int age;

    //getters and setters
    @Override
    public String toString() {
        return "[" + this.name + "  " + this.age + "]";
    }
}

class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        Person per = null;
        try {
            per = (Person) demo.newInstance();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        per.setName("Rollen");
        per.setAge(20);
        System.out.println(per);
    }
}

【运行结果】:


[Rollen  20]


但是注意一下,当我们把Person中的默认的无参构造函数取消的时候,比如自己定义只定义一个有参数的构造函数之后,会出现错误:


比如我定义了一个构造函数:


public Person(String name, int age) {
        this.age = age;
        this.name = name;
    }

然后继续运行上面的程序,会出现:


java.lang.InstantiationException: Reflect.Person

    at java.lang.Class.newInstance0(Class.java:340)

    at java.lang.Class.newInstance(Class.java:308)

    at Reflect.hello.main(hello.java:39)

Exception in thread "main" java.lang.NullPointerException

    at Reflect.hello.main(hello.java:47)

所以大家以后再编写使用Class实例化其他类的对象的时候,一定要自己定义无参的构造函数


比如我的这个bug也是因为这个默认构造函数的问题,实例化对象就出错了。

【案例4】通过Class调用其他类中的构造函数 (也可以通过这种方式通过Class创建其他类的对象)

package Reflect;

import java.lang.reflect.Constructor;

class Person {
    private String name;
    private int age;

    public Person() {
    }

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

    public Person(int age) {
        this.age = age;
    }

    public Person(String name, int age) {
        this.age = age;
        this.name = name;
    }

    //getters and setters
    @Override
    public String toString() {
        return "[" + this.name + "  " + this.age + "]";
    }
}

class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        Person per1 = null;
        Person per2 = null;
        Person per3 = null;
        Person per4 = null;
        //取得全部的构造函数
        Constructor<?> cons[] = demo.getConstructors();
        try {
            per1 = (Person) cons[0].newInstance();
            per2 = (Person) cons[1].newInstance("Rollen");
            per3 = (Person) cons[2].newInstance(20);
            per4 = (Person) cons[3].newInstance("Rollen", 20);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(per1);
        System.out.println(per2);
        System.out.println(per3);
        System.out.println(per4);
    }
}

【运行结果】:


[null  0]


[Rollen  0]


[null  20]


[Rollen  20]


【案例5】返回一个类实现的接口:

package Reflect;

interface China {
    //public static final String name = "Rollen";
    //接口中声明前面的类型等修饰符都是多余的
    String name = "Rollen";
    int age = 20;
    void sayChina();
    void sayHello(String name, int age);
}

class Person implements China {
    private String sex;

    public Person() {
    }
    public Person(String sex) {
        this.sex = sex;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    @Override
    public void sayChina() {
        System.out.println("hello ,china");
    }
    @Override
    public void sayHello(String name, int age) {
        System.out.println(name + "  " + age);
    }
}

class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        //保存所有的接口
        Class<?> intes[] = demo.getInterfaces();
        for (int i = 0; i < intes.length; i++) {
            System.out.println("实现的接口   " + intes[i].getName());
        }
    }
}

【运行结果】:


实现的接口   Reflect.China

(注意,以下几个例子,都会用到这个例子的Person类,所以为节省篇幅,此处不再粘贴Person的代码部分,只粘贴主类hello的代码)


【案例6】:取得其他类中的父类

class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        //取得父类
        Class<?> temp = demo.getSuperclass();
        System.out.println("继承的父类为:   " + temp.getName());
    }
}

【运行结果】


继承的父类为:   java.lang.Object



【案例7】:获得其他类中的全部构造函数
这个例子需要在程序开头添加import java.lang.reflect.*;
然后将主类编写为:

import java.lang.reflect.Constructor;

class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        Constructor<?> cons[] = demo.getConstructors();
        for (int i = 0; i < cons.length; i++) {
            System.out.println("构造方法:  " + cons[i]);
        }
    }
}

【运行结果】:


构造方法:  public Reflect.Person()


构造方法:  public Reflect.Person(java.lang.String)



【案例8】接下来让我们取得其他类的全部属性吧,最后我讲这些整理在一起,也就是通过class取得一个类的全部框架

import java.lang.reflect.Modifier;

class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("===============本类属性========================");
        // 取得本类的全部属性
        Field[] field = demo.getDeclaredFields();
        for (int i = 0; i < field.length; i++) {
            // 权限修饰符
            int mo = field[i].getModifiers();
            String priv = Modifier.toString(mo);
            // 属性类型
            Class<?> type = field[i].getType();
            System.out.println(priv + " " + type.getName() + " "
                    + field[i].getName() + ";");
        }
        System.out.println("===============实现的接口或者父类的属性========================");
        // 取得实现的接口或者父类的属性
        Field[] filed1 = demo.getFields();
        for (int j = 0; j < filed1.length; j++) {
            // 权限修饰符
            int mo = filed1[j].getModifiers();
            String priv = Modifier.toString(mo);
            // 属性类型
            Class<?> type = filed1[j].getType();
            System.out.println(priv + " " + type.getName() + " "
                    + filed1[j].getName() + ";");
        }
    }
}

【运行结果】:


===============本类属性========================


private java.lang.String sex;


===============实现的接口或者父类的属性========================


public static final java.lang.String name;


public static final int age;



【案例9】其实还可以通过反射调用其他类中的方法:

import java.lang.reflect.Method;

class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            //调用Person类中的sayChina方法
            Method method = demo.getMethod("sayChina");
            method.invoke(demo.newInstance());
            //调用Person的sayHello方法
            method = demo.getMethod("sayHello", String.class, int.class);
            method.invoke(demo.newInstance(), "Rollen", 20);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

【运行结果】:


hello ,china


Rollen  20



【案例10】调用其他类的set和get方法

import java.lang.reflect.Method;

class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        Object obj = null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            obj = demo.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        setter(obj, "Sex", "男", String.class);
        getter(obj, "Sex");
    }

    /**
     * @param obj 操作的对象
     * @param att 操作的属性
     */
    public static void getter(Object obj, String att) {
        try {
            Method method = obj.getClass().getMethod("get" + att);
            System.out.println(method.invoke(obj));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @param obj   操作的对象
     * @param att   操作的属性
     * @param value 设置的值
     * @param type  参数的属性
     */
    public static void setter(Object obj, String att, Object value, Class<?> type) {
        try {
            Method method = obj.getClass().getMethod("set" + att, type);
            method.invoke(obj, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}// end class

【运行结果】:





【案例11】通过反射操作属性

import java.lang.reflect.Field;

class hello {
    public static void main(String[] args) throws Exception {
        Class<?> demo = null;
        Object obj = null;

        demo = Class.forName("Reflect.Person");
        obj = demo.newInstance();

        Field field = demo.getDeclaredField("sex");
        field.setAccessible(true);
        field.set(obj, "男");
        System.out.println(field.get(obj));
    }
}// end class



【案例12】通过反射取得并修改数组的信息:


import java.lang.reflect.*;

class hello {
    public static void main(String[] args) {
        int[] temp = {1, 2, 3, 4, 5};
        Class<?> demo = temp.getClass().getComponentType();
        System.out.println("数组类型: " + demo.getName());
        System.out.println("数组长度  " + Array.getLength(temp));
        System.out.println("数组的第一个元素: " + Array.get(temp, 0));
        Array.set(temp, 0, 100);
        System.out.println("修改之后数组第一个元素为: " + Array.get(temp, 0));
    }
}

【运行结果】:


数组类型: int


数组长度  5


数组的第一个元素: 1


修改之后数组第一个元素为: 100



【案例13】通过反射修改数组大小

import java.lang.reflect.Array;

class hello {
    public static void main(String[] args) {
        int[] temp = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        int[] newTemp = (int[]) arrayInc(temp, 15);
        print(newTemp);
        System.out.println("=====================");
        String[] atr = {"a", "b", "c"};
        String[] str1 = (String[]) arrayInc(atr, 8);
        print(str1);
    }

    /**
     * 修改数组大小
     */
    public static Object arrayInc(Object obj, int len) {
        Class<?> arr = obj.getClass().getComponentType();
        Object newArr = Array.newInstance(arr, len);
        int co = Array.getLength(obj);
        System.arraycopy(obj, 0, newArr, 0, co);
        return newArr;
    }

    /**
     * 打印
     */
    public static void print(Object obj) {
        Class<?> c = obj.getClass();
        if (!c.isArray()) {
            return;
        }
        System.out.println("数组长度为: " + Array.getLength(obj));
        for (int i = 0; i < Array.getLength(obj); i++) {
            System.out.print(Array.get(obj, i) + " ");
        }
    }
}

【运行结果】:


数组长度为: 15


1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================


数组长度为: 8


a b c null null null null null