四大神器之反射

Java反射机制,是一个基础的内容章节,在对于之后的框架学习中起到了至关重要的作用,现在比较流行的是spring

框架 ,其中的IOC(自动注入)以及AOP(动态代理),在AOC中代理模式又分为动态代理和byteCode

instrument(插桩)或者是CGLIB 。

在学习Java反射机制前,首先问一个问题:在Java运行时,对于任意一个类,能否知道这个类有那些属性和方法?对

于任意一个对象,能否调用它任意一个方法?

答案是肯定的。可以!

在这里要去区别一个事情:如果说在自己写的类中去改一个数据类型或者说属性,那只是在编译时,并不是在运行

时。

反射机制的几大功能:

  • 在运行时,判断任意一个对象所属类。
  • 在运行时,构造任意一个对象。
  • 在运行时,判断任意一个类所具有的成员变量和方法
  • 在运行时,调用任意一个对象的方法。

一般而言:程序运行时,允许改变程序结构和变量类型成为动态语言。由此可见Java并不是动态语言,但是Java有一

个动态相关的机制Reflection,可以运行时加载、探知、使用编译期间完全未知的classes(但是methods定义不知

道)。所以Reflection是Java视为动态语言的关键性质,允许在程序运行时通过Reflection APIs 取得任何一个已知名

称的class的内部信息。(包括父类,接口,变量,方法等)。

接下来我们用代码来举一个例子。

public class DumpMethods {
    //从命令行接受一个字符串(该字符串是某个类的全名)
    //打印该类的所有方法

    public static void main(String[] args) throws ClassNotFoundException {
        //class类是所有反射的入口
        Class<?> classType = Class.forName(args[0]);//编译时不知道args是什么?

        Method[] methods = classType.getDeclaredMethods();

        for (Method method : methods) {
            System.out.println(method);
        }

    }
}

在这里,我们可以看到,Java虚拟机并不知道你所要传入的参数是什么,这个时候我们类的全类型名

称 Java.lang.String输入进去,我们可以看到如下图片

其中,标红的那一行可以看到,直接将私有的方法也可显示出来。这一个是非常有用的。那么这些代码就可以很明显

的让我们知道,在Java运行时,就可以判断任意一个对象所属类。

接下来,我们来看一下反射的相关代码:

public class InvokeTester {
    public int add(int param1, int param2) {
        return param1 + param2;
    }

    public String echo(String msg) {
        return msg + "hello";
    }

    public static void main(String[] args) throws Exception {
        Class<?> classType = InvokeTester.class; //获取类对象

        Object invokeTester = classType.newInstance();//创建此 Class 对象所表示的类的一个新实例。
        //调用前提是 必须有一个不带参数的构造器

        //以上两行代码就相当于new invokeTester

        Method addmethod = classType.getMethod("add", int.class, int.class);//确定这个方法需要输入 方法名 参数

        Object result = addmethod.invoke(invokeTester, new Object[]{100, 200});
        //以上两行相当于i.add(100,200)
        System.out.println((Integer) result);

        Method echoMethod = classType.getMethod("echo", new Class[]{String.class});
        Object result2 = echoMethod.invoke(invokeTester, "hello world");
        System.out.println((String) result2);
    }
}

在这里,着重说获取类对象时,创建的class对象新的实例时,必须有一个不带参数的构造器,否则会报错,那么怎

没有应该怎么办呢?下面会讲到。确认一个方法,我们通过重载机制就可以知道,需要通过这个方法的名字和他的参

数来确认。上一个我们通过classType.getDeclareMethods()来获取了所有方法,而现在我们可以通过

classType.getMethods()方法来获得这个我们需要已知方法的名字,在这里参数类型是int.class,String.class.在之

后,我们通过revoke方法,来获得我们调用方法的结果,invoke方法中的两个参数,第一个参数是我们需要调用的对

象,第二个参数就是调用方法的参数,这个参数应该与getmethod方法的参数所写的类型一致,下面我们来看一下结

果:

我们通过这个例子,就可以发现,通过反射机制我们完全可以调用一个方法。

接下来,整一个复杂点的!

public class ReflectTester {

    public Object copy(Object object) throws Exception {
        Class<?> classType = object.getClass();

        System.out.println(classType.getName());

        Object objectCopy = classType.getConstructor(new Class[]{})
                .newInstance(new Object[]{});
        //相当于是 object object2 = classType.newInstance();

        //获得对象的所有属性
        Field[] fields = classType.getDeclaredFields();

        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];

            String fieldName = field.getName();

            //获得属性的首字母并转换为大写
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            //获得和属性对应的getxxx()方法
            String getMethodName = "get" + firstLetter + fieldName.substring(1);
            //获得个属性对应的setxxx()方法
            String setMethodName = "set" + firstLetter + fieldName.substring(1);

            //获得get方法
            Method getMethod = classType.getMethod(getMethodName, new Class[]{});

            //获得set方法
            Method setMethod = classType.getMethod(setMethodName, new Class[]{field.getType()});

            Object value = getMethod.invoke(object, new Object[]{});

            System.out.println(fieldName + ":" + value);

            setMethod.invoke(objectCopy, new Object[]{value});
        }
        return objectCopy;
    }

    public static void main(String[] args) throws Exception {

        Customer customer = new Customer();

        customer.setId(new Long(1));
        customer.setName("zhangsan");
        customer.setAge(20);

        Customer customerCopy = (Customer) new ReflectTester().copy(customer);

        System.out.println(customerCopy.getId() + "," + customerCopy.getName() + "," + customerCopy.getAge());
    }

}

class Customer {
    private long id;

    private String name;

    private int age;

    public Customer() {
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

以上代码创造了一个Customer类,并通过反射进行了一次copy,调用getter,setter方法,成功。此处一定要在

Customer类中写入构造器,否则容易造成权限不通过导致没有办法读取。我们可以看到  Object object copy =

classType.getConstructor(new Class[]{}) .newInstance(new Object[]{});这一行代码就相当于是object object2 =

classType.newInstance();如果没有无参构造器时,则可运用这个方法

原文地址:https://www.cnblogs.com/xiaobaoa/p/12178508.html

时间: 2024-10-21 11:00:50

四大神器之反射的相关文章

四大神器之反射(二)

利用反射来操纵数组 import java.lang.reflect.Array; /** * * 利用反射来操纵数组 */ public class ArrayTester { public static void main(String[] args) throws ClassNotFoundException { Class classType = Class.forName("java.lang.String"); Object array = Array.newInstanc

破解NET的四大神器(转)

原文地址 原本这篇文章可以更早一星期写出来与大家分享,由于某方面的原因耽搁到现在,心里竟有那么一点好像对不住大家的感觉.这当然与神器有关,因为我发现利用这四大神器我似乎觉得几乎所有的NET程序破解都不在话下了.而我竟然在发现这神器组合后推迟了一周才分享与大家! 在开始分享之前,还是要说明一点,说是神器到目前为止也仅仅是对我自己而言,至于这四大神器会不会成为对各位而言的神器就不得而言了,因此当有哪位亲拿到这四大神器后仍然感到破解NET程序存在很大困难,请拍砖. 先介绍一下我眼中的四大神器:De4D

让程序猿不再苦逼的四大神器

做程序猿「媛」是一个苦逼的活,大周六地早起在技术群里招呼.看到没有啥人响应,说了一句.「预计都没有醒」.然后一位哥们抛过来,「在加班」 ! 做 Web 开发更是一个苦逼的活.不像是做 iOS,搞定client.基本上就万事大吉了. 做 Web 开发不仅仅是要做后端.前端也须要了解和熟悉! 做前后端通吃的 DevOps 全栈project师绝对是最苦逼的活,不但须要做开发,而且还要了解运维.优化.不会运维的project师绝对不是一个好架构师. 但所幸的事.一个优秀的project师虽然非常忙,虽

net程序破解神器

本帖最后由 Pnmker 于 2012-12-2 05:19 编辑 原本这篇文章可以更早一星期写出来与大家分享,由于某方面的原因耽搁到现在,心里竟有那么一点好像对不住大家的感觉.这当然与神器有关,因为我发现利用这 四大神器我似乎觉得几乎所有的NET程序破解都不在话下了.而我竟然在发现这神器组合后推迟了一周才分享与大家! 在开始分享之前,还是要说明一点,说是神器到目前为止也仅仅是对我自己而言,至于这四大神器会不会成为对各位而言的神器就不得而言了,因此当有哪位亲拿到这四大神器后仍然感到破解NET程序

springboot之启动原理解析及源码阅读

原文地址:https://www.cnblogs.com/shamo89/p/8184960.html 正文 我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication //Annotation(注解)定义了(@SpringBootApplication) public class Application { public static void main(String[] args) { //类定义(SpringApplication.run

springboot工作原理

SpringBoot为我们做的自动配置,确实方便快捷,但一直搞不明白它的内部启动原理,这次就来一步步解开SpringBoot的神秘面纱,让它不再神秘. @SpringBootApplication   public class Application {   public static void main(String[] args) {   SpringApplication.run(Application.class, args);   }   } 从上面代码可以看出,Annotation定

移动端页面性能探究

一.背景: 智能终端的普及改变了人们对互联网的使用习惯,终端环境对页面性能有更高的要求,接下来以一张图来分析:1s内渲染一个移动页面 网络整体消耗来分析: 1.服务器响应应该小于200ms 2.尽量少的重定向 3.尽量少的第一次渲染的请求 4.避免过多堵塞的js和css堵塞 js执行效率和渲染效率: 1.给浏览器留的200ms渲染时间 2.优化我们的js执行效率和渲染时间 二.主要的web性能优化 页面请求:DNS Lookup.减少重定向.并行请求.压缩.缓存.按需加载.前端模块化 运行环境:

让运维工程师不再蓝瘦、香菇

最近广西一小哥失恋后录的视频风靡互联网,也让"蓝瘦.香菇"这两个词火了一把.虽然原故事男主角是因为失恋才蓝瘦.香菇,但想想作为运维"狗"的我们也时常因强大的工作压力而蓝瘦,常常在晚上睡得香呼呼的时候因为要处理故障从温暖的被窝爬起来,看着铝朋友鄙视的眼神,真的好香菇--本来作为技术大牛的我们,工作应该是很酷的事情,享受的应该是小白美铝们崇拜的眼神,可现在却那么苦逼,天天被应用上线.系统巡检.故障排除这些琐事缠身,想想都蓝瘦!我们怎么样才能重获崇拜,有更多的时间陪伴家人

.net 逆向工具

做xdctf的时候,遇到一个.net逆向,自己根本没学过.net,用reflector打开后直接看不懂,放弃. 现在看了下writeup,知道了之所以看不懂是因为加壳了.所以,下意识了解下.net下应用程序的逆向的基础工具.在这里将一篇文章中讲的东西粘贴过来,记录一下. 转自:http://www.52pojie.cn/thread-174802-1-1.html 先介绍一下我眼中的四大神器:De4Dot.Reflector.Reflexil以及DILE.其中 De4Dot是一个开源的脱壳/反混