Java反射学习笔记

Java的反射机制,允许程序在运行时获取类的任何信息:包括类名、父类、实现的接口、参数列表、构造函数列表、方法列表以及属性和方法的修饰符等等。Java的反射机制使用过一组Java类实现的,包括:Class, Method, Constructor以及Modifier等。

下面的一个例子展示了Java反射机制的基本概念和用法(仅仅是学习笔记)。参考文献部分列出了比较好的博客,请自行参阅。

package reflection.data;

import java.lang.reflect.*;

/**
 * Created by zmz on 16/5/26.
 */


interface Person{
    public void sayHello(String otherName);
}

class Student implements Person{

    private String name;
    private int age;

    public Student(){
        this.name = "";
        this.age = 0;
    }

    public Student(String name){
        this.name = name;
        this.age = 0;
    }

    public Student(int age){
        this.name = "";
        this.age = age;
    }

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

    @Override
    public void sayHello(String otherName){
        System.out.println("Hello " + otherName + "! I'm " + this.name +".");
    }

    public String toString(){
        return "[" + this.name + ", " + this.age +"]";
    }

    public String getName(){
        return this.name;
    }

    public int getAge(){
        return this.age;
    }

    public void setName(String name){
        this.name = name;
    }

    public void setAge(int age){
        this.age = age;
    }


}


public class MyTest {
    public static void main(String[] args){
        /****************三种获取Class对象的方法********************************/
        System.out.println("****************三种获取Class对象的方法********************************");
        Class<Student> c1 = Student.class;  // 第一种方法
        Class<?> c2;
        /*
         * 第二种方法:最好使用这种方式,捕获异常
         */
        try{
            c2 = Class.forName("reflection.data.Student");
            System.out.println(c1 == c2);
        }
        catch (Exception e){
            e.printStackTrace();
        }

        Student p1 = new Student("zmz", 27);
        // 第三种方法:通过变量的getClass()方法获取
        Class c3 = p1.getClass();

        System.out.println(c1 == c3);

        System.out.println("\n****************获取包名和类名********************************");

        String className = p1.getClass().getName();
        String simpleName = p1.getClass().getSimpleName();
        System.out.println("Class.getName()获取完整的类名(包括包名): " + className);  // 输出:Class.getName()获取完整的类名(包括包名): reflection.data.Student
        System.out.println("Class.getSimpleName()只获取类名:" + simpleName); // 输出: Class.getSimpleName()只获取类名:Student

        System.out.println("\n****************构造函数类:Constructor********************************");

        Class studentClass = Student.class;
        try{
            // 下面这种方式调用无参构造函数,所以必须保证类具有无参的构造参数
            Student tem = (Student)studentClass.newInstance();
            tem.sayHello("ssy");                       // 输出: Hello! I'm .
            System.out.println(tem.toString());   // [, 0]
        }
        catch (InstantiationException e){
            e.printStackTrace();
        }
        catch (IllegalAccessException e){
            e.printStackTrace();
        }

        System.out.println("----------------构造函数列表-------------------");

        Constructor<reflection.data.Student>[] constructors = studentClass.getConstructors();  // 获取所有的构造参数

        for(int i = 0; i < constructors.length; i++){
            Constructor c = constructors[i];
            System.out.println("第" + i + "个构造函数");
            System.out.println("  方法名: " + c.getName());  // Constructor.getName()获取完整的类名,例如:reflection.data.Student
            System.out.println("  修饰符: " + Modifier.toString(c.getModifiers()));  // Constructor.getModifiers()获取修饰符,为枚举类型,需要使用Modifier类进行转换

            Class[] paramTypes = c.getParameterTypes();  // 获取参数的类型列表
            for(int j = 0; j < paramTypes.length; j++){

                System.out.println("  第" + j + "个参数的类型");
                System.out.println("    " + paramTypes[j].getName());  //输出:  java.lang.String
            }
            System.out.println("  该构造函数的完整签名: " + c);  // public reflection.data.Student(java.lang.String)
        }

        System.out.println("----------------通过构造函数对象新建对象-------------------");
        try{
            Student s1 = constructors[0].newInstance("zmz", 27);   // 输出: [zmz, 27]
            System.out.println(s1.toString());
        }
        catch (Exception e){
            e.printStackTrace();
        }

        System.out.println("\n****************返回实现的接口********************************");
        Class<?> interfaces[] = Student.class.getInterfaces();
        for(int i = 0; i < interfaces.length; i++){
            System.out.println("第" + i + "个接口");
            System.out.println(interfaces[i].getName());  // reflection.data.Person
        }

        System.out.println("\n****************返回父类********************************");
        Class superClass = Student.class.getSuperclass();
        System.out.println("父类:" + superClass.getName());  //输出:   父类:java.lang.Object

        System.out.println("\n****************获取所有的方法以及方法的异常********************************");

        Method methods[] = Student.class.getMethods();

        for(int i = 0; i < methods.length; ++i) {
            Class<?> returnType = methods[i].getReturnType();  // 方法返回类型的Class对象
            Class<?> paras[] = methods[i].getParameterTypes();  // 方法的参数的Class对象数组

            int temp = methods[i].getModifiers();  // 获取修饰符
            System.out.print(Modifier.toString(temp) + " ");
            System.out.print(returnType.getName() + "  ");
            System.out.print(methods[i].getName() + " ");
            System.out.print("(");

            for(int j=0;j<paras.length;++j){
                System.out.print(paras[j].getName()+" "+"arg"+j);
                if(j<paras.length-1){
                    System.out.print(",");
                }
            }

            Class<?> exce[]=methods[i].getExceptionTypes();  // 获取该函数的异常
            if(exce.length>0){
                System.out.print(") throws ");
                for(int k = 0; k < exce.length; ++k){
                    System.out.print(exce[k].getName()+" ");
                    if(k<exce.length-1){
                        System.out.print(",");
                    }
                }
            }else{
                System.out.print(")");
            }
            System.out.println();  // 一个完整函数的输出例子:public final void  wait (long arg0,int arg1) throws java.lang.InterruptedException
        }

        System.out.println("\n****************获取所有的属性********************************");
        System.out.println("---本类属性------");

        Field fields[] = Student.class.getDeclaredFields();  //获取本类声明的属性

        for (int j = 0; j < fields.length; j++) {
            int mo = fields[j].getModifiers();// 权限修饰符
            String priv = Modifier.toString(mo);
            Class<?> type = fields[j].getType(); // 属性类型
            System.out.println(priv + " " + type.getName() + " "  + fields[j].getName() + ";");
        }

        System.out.println("---所有的属性------");

        Field fields1[] = Student.class.getDeclaredFields();  //获取本类声明的属性

        for (int j = 0; j < fields1.length; j++) {
            int mo = fields1[j].getModifiers();// 权限修饰符
            String priv = Modifier.toString(mo);
            Class<?> type = fields1[j].getType(); // 属性类型
            System.out.println(priv + " " + type.getName() + " "  + fields1[j].getName() + ";");
        }

        System.out.println("\n****************通过反射调用类的函数********************************");
        try {
            Class demo = Student.class;
            Method method=demo.getMethod("sayHello", String.class);//调用Person类中的sayHello方法
            method.invoke(demo.newInstance(), "ssy");

            Method method2 = demo.getMethod("toString");
            System.out.println(method2.invoke(demo.newInstance()));
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("-----调用set方法--------------");
        Student s1 = new Student();
        try{
            Method setNameMethod = Student.class.getMethod("setName", String.class);
            setNameMethod.invoke(s1, "zmz");
        }
        catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("-----调用get方法--------------");
        try{
            Method getNameMethod = s1.getClass().getMethod("getName");
            System.out.println(getNameMethod.invoke(s1));   //输出:  zmz
        }
        catch (Exception e){
            e.printStackTrace();
        }

        System.out.println("\n****************通过反射操作属性********************************");

        Student s2 = new Student("ssy", 28);
        System.out.println(s2.toString());   //输出: [ssy, 28]

        try{
            Field ageField = s2.getClass().getDeclaredField("age");  // getDeclaredField()返回所有的属性,getFields()返回所有可访问的公共字段
            ageField.setAccessible(true);  // 私有变量可以访问
            ageField.set(s2, 29);
            System.out.println(s2);  // 输出: [ssy, 29]
        }
        catch (Exception e){
            e.printStackTrace();
        }

        System.out.println("\n****************通过反射修改数组的信息********************************");
        int[] temp = {1,2,3,4,5};
        Class<?> demo = temp.getClass().getComponentType();
        System.out.println("数组元素类型: " + demo.getName());  // int
        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));

        /**
         * 其实在java中有三种类类加载器。

         1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。

         2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类

         3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
         */
        System.out.println("\n****************获取类加载器********************************");
        System.out.println(Student.class.getClassLoader().getClass().getName());  // sun.misc.Launcher$AppClassLoader

    }
}

java反射详解

----EOF-----

Categories: java Tags: java 反射