四大神器之反射

Java反射机制,是一个基础的内容章节,在对于以后的框架学习中起到了相当重要的做用,如今比较流行的是springjava

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

instrument(插桩)或者是CGLIB 。app

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

 

于任意一个对象,可否调用它任意一个方法?学习

 

答案是确定的。能够!this

 

在这里要去区别一个事情:若是说在本身写的类中去改一个数据类型或者说属性,那只是在编译时,并非在运行spa

 

时。命令行

 

反射机制的几大功能:代理

 

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

 

通常而言:程序运行时,容许改变程序结构和变量类型成为动态语言。因而可知Java并非动态语言,可是Java有一code

 

个动态相关的机制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输入进去,咱们能够看到以下图片

 

结果.jpg

 

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

 

的让咱们知道,在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方法的参数所写的类型一致,下面咱们来看一下结

 

果:

Snipaste_2020-01-10_11-55-11.jpg

 

咱们经过这个例子,就能够发现,经过反射机制咱们彻底能够调用一个方法。

 

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

 

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();若是没有无参构造器时,则可运用这个方法

Snipaste_2020-01-10_11-59-09.jpg

相关文章
相关标签/搜索