Java反射机制(一)

什么是反射?
反射机制是在【运行状态】中:
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;

反射提供的功能:
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法。
生成动态代理

反射机制原理
Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。也就是说,ClassLoader找到了需要调用的类时(java为了调控内存的调用消耗,类的加载都在需要时再进行,很抠但是很有效),就会加载它,然后根据.class文件内记载的类信息来产生一个与该类相联系的独一无二的Class对象。该Class对象记载了该类的字段,方法等等信息。以后jvm要产生该类的实例,就是根据内存中存在的该Class类所记载的信息(Class对象应该和我所了解的其他类一样会在堆内存内产生、消亡)来进行。而java中的Class类对象是可以人工自然性的(也就是说开放的)得到的(虽然你无法像其他类一样运用构造器来得到它的实例,因为Class对象都是jvm产生的。不过话说回来,客户产生的话也是无意义的),而且,更伟大的是,基于这个基础,java实现了反射机制。

获取Class对象三种方式:

  • 1.通过Object类的getClass()方法。例如:
    Class perClazz = new String("").getClass();
  • 2.通过Class类的静态方法——forName()来实现:
    Class perClazz = Class.forName(“MyObject”);
  • 3.如果T是一个已定义的类型的话,在java中,它的.class文件名:T.class就代表了与其匹配的Class对象,例如:Class perClazz = Manager.class;Class c4 = int.class;
    Class perClazz = Double[].class;

获取方法

  • //获取所有的公共方法
    Method[] methods = perClazz.getMethods();
  • //获取当前类的所有方法(当前类,忽略访问修饰符限制)
    Method[] declaredMethods = perClazz.getDeclaredMethods();

获取所有的接口

  • //Java多实现,获取所有的接口
    Class<?>[] interfaces = perClazz.getInterfaces();

获取父类

  • //Java单继承,获取父类
    Class<?> superClass = perClazz.getSuperclass();

获取构造方法

  • //获取所有的构造方法
    Constructor<?>[] constructors = perClazz.getConstructors();
  • //获取指定的构造放方法,获取类型方法时,基本类型和包装类是不同的
    Constructor constructor = perClazz.getConstructor(int.class);

获取类的属性

  • //公共属性
    Field[] fields = perClazz.getFields();
  • //所有属性
    Field[] declaerdields = perClazz.getDeclaredFields();

修改访问权限

  • Field.setAccessible(true);//属性
  • Method.setAccessible(true);//方法
  • Constructor.setAccessible(true);//构造方法

调用Class属性/方法/构造器

  • 属性
    Field idField = perClazz.getDeclaredField(“id”);
    //修改访问权限Field/Method.setAccessible(true);/
    idField.setAccessible(true);
    idField.set(person,1);
    System.out.println(person.getId());

  • 方法
    Method priMethod = perClazz.getDeclaredMethod(“privateMethod”,null);
    priMethod.setAccessible(true);
    priMethod.invoke(person,null);//invoke()调用方法

    Method priMethod2 = perClazz.getDeclaredMethod(“privateMethod2”,String.class);
    priMethod2.setAccessible(true);
    priMethod2.invoke(person,“JavaMan”);//invoke()调用方法

  • 构造器
    Constructor constructor = perClazz.getConstructor(int.class);
    Person person = (Person) constructor.newInstance(15);
    System.out.println(person.getId());

绕过范性类型检查
编译器编译带参数说明的集合时会去掉类型的信息,转化为普通的链表,所以运行时,将不会受到泛型的影响。所以可以这样来绕开泛型的限制;

ArrayList<Integer> al = new ArrayList<Integer>();
		al.add(1);
		al.add(2);
		//获取链表的add方法,注意这里是Object.class,如果写int.class会抛出NoSuchMethodException异常
		Method m = al.getClass().getMethod("add", Object.class);
		//调用反射中的add方法加入一个string类型的元素,因为add方法的实际参数是Object
		m.invoke(al, "hello");

配置文件+反射机制
通过配置文件配置类的全路径和部分属性,可以创造工具类利用反射机制实现类的各种操作。

XXX.properties
ClassPath=com.javaman.reflect.Person

 //Dome.class.getClassLoader()获取文件路径类加载器
        InputStream in = Dome.class.getClassLoader().getResourceAsStream("XXX.properties");
        //读取文件
        Properties properties=new Properties();
        properties.load(in);
        String ClassPath = properties.getProperty("ClassPath");

其他方法

  • 1.getName()
    一个Class对象描述了一个特定类的特定属性,而这个方法就是返回String形式的该类的简要描述。

  • 2.newInstance()
    该方法可以根据某个Class对象产生其对应类的实例。需要强调的是,它调用的是此类的默认构造方法。

  • 3.getClassLoader()
    返回该Class对象对应的类的类加载器。

  • 4.getComponentType()
    该方法针对数组对象的Class对象,可以得到该数组的组成元素所对应对象的Class对象。例如:
    int[] ints = new int[]{1,2,3};
    Class class1 = ints.getClass();
    Class class2 = class1.getComponentType();
    而这里得到的class2对象所对应的就应该是int这个基本类型的Class对象。

  • 5.getSuperClass()
    返回某子类所对应的直接父类所对应的Class对象。

  • 6.isArray()
    判定此Class对象所对应的是否是一个数组对象。

代码测试

package com.javaman.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.FileHandler;

/**
 * Created by zhahongsheng on 2019/4/14.
 */
public class TestReflect {

    /**
     * 获取反射对象(反射入口)
     */
    public static void demo1(){
        //获取反射对象(反射入口)1。Class.forName(全类名)2.xx.Class(),3.对象.getclass()

        try {
            Class<?> perClazz = Class.forName("com.javaman.reflect.Person");
            System.out.println(perClazz);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Class<?> perClazz2= Person.class;
        System.out.println(perClazz2);

        Person per = new Person();
        Class<?> perClazz3 = per.getClass();
        System.out.println(perClazz3);
    }

    //获取方法
    public static void demo2(){
        //Class入口
        Class<?> perClazz = null;
        try {
            perClazz = Class.forName("com.javaman.reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //获取所有的公共方法
        Method[] methods = perClazz.getMethods();
        for(Method method : methods){
            System.out.println(method);
        }

        System.out.println("=========================================================");
        //获取当前类的所有方法(当前类,忽略访问修饰符限制)
        Method[] declaredMethods = perClazz.getDeclaredMethods();
        for (Method method : declaredMethods){
            System.out.println(method);
        }
    }

    //获取所有的接口
    public static void demo3(){
        Class<?> perClazz =null;
        try {
            perClazz = Class.forName("com.javaman.reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Class<?>[] interfaces = perClazz.getInterfaces();
        for(Class<?> inter : interfaces ){
            System.out.println(inter);
        }
    }

    //获取父类
    public static void demo4(){
        Class<?> perClazz =null;
        try {
            perClazz = Class.forName("com.javaman.reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Class<?> superClass = perClazz.getSuperclass();
        System.out.println(superClass);
    }

    //获取所有的构造方法
    public static void demo5() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> perClazz =null;
        try {
            perClazz = Class.forName("com.javaman.reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Constructor<?>[] constructors = perClazz.getConstructors();
        for(Constructor constructor : constructors){
            System.out.println(constructor);
        }

        //获取指定的构造放方法
        //在获取类型方法时,基本类型和包装类是不同的
        Constructor constructor = perClazz.getConstructor(int.class);

        Person person = (Person) constructor.newInstance(15);
        System.out.println(person.getId());

    }

    //获取所有的公共属性
    public static void demo6(){
        Class<?> perClazz =null;
        try {
            perClazz = Class.forName("com.javaman.reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //公共属性
        Field[] fields = perClazz.getFields();
        for(Field field : fields){
            System.out.println(field);
        }
        //所有属性
        Field[] declaerdields = perClazz.getDeclaredFields();
        for(Field field : declaerdields){
            System.out.println(field);
        }
    }

    public static void demo7() throws IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
        Class<?> perClazz =null;
        try {
            perClazz = Class.forName("com.javaman.reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Object instance = perClazz.newInstance();
        if(instance instanceof Person){
            Person person = (Person)instance;
            person.interfaceMethod();

            Field idField = perClazz.getDeclaredField("id");
            //修改访问权限Field/Method.setAccessible(true);/
            idField.setAccessible(true);
            idField.set(person,1);
            System.out.println(person.getId());

            Method priMethod = perClazz.getDeclaredMethod("privateMethod",null);
            priMethod.setAccessible(true);
            priMethod.invoke(person,null);//invoke()调用方法

            Method priMethod2 = perClazz.getDeclaredMethod("privateMethod2",String.class);
            priMethod2.setAccessible(true);
            priMethod2.invoke(person,"JavaMan");//invoke()调用方法
        }
    }
    public static void main(String[] args) {
//            demo1();
//            demo2();
//            demo3();
//            demo4();
        try {
            demo5();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
//        demo6();
        try {
            demo7();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }


}

总结
反射机制是java框架的核心,反射机制的重点在于运行状态下工作

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值