javaSEJava学习笔记程序员

反射

2017-04-13  本文已影响27人  风吹稻子

1.什么是反射?

“听其声,问其人”,就是根据声音,我们可以知道这个人。而反射就是“根据当前类,获取这个类的属性和方法以及构造器”。

比如我们知道一个类名Person,但不知道Person类的方法,属性以及构造器。如果我们想知道Person类到底有什么方法、属性、构造器?怎么办呢?那就使用反射。

2.为什么要用反射?

1. 判断运行时对象所属的类
2. 判断运行时对象所具有的成员变量和方法
3. 甚至可以调用到private的方法
4. 生成动态代理

3.什么是动态代理?

4.使用反射的步骤

  1. 首先获取一个类的Class对象
  2. 用这个对象来调用相应的方法获取属性、构造器和方法。

注意:三个重要的反射类,Filed、Constructor、Method

5.获取Class对象的方式

  1. “.class”方法:在知道类型的情况下使用,比如boolean.class
  2. "Object.getClass()":在知道对象的情况下使用,比如:new Date().getClass
  3. "Class.forName()":在知道类的全名下使用,比如“java.lang.String”.但是这种方法不能用在基本类型上,但可以用在基本类型的数组上。而且此类在使用的基础上,会抛出异常。

代码示例:
package reflection;

import java.util.Date;

public class TestReflection {

    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println("第一种方法:Object.getClass()");
        Class c1 = new Date().getClass();
        System.out.println(c1.getName());// 输出对象名称
        System.out.println("第二种方法:.class语法");
        Class c2 = boolean.class;
        System.out.println(c2.getName());
        System.out.println("第三种方法:Class.forName()");
        Class c3 = Class.forName("java.lang.String");
        System.out.println(c3.getName());
        System.out.println("第四种方法:包装类的Type域");
        Class c4 = Double.TYPE;
        System.out.println(c4.getName());
        
    }

}

结果:

第一种方法:Object.getClass()
java.util.Date
第二种方法:.class语法
boolean
第三种方法:Class.forName()
java.lang.String
第四种方法:包装类的Type域
double

说明:
TYPE:每个基本数据类型和void都有包装类,利用TYPE就可以获取Class对象
getName():查看各种类型对象的名称,可以根据这些名称判断原来对象的类型

6.奇怪的数组类型

// 奇怪的数组类型
    String array = new int[4].getClass().getName();
    String array2 = new int[4][4].getClass().getName();

    System.out.println("一维基本类型数组" + array);
    System.out.println("二维基本类型数组" + array2);

    System.out.println("使用getCanonicalName()方法可以直接获取数组");
    String arrayCopy = new int[4].getClass().getCanonicalName();
    String arrayCopy2 = new int[4][4].getClass().getCanonicalName();

    System.out.println("一维基本类型数组" + arrayCopy);
    System.out.println("二维基本类型数组" + arrayCopy2);

测试结果:

一维基本类型数组[I
二维基本类型数组[[I
使用getCanonicalName()方法可以直接获取数组:
一维基本类型数组int[]
二维基本类型数组int[][]

说明:
1.一维数组和二维数组对象类型是“[”组成
2.可以直接使用getCanonicalName()方法获取直观的数组类型

获取类的一些基本信息

 package reflection;

import java.lang.reflect.Modifier;

public class TestReflection {
    private String name;
    private boolean b;
    private int[] age;

    //方法
    public int info(int a) {
        return a;
    }

    public static void main(String[] args) throws ClassNotFoundException {
        // 获取类名
        Class c1 = TestReflection.class;
        Class c2 = Class.forName("reflection.TestReflection");
        System.out.println("类名" + c1);

        // 获取指定的包名
        String package1 = c1.getPackage().getName();
        System.out.println("包名:" + package1);

        // 获取类的修饰符,注意修饰符返回的是数字0,1,2
        int mod = c1.getModifiers();
        String modifier = Modifier.toString(mod);
        System.out.println("修饰符:" + modifier);

        // 获取父类 
        Class superClazz = c1.getSuperclass();
        String superClazzName = superClazz.getName();
        System.out.println("父类:" + superClazzName);

        // 获取实现的接口
        Class[] interfaces = c1.getInterfaces();
        for (Class i : interfaces) {
            System.out.println("接口名" + i.getName());
        }
    }

}

测试结果:

类名class reflection.TestReflection
包名:reflection
修饰符:public
父类:java.lang.Object

获取成员变量

        // 获取指定类的成员变量
        Field[] fields = c1.getDeclaredFields();
        for(Field f : fields){

        //获取每一个变量的修饰符
        int modf = f.getModifiers();
        String  modifiers = Modifier.toString(modf);
        
        //获取类型
        Class type = f.getType();
        String typeName = type.getName();

        //获取变量名
        String name = f.getName();
        System.out.println("变量名:"+name+" 类型:"+typeName+" 修饰符:"+modifiers);

测试结果:

变量名:name 类型:java.lang.String 修饰符:private
变量名:b 类型:boolean 修饰符:private
变量名:age 类型:[I 修饰符:private

获取构造方法

    //获取构造方法
    Constructor[] constructor = c1.getDeclaredConstructors();
    for(Constructor construct : constructor){
        //这里只获取了名字,修饰符,参数与上大致相同
        String conName = construct.getName();
        System.out.println("构造方法的名字:"+conName);
    }

测试结果:

构造方法的名字:reflection.TestReflection

获取成员方法

// 获取成员方法
    Method[] methods = c1.getDeclaredMethods();
    for (Method m : methods) {
        // 获取方法的修饰符
        int modm = m.getModifiers();
        String modName = Modifier.toString(modm);
        // 获取返回值类型
        Class returnType = m.getReturnType();
        String returName = returnType.getName();
        if (returnType.isArray()) {
            //returName = returnType.getClass().getCanonicalName();
            returName = returnType.getComponentType().getName();
        }
        // 获取方法名
        String methodName = m.getName();
        System.out.println("方法名:" + methodName + " 方法修饰符:" + modName + " 方法的返回类型" + returName);
        // 获取参数相关信息
        Class[] parameter = m.getParameterTypes();
        for (Class p : parameter) {
            // 获取参数的类型
            String paramType = p.getTypeName();

            // 获取参数名
            String paramName = p.getName();
            System.out.println(methodName + "方法的参数名:" + paramName + " 参数的类型:" + paramType);
        }

        System.out.println("-------------------------");
    }

测试结果:

方法名:main 方法修饰符:public static 方法的返回类型void
main方法的参数名:[Ljava.lang.String; 参数的类型:java.lang.String[]
-------------------------
方法名:info 方法修饰符:public 方法的返回类型int
info方法的参数名:int 参数的类型:int
info方法的参数名:boolean 参数的类型:boolean
-------------------------

反射应用的链接

http://www.jianshu.com/p/2de67f864d04

上一篇下一篇

猜你喜欢

热点阅读