1.反射
- 为什么需要反射
在不修改源码的情况下,控制程序
在不知道类结构信息的情况下,也可以获取类的结构信息,方便后续的hook
可以突破访问修饰符的限制 反射入门
加载类
得到方法对象
调用方法,如果是实例方法,还需要创建一个实例import java.lang.reflect.Method;
public class Hello {
public static void main(String[] args) throws Exception{
String class_test= "class_test";
String MethodNaMe="b";
Class<?> cls = Class.forName(class_test);//找到一个类
Method method = cls.getMethod(MethodNaMe);//找到一个方法
method.invoke(null);//执行方法;static方法可以使用null;其他的后续补充
}}
class class_test{
public static int b() {
System.out.println("测试文本1");
return 0;
}
public int age =0;
public class_test(int age) {
System.out.println("测试文本2222");
this.age = age;
}
}
2.Class类
Class也是类,因此也继承Object类(接口没有继承Object)
- Class类对象是通过ClassLoader的loadClass加载的
- Class类对象只加载一次,除非ClassLoader不一样(具体看代码)
- 通过Class可以完整地得到一个类的完整结构,通过一系列API
Class对象是存放在堆的,类的字节码二进制数据,是放在方法区的,有的也称为类的元数据(包括方法代码, 变量名,方法名,访问权限等等)
import java.lang.reflect.Method;
public class Hello {
public static void main(String[] args) throws Exception{
String class_test= "class_test";
String MethodNaMe="b";
new class_test(1).b();
Class<?> cls = Class.forName(class_test);
Method method = cls.getMethod(MethodNaMe);
method.invoke(null);
/*
两种方法,如果我们执行了 new class_test(1).b();来实现b方法,
那么method.invoke(null);这种方法就不会通过ClassLoader的loadClass加载的
反之,我们没有执行第一个方法,直接执行第二个方法,那么method.invoke(null)就会通过ClassLoader的loadClass加载的
*/
}}
class class_test{
public static int b() {
System.out.println("测试文本1");
return 0;
}
public int age =0;
public class_test(int age) {
System.out.println("测试文本2222");
this.age = age;
}
}
3. Class类对象的获取方式(重点)
a) Class.forName(…)
b) 类.class 多用于参数传递
c) 对象.getClass()
d) ClassLoader.loadClass(…)
e) 基本数据类型的Class类对象获取 int.class Integer.TYPE
f) 包装类的Class类对象获取 Integer.class4.哪些有Class对象
获取内部类
public class Hello {
public static void main(String[] args) throws Exception{
System.out.println(Class.forName("class_test$demo"));//class class_test$demo
}}//Class.forName(类的全路径,极包名+类名)
class class_test{
public int age =0;
public class_test(int age) {
System.out.println("测试文本2222");
this.age = age;
}
class demo {
}
}
匿名类内部类
public class Hello {
public static void main(String[] args) throws Exception{
new demo1() {//同目录下创建一个接口
public void test(){
System.out.println("-------------------------");
};
}.test();//匿名类内部类
System.out.println(Class.forName("Hello$1"));//class Hello$1
}}
接口,数组
public class Hello {
public static void main(String[] args) throws Exception{
//同目录下创建一个接口
System.out.println("-------------------------");//匿名类内部类
System.out.println(demo1.class);//interface demo1 接口
System.out.println(Integer.class);//class java.lang.Integer 包装类
System.out.println(Void.class);//class java.lang.Void
String[] A=new String[]{"aaaa"};
String[][] A1=new String[][]{{"aaaa"}};
System.out.println(A.getClass());//class [[Ljava.lang.String;
System.out.println(String[].class);//class [[Ljava.lang.String;
System.out.println(String[][].class);//class [[Ljava.lang.String;
}}
4.反射创建对象
a) 无参构造器
b) 有参构造器
c) 私有构造器import java.lang.reflect.Constructor;
public class Hello {
public static void main(String[] args) throws Exception{
Class<?> a1 = Class.forName("test");
Object o = a1.newInstance();//newInstance调用无参构造器
System.out.println(o.getClass());
Constructor<?> constructor = a1.getConstructor(String.class, int.class);//有参构造器
constructor.newInstance("123",50);
Constructor<?> o2222 = a1.getDeclaredConstructor(String.class);//访问私有构造器
o2222.setAccessible(true);//作用:加上即可访问私有方法
o2222.newInstance("1233");
}}
class test{
public String name;
public int age;
public test() {
System.out.println("================");
}
public test(String name, int age) {
System.out.println("*****************");
this.name = name;
this.age = age;
}
private test(String name) {
System.out.println("-------------------");
this.name = name;
}
}
反射操作属性
a) 获取属性(四种)
b) 设置属性
c) 私有属性
d) 如果是静态属性,第一个参数可以给null
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class Hello {
public static void main(String[] args) throws Exception{
Class<?> a1 = Class.forName("test");
Constructor<?> o2222 = a1.getDeclaredConstructor(String.class);//访问私有构造器
o2222.setAccessible(true);//作用:加上即可访问私有方法
Object o1 = o2222.newInstance("1233");
Field Fieldname = a1.getField("name");
System.out.println(Fieldname.get(o1));//取值
Fieldname.set(o1,"修改文本");//改值
System.out.println(Fieldname.get(o1));//取值
Field Fieldsex = a1.getDeclaredField("sex");
Fieldsex.setAccessible(true);
Fieldsex.set(o1,true);
//Fieldsex.set(null,true); 静态属性的时候可以设置成为null
boolean sex = (boolean) Fieldsex.get(o1);
System.out.println(sex);
}}
class test{
public String name;
public int age;
private static boolean sex;
public test() {
System.out.println("================");
}
public test(String name, int age) {
System.out.println("*****************");
this.name = name;
this.age = age;
}
private test(String name) {
System.out.println("-------------------");
this.name = name;
}
}
- 反射操作方法
a) 获取方法(四种)
b) 调用方法
c) 私有方法
d) 如果是静态方法,第一个参数可以给null
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Hello {
public static void main(String[] args) throws Exception{
Class<?> a1 = Class.forName("test");
Constructor<?> o2222 = a1.getDeclaredConstructor(String.class);
o2222.setAccessible(true);
Object o1 = o2222.newInstance("1233");
Method test_method = a1.getMethod("test_method", String.class);
Object invoke = test_method.invoke(o1, "55555");
Method test_method_private = a1.getDeclaredMethod("test_method_private", String.class);
test_method_private.setAccessible(true);
Object invoke1 = (String)test_method_private.invoke(o1, "555");
System.out.println(invoke1);
}}
class test{
public String name;
public int age;
private static boolean sex;
public test() {
System.out.println("================");
}
public test(String name, int age) {
System.out.println("*****************");
this.name = name;
this.age = age;
}
public static String test_method(String name) {
return "2222222"+" "+name;
}
private test(String name) {
System.out.println("-------------------");
this.name = name;
}
private String test_method_private(String name) {
return "69696 "+name;
}
}
其他方法:
- java.lang.reflect.Field类
a) getModifiers: 以int形式返回修饰符
a) getType: 以Class形式返回类型
a) getName: 返回属性名 - java.lang.reflect.Method类
a) getModifiers: 以int形式返回修饰符
a) getReturnType: 以Class形式获取返回类型
a) getName: 返回方法名
a) getParameterTypes: 以Class[]返回参数类型数组 java.lang.reflect.Constructor类
a) getModifiers: 以int形式返回修饰符
a) getName: 返回构造器名(全类名)
a) getParameterTypes: 以Class[]返回参数类型数组
a) newInstanceimport java.lang.reflect.Method;
public class Hello {
public static void main(String[] args) throws Exception{
Class<?> a1 = Class.forName("test");
Method[] declaredMethods = a1.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
}}
class test{
public String name;
public int age;
private static boolean sex;
public test() {
System.out.println("================");
}
public test(String name, int age) {
System.out.println("*****************");
this.name = name;
this.age = age;
}
public static String test_method(String name) {
return "2222222"+" "+name;
}
private test(String name) {
System.out.println("-------------------");
this.name = name;
}
private String test_method_private(String name) {
return "69696 "+name;
}
private String a3333(String name) {
return "69696 "+name;
}
}