反射
- 反射就是:加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)
反射学什么?
学习获取类的信息、操作它们
- 反射第一步:加载类,获取类的字节码:Class对象
- 获取类的构造器:Constructor对象
- 获取类的成员变量:Field对象
- 获取类的成员方法:Method对象
全部认识完后,再看反射的应用场景
1、反射第一步:加载类,获取类的字节码:Class对象
获取Class对象的三种方式
- Class c1=类名.class
- 调用Class提供方法: public static Class forName(String package)
- Object提供的方法: publicClass getClass(); Class c3=对象.getClass()
代码演示:
package com.zeyu.reflect;
public class Test1Class {
public static void main(String[] args) throws Exception {
Class c1 = Student.class;
System.out.println(c1.getName()); //全类名
System.out.println(c1.getSimpleName()); //简名:Student
Class c2 = Class.forName("com.zeyu.reflect.Student"); //填全类名
System.out.println(c1 == c2); //拿到的是同一个对象
Student s = new Student(); //创建类的实例
Class c3 = s.getClass(); //调用getClass方法
System.out.println(c3 == c2); //拿到的依旧是同一个对象
}
}
运行结果:
2、获取类的构造器:Constructor对象
Class提供了从类中获取构造器的方法
获取类构造器的作用:依然是初始化对象返回
代码演示:
package com.zeyu.reflect;
import org.junit.Test;
import java.lang.reflect.Constructor;
public class Test2Constructor {
@Test
public void testGetConstructors() {
//1、反射第一步,必须先得到这个类的class对象
Class c = Cat.class;
//2、获取类的全部构造器
// Constructor[] constructors = c.getConstructors(); //只能拿public类型的构造器
Constructor[] constructors = c.getDeclaredConstructors();
//3、遍历数组中的每一个构造器对象
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "-->" + constructor.getParameterCount());
}
}
@Test
public void testGetConstructor() throws Exception {
//1、反射第一步,必须先得到这个类的class对象
Class c = Cat.class;
//2、获取某一个构造器:无参构造器
// Constructor constructor = c.getConstructor(); //只能拿public类型的构造器
Constructor constructor = c.getDeclaredConstructor(); //存在就能拿到
System.out.println(constructor.getName() + "-->" + constructor.getParameterCount());
constructor.setAccessible(true); //禁止检查访问权限
Cat cat = (Cat) constructor.newInstance(); //调用构造器完成对象初始化
System.out.println(cat);
//获取有参构造器
Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class);
System.out.println(constructor2.getName() + "-->" + constructor2.getParameterCount());
constructor2.setAccessible(true);
Object cat2 = constructor2.newInstance("黑猫警长", 3); //初始化对象
System.out.println(cat2);
}
}
运行结果:
也可以用反射破坏单例设计模式
3、获取类的成员变量:Field对象
Class提供了从类中获取成员变量的方法
获取到成员变量的作用:依然是赋值、取值
代码演示:
package com.zeyu.reflect;
import org.junit.Test;
import java.lang.reflect.Field;
public class Test3Field {
@Test
public void testGetFields() throws Exception {
//反射第一步,必须先拿到类的class对象
Class c = Cat.class;
//获取类的全部成员变量
Field[] fields = c.getDeclaredFields();
//遍历这个成员变量数组
for (Field field : fields) {
System.out.println(field.getName() + "--->" + field.getType());
}
//拿到某个成员变量
Field fName = c.getDeclaredField("name");
System.out.println(fName.getName() + "--->" + fName.getType());
Field fAge = c.getDeclaredField("age");
System.out.println(fAge.getName() + "--->" + fAge.getType());
//赋值
Cat cat = new Cat();
fName.setAccessible(true); //暴力访问
fName.set(cat,"小橘");
System.out.println(cat);
//取值
String name = (String) fName.get(cat);
System.out.println(name);
}
}
运行结果:
4、获取类的成员方法:Method对象
Class提供了从类中获取成员方法的API
成员方法的作用:依然是执行
代码演示:
package com.zeyu.reflect;
import org.junit.Test;
import java.lang.reflect.Method;
public class Test4Methods {
@Test
public void TestGetMethods() throws Exception {
//1、反射第一步,先得到类的class对象
Class c = Cat.class;
//2、获取类的全部成员方法
Method[] methods = c.getDeclaredMethods();
//3、遍历这个数组的每个方法对象
for (Method method : methods) { //getParameterCount()统计形参个数
System.out.println(method.getName() + "--->" + method.getParameterCount() + "--->"
+ method.getReturnType());
}
//4、获取某个方法对象
Method run = c.getDeclaredMethod("run");
System.out.println(run.getName() + "--->" + run.getParameterCount() + "--->"
+ run.getReturnType());
Method eat = c.getDeclaredMethod("eat", String.class);
System.out.println(eat.getName() + "--->" + eat.getParameterCount() + "--->"
+ eat.getReturnType());
Cat cat = new Cat();
run.setAccessible(true); //禁止检查访问权限
Object rs = run.invoke(cat);//调用无参run方法,用cat对象调用
System.out.println(rs); //无返回值,返回结果为空
eat.setAccessible(true);
Object rs2 = (String) eat.invoke(cat, "鱼");
System.out.println(rs2);
}
}
运行结果:
反射的作用?
- 基本作用:可以得到一个类的全部成分然后操作
- 可以破坏封装性
- 最重要的用途是:适合做lava的框架,基本上,丰流的框架都会基于反射设计出一些通用的功能
案例:使用反射做一个简易版的框架
需求:
对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去
实现步骤
- 定义一个方法,可以接收任意对象
- 每收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量
- 遍历成员变量,然后提取成员变量在该对象中的具体值
- 把成员变量名、和其值,写出到文件中去即可
代码演示:
实现类:
package com.zeyu.reflect;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
public class ObjectFrame {
//保存任意对象的字段和数据到文件中去
public static void saveObject(Object obj) throws Exception {
PrintStream ps = new PrintStream(new FileOutputStream("src\\com\\zeyu\\reflect\\data.txt",true));
//obj是任意对象,到底有多少字段需要保存
Class c = obj.getClass();
String cname = c.getSimpleName();
ps.println("------------------" + cname + "------------------");
//从这个类中提取它的全部成员变量
Field[] fields = c.getDeclaredFields();
//遍历每个成员变量
for (Field field : fields) {
field.setAccessible(true);
//拿到成员变量的名字
String name = field.getName();
//拿到这个成员变量在对象中的数据
String value = field.get(obj) + "";
ps.println(name + "=" + value);
}
ps.close();
}
}
测试类:
package com.zeyu.reflect;
import org.junit.Test;
public class Teat5ObjectFrame {
@Test
public void testSave() throws Exception {
Cat cat = new Cat("小橘",2);
Student s = new Student("小明","男",22,172.8);
ObjectFrame.saveObject(cat);
ObjectFrame.saveObject(s);
}
}
运行结果: