zoukankan      html  css  js  c++  java
  • 【Java】 Java反射机制总结

    一.什么是反射

      在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。

    二.为什么需要反射

      首先我们要了解Java的编译类型有两种:

        1.静态编译:在编译时确定类型,绑定对象即通过。

        2.动态编译:运行时确定类型,绑定对象。动态编译最大限度地发挥了Java的灵活性,体现了多态的应用,可以减低类之间的耦合性。

      而Java反射机制在Java动态编译的起到了一个关键作用。

    三.反射获取Class对象的三种方式(获取字节码对象)

    public class ReflectDemo1 {
        public static void main(String[] args) throws ClassNotFoundException {
            //方式一(通过Class.forName的方式,括号中是包名.类名)常用
            Class clazz1 = Class.forName("xx.ReflectDemo1");
            //方式二(类名.class)
            Class clazz2 = ReflectDemo1.class;
            //方式三(创建类的实例对象,再通过getClass的方式)
            ReflectDemo1 ref = new ReflectDemo1();
            Class clazz3 = ref.getClass();
            
            System.out.println(clazz1 == clazz2);//true
            System.out.println(clazz2 == clazz3);//true,三个字节码对象是同一个字节码对象
        }
    }

    四.通过反射获构造器,成员变量,方法等

    public class ReflectDemo2 {
        private String name;
        public ReflectDemo2(String name) {
            super();
            this.name = name;
        }
        @Override
        public String toString() {
            return "[name=" + name + "]";
        }
        public void method1(){
            System.out.println("你好啊");
        }
        public void method2(String name){
            System.out.println("hello"+name);
        }
    
        public static void main(String[] args) throws Exception {
            //通过反射获取有参构造,并通过有参构造创建对象
            Class clazz = Class.forName("course9.ReflectDemo2");
            Constructor c = clazz.getConstructor(String.class);
            ReflectDemo2 ref = (ReflectDemo2) c.newInstance("zx");
            System.out.println(ref);
            //通过反射获取成员变量并使用
            Field f = clazz.getDeclaredField("name");//获取姓名字段(暴力反射获取,即使是私有变量)
            f.setAccessible(true);//设置去除私有权限
            f.set(ref, "ls");
            System.out.println(ref);
            
            //通过反射获取方法并使用
            Method m1 = clazz.getMethod("method1");
            Method m2 = clazz.getMethod("method2",String.class);
            m1.invoke(ref);
            m2.invoke(ref,"张三");
            
        }
    }

    输出结果如下:

    五.通过反射越过泛型检查

    public class ReflectDemo3 {
        public static void main(String[] args) throws Exception {
            //使用反射越过泛型的检查
            ArrayList<Integer> list = new ArrayList<>();//创建一个存放整型的链表
            list.add(11);
            list.add(22);
            Class clazz = Class.forName("java.util.ArrayList");//获取java.util.ArrayList类的字节码对象
            Method m = clazz.getMethod("add", Object.class);//获取其中的add方法
            m.invoke(list, "abc");//链表中添加字符串
            System.out.println(list);
        }
    }

     输出结果如下:(“abc”不是Interger类型,但是能存放在创建的链表中)

    六.反射实现动态代理

    public class ReflectDemo4 implements User{
        public static void main(String[] args) {
            ReflectDemo4 ref = new ReflectDemo4();
            ref.add();
            ref.delete();
            MyInvocationHandler m = new MyInvocationHandler(ref);//创建动态代理类(放入需要代理的对象)
            User user = (User) Proxy.newProxyInstance(ref.getClass().getClassLoader(), ref.getClass().getInterfaces(), m);//获取类加载器和接口
            
            System.out.println("-----------------------");
            user.add();
            user.delete();
        }
        @Override
        public void add() {
            System.out.println("添加功能");
        }
        @Override
        public void delete() {
            System.out.println("删除功能");
        }
    }
    interface User{
        public void add();
        public void delete(); 
    }
    
    //动态代理类
    class MyInvocationHandler implements InvocationHandler{
        private Object target;
        public MyInvocationHandler(Object target) {
            super();
            this.target = target;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("权限校验");
            method.invoke(target, args);//执行被代理target对象的方法
            System.out.println("日志记录");
            return null;
        }
        
    }

    输出结果如下:(动态代理前的输出和代理后的输出)

    七.反射的一些应用

      如加载一些文件

      逆向代码 ,例如反编译

      与注解相结合的框架 例如Spring

      动态生成类框架 例如Gson

  • 相关阅读:
    接收HttpPost请求路由可以不用带去掉参数
    吟唱一首
    C# XML反序列化解析成对象集合
    两个对象中相同属性赋值
    CefSharp 笔记-1
    C# 笔记--Label设置背景图片
    C# 笔记--VS 2017包下载超时,连接失败
    SQLite——C#查询表时 该字符串未被识别为有效的 DateTime 错误
    C# 笔记--Sendkeys
    C# 笔记——MeasureString准确测量
  • 原文地址:https://www.cnblogs.com/ywb-articles/p/10588298.html
Copyright © 2011-2022 走看看