※ 学习目标
一、什么是反射?
反射就是:加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)
二、学什么?
- 反射的第一步:加载类,获取类的字节码:
class对象
- 获取类的构造器:
Constructor对象
- 获取类的成员变量:
Field对象
- 获取类的成员方法:
Method对象
2.1 获取类的字节码:class对象
方法 | 说明 |
---|
c1.getName() | 全类名 |
c1.getSimpleName() | 简名 |
获取Class对象的三种方式:
Class c1 = 类名.class
- 调用Class提供的方法:
public static Class forName(String package)
- 调用Object提供的方法:
public Class getClass();
Class c3 = 对象.getClass
public class Test1Class {
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = Student.class;
System.out.println(c1.getName());
System.out.println(c1.getSimpleName());
Class c2 = Class.forName("com.ming.reflect.Student");
System.out.println(c1 == c2);
Student student = new Student();
Class c3 = student.getClass();
System.out.println(c3 == c2);
}
}
2.2 获取类的构造器:Constructor对象
作用:初始化对象并返回
注意:反射是可以破坏封装性的。
构造器 | 说明 |
---|
Constructor<?>[] getConstructors() | 获取全部构造器(只能获取public修饰的) |
Constructor<?>[] getDeclaredConstructors() | 获取全部构造器(只要存在就能拿到)【推荐使用】 |
Constructor getConstructor(Class<?>… parameterTypes) | 获取某个构造器(只能获取public修饰的) |
Constructor getDeclaredConstructor(Class<?>… parameterTypes) | 获取某个构造器(只要存在就能拿到)【推荐使用】 |
方法 | 说明 |
---|
constructor.getName() | 构造器名称 |
constructor.getParameterCount() | 构造器参数个数 |
T newInstance(Object… initargs) | 调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回 |
public void setAccessible(boolean flag) | 设置为True,表示禁止检查访问控制(暴力反射)破坏封装性 |
public class Test2Constructor {
@Test
public void testGetConstructors() {
Class catClass = Cat.class;
Constructor[] constructors = catClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.getName());
System.out.println(constructor.getParameterCount());
}
}
@Test
public void testGetDeclaredConstructors() {
Class catClass = Cat.class;
Constructor[] constructors = catClass.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.getName());
System.out.println(constructor.getParameterCount());
}
}
@Test
public void testGetConstructor() throws NoSuchMethodException {
Class catClass = Cat.class;
Constructor constructor = catClass.getConstructor(String.class, int.class);
System.out.println(constructor.getName());
System.out.println(constructor.getParameterCount());
}
@Test
public void testGetDeclaredConstructor() throws NoSuchMethodException {
Class catClass = Cat.class;
Constructor constructor = catClass.getDeclaredConstructor(String.class, int.class);
System.out.println(constructor.getName());
System.out.println(constructor.getParameterCount());
}
@Test
public void testNewInstance() throws Exception {
Class catClass = Cat.class;
Constructor constructor1 = catClass.getDeclaredConstructor();
Constructor constructor2 = catClass.getDeclaredConstructor(String.class, int.class);
Cat cat1 = (Cat) constructor1.newInstance();
Cat cat2 = (Cat) constructor2.newInstance("小花", 5);
System.out.println(cat1);
System.out.println(cat2);
}
@Test
public void testSetAccessible() throws Exception{
Class catClass = Cat.class;
Constructor constructor1 = catClass.getDeclaredConstructor();
Constructor constructor2 = catClass.getDeclaredConstructor(String.class, int.class);
constructor1.setAccessible(true);
constructor2.setAccessible(true);
Cat cat1 = (Cat) constructor1.newInstance();
Cat cat2 = (Cat) constructor2.newInstance("小花", 5);
System.out.println(cat1);
System.out.println(cat2);
}
}
public class Cat {
private String name;
private int age;
private Cat() {
}
public Cat(String name, int age) {
this.name = name;
this.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;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2.3 获取类的成员变量:Field对象
作用:赋值、取值
构造器 | 说明 |
---|
public Field[] getFields() | 获取类的全部成员变量【只能获取public修饰的】 |
public Field[] getDeclaredFields() | 获取类的全部成员变量【只要存在就能拿到】 |
public Field getField(String name) | 获取类的某个成员变量【只能获取public修饰的】 |
public Field getDeclaredField(String name) | 获取类的某个成员变量【只要存在就能拿到】 |
方法 | 说明 |
---|
field.getName() | 成员变量的名字 |
field.getType() | 成员变量的类型 |
void set(Object obj, Object value) | 赋值 |
Object get(Object obj) | 取值 |
public void setAccessible(boolean flag) | 设置为True,表示禁止检查访问控制(暴力反射) |
public class Test3Field {
@Test
public void testGetFields() {
Class catClass = Cat.class;
Field[] fields = catClass.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
System.out.println(field.getType());
}
}
@Test
public void testGetField() throws Exception {
Class catClass = Cat.class;
Field fieldAge = catClass.getDeclaredField("age");
fieldAge.setAccessible(true);
System.out.println(fieldAge.getName());
System.out.println(fieldAge.getType());
Cat cat = new Cat("小花", 22);
fieldAge.set(cat, 100);
System.out.println(cat);
System.out.println(fieldAge.get(cat));
}
}
2.4 获取类的成员方法:Method对象
作用:执行方法
构造器 | 方法 |
---|
Method[] getMethods() | 获取类的全部成员方法(只能获取public修饰的) |
Method[] getDeclaredMethods() | 获取类的全部成员方法(只要存在就能拿到) |
Method getMethod(String name, Class<?>… parameterTypes) | 获取类的某个成员方法(只能获取public修饰的) |
Method getDeclaredMethod(String name, Class<?>… parameterTypes) | 获取类的某个成员方法(只要存在就能拿到) |
方法 | 说明 |
---|
public Object invoke(Object obj, Object… args) | 触发某个对象的该方法执行 |
public void setAccessible(boolean flag) | 设置为true,表示禁止检查访问控制(暴力反射) |
method.getName() | 获取成员方法的名称 |
method.getParameterCount() | 获取成员方法参数个数 |
method.getReturnType() | 获取成员方法返回值类型 |
public class Test4Method {
@Test
public void getMethods() {
Class catClass = Cat.class;
Method[] methods = catClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
System.out.println(method.getParameterCount());
System.out.println(method.getReturnType());
System.out.println("---------------------------------");
}
}
@Test
public void getMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class catClass = Cat.class;
Method method = catClass.getDeclaredMethod("eat", String.class);
System.out.println(method.getName());
System.out.println(method.getParameterCount());
System.out.println(method.getReturnType());
method.setAccessible(true);
Cat cat = new Cat("张三", 22);
Object invoke = method.invoke(cat, "123");
System.out.println(invoke);
}
}
3. 反射的作用以及应用场景
- 基本作用:可以得到一个类的全部成分然后操作。
- 可以破坏封装性。
最重要的用途是:适合做Java的框架,基本上,主流的框架都会基于反射设计出一些通用的功能
3.1 案例
对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去.
- 定义一个方法,可以接收任意对象。
- 没收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量。
- 遍历成员变量,然后提取成员变量在该对象中的具体的值。
- 把成员变量名和值写入文件中
public class Test5 {
@Test
public void save() throws Exception {
Student student = new Student("张三", 22, '男', 180.0, "读书");
Teacher teacher = new Teacher("阿旧", 999.9);
ObjectFrame.saveObject(student);
ObjectFrame.saveObject(teacher);
}
}
public class ObjectFrame {
public static void saveObject(Object obj) throws Exception {
PrintStream printStream = new PrintStream(new FileOutputStream("D:\\repo\\javasepro\\networkCommunication\\src\\com\\ming\\reflect\\data.txt", true));
Class objClass = obj.getClass();
String simpleName = objClass.getSimpleName();
printStream.println("------------ " + simpleName + " ------------");
Field[] fields = objClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String name = field.getName();
String value = String.valueOf(field.get(obj));
printStream.println(name + "=" + value);
}
}
}