Java反射学习

152 阅读3分钟

近期在看Netty相关的学习资料,其中涉及到了手写框架的部分,有用到Java反射这一部分的知识,于是整理学习一番。

反射是框架设计的灵魂。

Java反射的定义

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

为什么要用反射

为什么要用反射呢?直接new一个对象不是很方便吗?
反射的初衷,并不是为了让你更方便的创建对象,而是让你在写代码时更加灵活,降低耦合度,提高代码的自适应能力。
例: 创建一千个名字不一样的对象。需要写new代码一千行吗,引入一千个类?通过反射则不用引入一千个类。

获取Class对象

class对象是Java反射机制实现的基础。

获取class对象有以下几种方法:

  • 通过Class.forName(“类路径‘)加载类 ------ 常用

    Class<?> cls = Class.forName("com.jishucai.reflection.Student");//forName(包名.类名)
    Student s1 = (Student)cls.newInstance();
    
  • 通过new的对象的.getClass()方法

    Student s2 = new Student();
    Class stuClass = s2.getClass();
    
  • 通过类.class文件

    Student s3 = Student.class;
    

获取类的信息

前面已经说过,可以通过反射获取到类的各种信息,下面一 一说明。

获取类的构造函数

  1. 单独获取某个构造函数

    getDeclaredConstructor(顺序传入参数类型)----不分构造器类型,public|!public
    getConstructor(参数类型)---只获取public类型
    
    eg:
    getDeclaredConstructor(String.class)
    getConstructor(String.class)
    
  2. 获取类的所有构造函数

    getDeclaredConstructors()		--- 获取所有的构造器
    getConstructors()				--- 获取public的构造器
    

获取类的成员方法

  1. 获取单个类的成员方法

    getDeclaredMethod(name, class[])	--- 获取指定参数的成员方法
    getMethod(name, class [])			--- 获取指定参数的public成员方法
    
  2. 获取所有成员方法

    getDeclaredMethods()   			--- 获取所有的成员方法
    getMethods()					--- 获取所有的public类型的成员方法
    
  3. 获取类的方法并执行

    通过执行method.invoke(Object o, class [] paramType)可以调用方法执行。
    
    eg:
    Class clazz = Class.forName("com.jishucai.reflection.Student");
    Object o = clazz.getDeclaredConstructor().newInstance();
    Method setSex = clazz.getMethod("setSex", int.class);
    setSex.invoke(o, 10);
    
    对于private类型的方法
    需要执行setAccessible
    
    testStudent.setAccessible(true);
    testStudent.invoke(o);
    

获取类的成员变量

  1. 获取单个类的成员变量

    getDeclaredField(String name);		---  获取指定的成员变量,所有类型
    getField(String name);				---  获取成员变量,public类型
    
  2. 获取所有的成员变量

    getDeclaredFields()					--- 获取所有的成员变量
    getFields()							--- 获取所有的public成员变量
    

获取类的修饰域

类Class、Method、Constructor、Field都有一个public方法int getModifiers()。该方法返回一个int类型的数,表示被修饰对象( Class、 Method、 Constructor、 Field )的修饰类型的组合值。

System.out.println("获取指定对象的修饰域");
System.out.println(Modifier.toString(studentName.getModifiers()));

Java反射的应用

  1. 实现动态代理

    // 实现接口
    public interface SomeService {
        public void eat(String food);
    }
    
    // 接口实现类
    public class SomeServiceImpl implements SomeService{
        @Override
        public void eat(String food) {
            System.out.println("猫吃" + food);
        }
    }
    
    // 代理类
    public class SomeInvocationHandler implements InvocationHandler {
    
        private SomeService service;
    
        public SomeInvocationHandler(SomeService service) {
            this.service = service;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("------begin-----");
            Object invoke = method.invoke(service, args);
            System.out.println("------end-------");
            return invoke;
        }
    }
    
    // 测试类
    public class TestProxy {
        public static void main(String[] args) {
            SomeService service = new SomeServiceImpl();
            SomeInvocationHandler someInvocationHandler = new SomeInvocationHandler(service);
            SomeService proxy = (SomeService) Proxy.newProxyInstance(someInvocationHandler.getClass().getClassLoader(),
                    service.getClass().getInterfaces(), someInvocationHandler);
            proxy.eat("你好");
    
        }
    }
    
    
  2. 跳过集合的编译检查

    在一个存储Integer类型数据的List中插入一个String类型数据

    public class TestReflect {
        public static void main(String[] args) throws Exception {
            ArrayList<Integer> list = new ArrayList<Integer>();
            Method method = list.getClass().getMethod("add", Object.class);
            method.invoke(list, "Java反射机制实例。");
            System.out.println(list.get(0));
        }
    }