反 射
Posted penguin1024
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反 射相关的知识,希望对你有一定的参考价值。
一.概述
反射的学习,是便于能更好的理解框架编程。 目前主流的框架技术底层都是反射的机制,如:struts、spring、hibernate等
反射本质上就是一种动态编程的技术,可以在运行阶段动态地创建对象以及动态地调用方法,具体由实参决定。
引出:
若想在写代码的时候,不能确定需要创建Person对象 还是 Student对象。而是希望程序到了运行阶段,能够自行动态地决定创建具体的那个所需对象。
那么此时,就需要用到反射技术!
如:
Person p = new Person(); - 只能创建Person类型的对象。
Student s = new Student(); - 只能创建Student类型的对象。
void show(){ }
void show(int i){ }
void show(double d){ }
如何使用 反射 ?
要用反射技术,需要借助一个类: Java.lang.Class 类
二,Class 类
1、基本概念
java.lang.Class类的实例代表应用程序的类和接口,通俗来说,就是该类的实例代表一种数据类型。
(不是内存空间中堆区中普通对象的一块内存空间)
区别于: Person p =new Person();
Person的一个实例, 代表的是 堆区中的一块内存空间。 而java.lang.Class类的实例代表一种数据类型。
该类没有公共的构造方法(自个不能new这个类的对象),
class对象是在加载类的时候,由Java虚拟机,以及通过调用类加载器中的defineClass( )方法自动构造的。【构造出来即代表一种数据类型】
那么要想使用Class这个类,则需要得到该类的引用!
如何获取该类的引用?
2.Class对象的获取方式(4种)
a. 使用 数据类型.class 的方式可以获取该类型的Class对象。(引用数据类型,基本数据类型都适用)
b. 使用 对象.getClass() 的方式可以获取该类型的Class对象。(只适用于引用数据类型)
【万物皆对象。所以,任何一个类都可以用 对象.getClass()方法区获取 它的class对象】
c. 使用 包装类的TYPE属性 获取该包装类对应基本数据类型的Class对象。
d.使用Class类的 forName() 方法获取参数类型的Class对象。 【forName()中,包名 不能省略】 (底层框架中,这种方式最常用)
基本数据类型 获取class对象的途径3种:a c d
引用数据类型 获取class对象的途径3种:a b d
代码测试:ClassObjectTest .java
package com.moneky1024; public class ClassObjectTest { public static void main(String[] args) throws ClassNotFoundException { //1.使用数据类型.class的方式来获取该类型的Class对象 //class java.lang.String System.out.println(String.class);//自动调用toString()方法 System.out.println(int.class); //int System.out.println(void.class); //void System.out.println(); //2.使用对象.getClass()的方式来获取该类型的Class对象 String s1 = new String("GoodMorning"); System.out.println(s1.getClass());//class java.lang.String Integer it1 = new Integer(66); System.out.println(it1.getClass());//class java.lang.Integer //int num = 118; //System.out.println(num.getClass()); error System.out.println(); //3.使用包装类的TYPE属性来获取基本数据类型的Class对象 System.out.println(Integer.TYPE); // int System.out.println(Integer.class);//class java.lang.Integer System.out.println(); //4.使用Class类的forName()方法获取Class对象 //class java.lang.String System.out.println(Class.forName("java.lang.String")); //System.out.println(Class.forName("int")); error } }
常用方法:
static Class forName(String className) - 获取参数指定类型的Class对象。
T newInstance( ) - 根据Class对象创建新实例。
Method getMethod(String name, Class... parameterTypes) - 用于获取对应类中指定的公共成员方法。
Constructor<T> getConstructor(Class<?>... parameterTypes) - 用于获取当前Class对象对应类中指定的公共构造方法。 (获取单个)
Constructor<?>[ ] getConstructors( ) - 获取对应类中所有的公共构造方法。 (获取多个,数组接收)
Field getDeclaredField(String name) - 获取对应类中指定的成员变量。
Field[ ] getDeclaredFields() - 获取对应类中所有的成员变量。
Method[ ] getMethods() - 用于获取对应类中所有的公共成员方法。
代码:
package com.moneky1024; public class Person { private String name; private int age; public Person() { super(); } public Person(String name, int age) { super(); setName(name); setAge(age); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } 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; } }
测试类:
package com.moneky1024; import java.lang.reflect.Constructor; public class Test { public static void main(String[] args) throws Exception { //1.创建Person类型的对象 Person p = new Person(); //调用无参构造方法 System.out.println(p); //null 0 System.out.println(); //2.获取Person类的Class对象并创建实例打印 null 0 System.out.println(Class.forName("xdl.day21.Person").newInstance()); System.out.println(); Person p2 = new Person("zhangfei", 30); System.out.println(p2); //zhangfei 30 System.out.println(); //1.获取Class对象,使用forName()方法 Class c1 = Class.forName("xdl.day21.Person"); //2.获取对应类中的构造方法,形参类型分别为:String 和 int Constructor cs1 = c1.getConstructor(String.class, int.class); //3.调用该构造方法创建新实例,并指定初始值,打印新实例的结果 System.out.println(cs1.newInstance("guanyu", 35));//guanyu 35 } }
结果:
class java.lang.String int void class java.lang.String class java.lang.Integer int class java.lang.Integer class java.lang.String
解析代码:
public Person(String name, int age) { super(); setName(name); setAge(age); }
Person类中的形参类型分别为: String 和 int 。
而在getConstructor(Class<?>...parameterTypes) 中 参数要的是 class类型
Constructor cs1 = c1.getConstructor(String.class, int.class);
即,getConstructor(String.class, int.class);
提出问题:
在class这个类中,提供了 无参的构造 形式。但是没有 提供 有参的构造形式 去创建新实例,那如果 想创建有参的对象,怎么办?
1、利用Class类中提供的 getConstructor( )方法;
它的作用: 获取括号中填写参数,指定的类的构造方法的信息。 拿出来后,封装到 Constructor <T> 类里面。
即, Constructor 类的对象,专门代表获取的构造方法。
2、获取到构造方法后,需要再借助一个 newInstance( )方法 :
调用 newInstance()的对象,使用 之前获取到的 构造方法 去构造这个新实例。
三、 Constructor类
java.lang.reflect.Constructor类 用于描述获取到的构造方法。T newInstance(Object... initargs) - 调用当前描述的构造方法去创建新实例。
四、Field类
常用方法:
Object get(Object obj) - 用于获取指定对象中此成员变量的数值。
void setAccessible(boolean flag) - 参数为true表示可以访问私有成员。
void set(Object obj, Object value) - 用于修改指定对象中当前成员变量的数值。
代码:
先编写一个Person.java类 (同上)
FieldTest.java类测试:
package com.monkey1024; import java.lang.reflect.Field; public class FieldTest { public static void main(String[] args) throws Exception{ //1.获取Class对象括号中 是 包名+类名 Class<?> c1 = Class.forName("com.monkey1024.Person"); //2.创建一个Person类型的对象,并传递实参 //为了得到对应的构造方法 // 传参 Person p = (Person) c1.getConstructor(String.class,int.class).newInstance("zhangfei", 30); //3.获取对应类中指定的成员变量 Field f1 = c1.getDeclaredField("name"); //提供 指定的成员变量 名,获得该指定的变量 //4.设置可以访问私有成员变量 f1.setAccessible(true); //若这行代码没有,则私有变量 不能被成功访问 //5.获取指定对象中此成员变量的数值并打印出来 System.out.println(f1.get(p)); // zhangfei f1.get(p)表示 去这个p对象中,找到名字为 name 的成员变量,并返回 这个变量 //6.修改指定对象中此成员变量的数值修改为"guanyu" f1.set(p, "guanyu"); System.out.println(f1.get(p)); // guanyu } }
结果:
zhangfei
guanyu
五、Method类
java.lang.reflect.Method类 用于描述获取到的成员方法。
常用方法:
Object invoke(Object obj, Object... args) - 用于obj对象调用当前方法,并传递args作为实参。
代码:
package com.monkey1024; import java.lang.reflect.Method; public class MethodTest { public static void main(String[] args) throws Exception { //1.获取Class对象 Class c1 = Class.forName("com.monkey1024.Person"); //2.使用有参构造方法创建该类的实例 Person p = (Person) c1.getConstructor(String.class, int.class).newInstance("zhangfei", 30); //3.获取对应类中指定的成员方法 Method m1 = c1.getMethod("toString"); //4.使用该对象调用此方法,并打印结果 System.out.println(m1.invoke(p));// zhangfei 30 } }
结果:
Person [name=zhangfei, age=30]
以上是关于反 射的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 创建反汇编解析器实例对象 | 设置汇编解析器显示细节 )(代码片段