反射
什么是反射
获取运行时类信息的手段
反射技术的起点就是获取字节码文件对象
获取字节码文件对象的几种方式
- 对象.getClass()
- 类名.class
- Class.forName(全类名)
- ClassLoader.loadClass(全类名)
无论通过何种方式获取到的字节码文件对象 , 都是同有一个
配置文件(.properties)
配置文件里面放的是什么? 一般放的就是配置信息, 数据库的配置信息, 第三方服务的配置信息
格式
键值对(key-value) key = value
- 注释使用的是#
- key不能重复
Properties
Properties
类表示了一个持久的属性集。Properties
可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
构造方法
Properties() 创建一个无默认值的空属性列表。
成员方法
void | load(InputStream inStream) 从输入流中读取属性列表(键和元素对)。 |
---|---|
void | load(Reader reader) 按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。 |
String | getProperty(String key) 用指定的键在此属性列表中搜索属性。 |
---|
通过反射获取构造方法(Constructor)
通过反射获取所有构造方法
Constructor[] getConstructors()
Constructor[] getDeclaredConstructors()
获取指定构造方法
Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
使用Constructor创建对象
Person p = new Person("zs",20,true)
newInstance(参数列表)
暴力破解权限限制
setAccessible(true)
/*
获取构造方法
*/
public class ConstructorTest {
public static void main(String[] args) throws Exception{
// 反射技术的起点获取字节码文件对象
Class<?> personCls = Class.forName("_23reflect.com.cskaoyan.bean.Person");
// 获取所有的public的构造方法
System.out.println("获取所有的public的构造方法");
// Constructor[] getConstructors()
Constructor<?>[] constructors = personCls.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("获取所有的构造方法");
//Constructor[] getDeclaredConstructors()
Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
for (Constructor constructor : declaredConstructors) {
System.out.println(constructor);
}
System.out.println("获取指定的public的构造方法---------");
// Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor<?> constructor = personCls.getConstructor(String.class, int.class);
System.out.println(constructor);
System.out.println("获取指定的构造方法---------");
//Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
Constructor<?> declaredConstructor =
personCls.getDeclaredConstructor(String.class, int.class, boolean.class);
System.out.println(declaredConstructor);
// 通过构造方法实例化对象
// newInstance(参数)
Object o = constructor.newInstance("zs", 20);
System.out.println(o);
// 暴力破解
// setAccessible(true) 忽略java语法检查
declaredConstructor.setAccessible(true);
Object o1 = declaredConstructor.newInstance("ls", 22, true);
System.out.println(o1);
}
}
通过反射获取成员变量(Field)
通过反射获取所有成员变量
Field[] getFields()
Field[] getDeclaredFields()
获取指定成员变量
Field getField(String name)
Field getDeclaredField(String name)
通过Field读写对象的成员变量(可暴力破解)
Object get(Object obj):获取值,传入对象
void set(Object obj, Object value):赋值,传入对象
public class FieldTest {
public static void main(String[] args) throws Exception{
// 获取字节码文件对象
Class<?> personCls = Class.forName("_23reflect.com.cskaoyan.bean.Person");
System.out.println("获取所有的public的成员变量-------");
// Field[] getFields()
Field[] fields = personCls.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("获取所有的成员变量-------");
//Field[] getDeclaredFields()
Field[] declaredFields = personCls.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field);
}
System.out.println("获取指定的public成员变量-------");
// Field getField(String name)
Field nameField = personCls.getField("name");
System.out.println(nameField);
System.out.println("获取指定成员变量-------");
//Field getDeclaredField(String name)
Field ageField = personCls.getDeclaredField("age");
System.out.println(ageField);
// 需要一个对象
Constructor<?> declaredConstructor = personCls.getDeclaredConstructor();
Object o = declaredConstructor.newInstance();
// set()给成员变量设置值
nameField.set(o, "zs");
System.out.println(o);
// get() 获取成员变量的值
System.out.println(nameField.get(o));
ageField.setAccessible(true);
ageField.set(o, 20);
System.out.println(o);
}
}
通过反射获取成员方法(Method)
获取所有成员方法
Method[] getMethods()
Method[] getDeclaredMethods()
获取指定的成员方法
Method getMethod(String name, Class<?>... parameterTypes)
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
利用Method调用对象的方法
Object invoke(Object obj, Object... args)
public class MethodTest {
public static void main(String[] args) throws Exception{
// 获取字节码文件对象
Class<?> personCls = Class.forName("_23reflect.com.cskaoyan.bean.Person");
System.out.println("获取所有的public的成员方法");
//Method[] getMethods()
Method[] methods = personCls.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("获取所有的成员方法-----------------");
Method[] declaredMethods = personCls.getDeclaredMethods();
//Method[] getDeclaredMethods()
for (Method method : declaredMethods) {
System.out.println(method);
}
System.out.println("获取指定的public的成员方法");
// Method getMethod(String name, Class<?>... parameterTypes)
Method eatMethod = personCls.getMethod("eat");
System.out.println(eatMethod);
System.out.println("获取指定的成员方法");
//Method getDeclaredMethod(String name, Class<?>... parameterTypes)
Method eatMethod2 = personCls.getDeclaredMethod("eat", String.class);
System.out.println(eatMethod2);
// 创建Person对象
Constructor<?> declaredConstructor = personCls.getDeclaredConstructor();
Object o = declaredConstructor.newInstance();
// invoke()
eatMethod.invoke(o);
eatMethod2.setAccessible(true);
eatMethod2.invoke(o, "apple");
}
}
补充
其他API
/*
补充其他API
*/
public class Demo2 {
public static void main(String[] args) throws Exception{
Class<?> personCls = Class.forName("_23reflect.com.cskaoyan.bean.Person");
//Class<?> personCls = Class.forName("java.io.OutputStream");
// 获取类名
String name = personCls.getName();
System.out.println(name);
// 获取简单名
System.out.println(personCls.getSimpleName());
// 获取父类
Class<?> superclass = personCls.getSuperclass();
System.out.println(superclass.getSimpleName());
// 获取接口信息
Class<?>[] interfaces = personCls.getInterfaces();
for (Class<?> i : interfaces) {
System.out.println(i);
}
// 获取成员变量
Field nameFiled = personCls.getDeclaredField("name");
// 获取权限修饰符
int modifiers = nameFiled.getModifiers();
System.out.println(modifiers);
// static String toString(int mod)
// 返回描述指定修饰符中的访问修饰符标志的字符串
String s = Modifier.toString(modifiers);
System.out.println(s);
// 获取成员变量类型
System.out.println(nameFiled.getType());
// 获取方法对象
Method eatMethod = personCls.getDeclaredMethod("eat");
System.out.println(eatMethod.getReturnType().getSimpleName());
}
}
小练习
1.设计一个方法如下,要求该方法能修改任意对象中,指定成员变量的值
import java.lang.reflect.Field;
/*
@param targetObj 要修改成员变量值的目标对象
@param fieldName 对象中要修改的成员变量的名字
@param newValue 要修改成员变量值的新值*/
public class Demo {
public static void setAll(Object targetObj, String fieldName, Object newValue) throws Exception {
//创建要修改成员变量值的目标对象的字节码文件对象
Class<?> targetObjClass = targetObj.getClass();
//通过反射获取对象中要修改的成员变量
Field nameField = targetObjClass.getDeclaredField(fieldName);
//解决权限问题,让jvm绕过权限检查机制
nameField.setAccessible(true);
//在指定对象上修改成员变量值的新值
nameField.set(targetObj, newValue);
}
}
2.使用反射机制完成学生对象的创建并输出学生信息。
要求:
(1)定义一个学生类Student,其中包含姓名(String)、年龄(int)、成绩(int)的属性。
(2)编写带参与无参构造方法。
(3)重写父类的toString()方法用于输出学生的信息。
(4)编写测试类TestStudent,从键盘录入学生的信息格式为(姓名:年龄:成绩)一次性录入使用“:”分隔,举例(张三:20:90)。
(5)使用String类的split方法按照“:”进行分隔。
(6)调用Constructor的newInstance()方法并用分隔后的信息初始化学生对象。
(7)调用重写父类的toString()方法将学生信息进入输出显示。
public class Student {
String name;
int age;
int score;
public Student() {
}
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
import java.lang.reflect.Constructor;
import java.util.Scanner;
public class TestStudent {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
String student = sc.nextLine();
String[] strings = student.split(":");
//反射技术的起点获取字节码对象
Class<?> studentCls = Class.forName("second_day._01exercise.Student");
//获取指定的public构造方法
Constructor<?> constructor = studentCls.getConstructor(String.class, int.class, int.class);
//通过构造方法实例化对象
//解决权限问题,让jvm绕过权限检查机制
constructor.setAccessible(true);
Student o = (Student) constructor.newInstance(strings[0], Integer.parseInt(strings[1]), Integer.parseInt(strings[2]));
System.out.println(o.toString());
}
}