反射
大约 5 分钟约 1515 字
代理相关
为什么需要代理?
代理可以无侵入式的对方法进行增强,而不需要修改原始方法的代码,这样就可以在不修改原始方法的情况下,对方法进行增强。
代理长什么样子?
代理里面就是对象要被代理的方法
Java通过什么方式来保证代理的样子?
通过接口保证,后面的对象和代理需要实现同一个接口,接口中就是被代理的所有方法
代码演示:
- BigStar.java
public class BigStar implements Star {
private String name;
@Override
public String sing(String name) {
System.out.println(this.name + "正在唱" + name);
return name;
}
@Override
public void dance() {
System.out.println(this.name + "正在跳舞");
}
//...
}
- Star接口
public interface Star {
//把需要被代理的方法定义在接口中
String sing(String name);
void dance();
}
- 代理工具
public class ProxyUtil {
/**
* 作用:给一个明星对象创建代理
* 形参:被代理的明星对象
* 返回值:给明星创建的代理
* <p>
* 需求:外面的人需要大明星唱一首歌
*/
public static Star createProxy(BigStar bigStar) {
Star star = (Star) Proxy.newProxyInstance(
ProxyUtil.class.getClassLoader(), //参数一:类加载器
new Class[]{Star.class}, //参数二:被代理类的所有接口
//参数三:代理对象的调用处理程序
new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
/*
参数一:代理对象
参数二:被代理的方法
参数三:被代理方法的参数
*/
if ("sing".equals(method.getName())) {
System.out.println("准备话筒,收钱");
} else if ("dance".equals(method.getName())) {
System.out.println("准备舞台,收钱");
}
//执行被代理的方法
//返回被代理方法的返回值
return method.invoke(bigStar, args);
}
}
);
return star;
}
}
- 测试类
public class Test {
public static void main(String[] args) {
BigStar star = new BigStar("蔡徐坤");
Star proxy = ProxyUtil.createProxy(star);
String result = proxy.sing("只因你太美");
System.out.println(result);
}
}
反射
什么是反射?
反射允许对成员变量,成员方法和构造方法的信息进行编程访问
获取反射三种方式
public class Test {
public static void main(String[] args) throws Exception {
//第一种方式:
//最为常用的方式,通过类的全路径,获取Class对象
Class clazz = Class.forName("com.cxk.fanshe.Student");
//第二种方式,更多的是当作参数传递
Class clazz2 = Student.class;
//第三种方式
//当我们已经有了这个类的对象,才可以使用
Student student = new Student();
Class clazz3 = student.getClass();
}
}
反射获取构造方法
Declared表示私有
方法名 | 说明 |
---|---|
Constructor<?>[] getConstructors() | 获得所有的构造(只能public修饰) |
Constructor<?>[] getDeclaredConstructors() | 获得所有的构造(包含private修饰) |
Constructor getConstructor(Class<?>... parameterTypes) | 获取指定构造(只能public修饰) |
Constructor getDeclaredConstructor(Class<?>... parameterTypes) | 获取指定构造(包含private修饰) |
Demo
public class Test {
public static void main(String[] args) throws Exception {
//1.获取class字节码文件对象
Class<?> clazz = Class.forName("com.cxk.fanshe.Student");
//2.1获取所有的构造方法
Constructor[] con1 = clazz.getDeclaredConstructors();
for (Constructor constructor : con1) System.out.println(constructor);
//2.2获取指定的构造方法
Constructor con2 = clazz.getDeclaredConstructor(); //空参
Constructor con3 = clazz.getDeclaredConstructor(String.class, Integer.class); //有参
int modifiers = con3.getModifiers(); //获取权限修饰符
Parameter[] parameters = con3.getParameters();//获取参数列表
con3.setAccessible(true);//暴力反射 无视权限修饰符 这样就可以访问私有构造方法了
Student cxk =(Student) con3.newInstance("cxk", 23);//创建对象
}
}
获取成员变量
方法名 | 说明 |
---|---|
Field[] getFields() | 返回所有成员变量对象的数组(只能拿public的) |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组,存在就能拿到 |
Field getField(String name) | 返回单个成员变量对象(只能拿public的) |
Field getDeclaredField(String name) | 返回单个成员变量对象,存在就能拿到 |
Demo:
public class Test {
public static void main(String[] args) throws Exception {
//1.获取class字节码文件对象
Class clazz = Class.forName("com.cxk.fanshe.Student");
Field[] fields = clazz.getDeclaredFields();//获取成员变量 所有的
Field age = clazz.getDeclaredField("age");//获取单个的
int modifiers = age.getModifiers();//获取权限修饰符
Class type = age.getType();//获取数据类型
String name = age.getName();//获取变量名
Student cxk = new Student("cxk", 30);
age.setAccessible(true);//暴力反射
Integer value =(Integer) age.get(cxk);
System.out.println(value);
age.set(cxk, 18);//修改已记录的值
System.out.println(cxk);
}
}
获取成员方法
方法名 | 说明 |
---|---|
Method[] getMethods() | 返回所有成员方法对象的数组(只能拿public的) |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,存在就能拿到 |
Method getMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象(只能拿public的) |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象,存在就能拿到 |
Demo:
public class Test {
public static void main(String[] args) throws Exception {
//1.获取class字节码文件对象
Class clazz = Class.forName("com.cxk.fanshe.Student");
Method[] methods1 = clazz.getMethods(); //获取所有的方法(包括父类)
Method[] methods = clazz.getDeclaredMethods();//获取所有的方法(不能获取父类)
Method eat = clazz.getMethod("eat", String.class);//获取单一方法
int modifiers = eat.getModifiers();//获取方法的修饰符
String name = eat.getName();//获取方法的名称
int parameterCount = eat.getParameterCount();//获取方法的参数个数
Class returnType = eat.getReturnType();//获取方法的返回值类型
Parameter[] parameters = eat.getParameters();//获取方法的参数列表
Class[] parameterTypes = eat.getParameterTypes();//获取方法的参数类型列表
Student cxk = new Student("cxk", 30);
eat.setAccessible(true);//暴力反射 使私有方法可以被访问
String apple =(String) eat.invoke(cxk, "apple");//执行方法
}
}
利用反射保存对象信息
Demo:
public class Test {
public static void main(String[] args) throws Exception {
/*
对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去
*/
Student s = new Student("小A",23,'女',167.5,"睡觉");
Teacher t = new Teacher("播妞",10000);
saveObject(s);
saveObject(t);
}
//把对象里面所有的成员变量名和值保存到本地文件中
public static void saveObject(Object obj) throws Exception {
//1.获取字节码文件的对象
Class clazz = obj.getClass();
//2. 创建IO流
BufferedWriter bw = new BufferedWriter(new FileWriter("./a.txt"));
//3. 获取所有的成员变量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
//获取成员变量的名字
String name = field.getName();
//获取成员变量的值
Object value = field.get(obj);
//写出数据
bw.write(name + "=" + value);
bw.newLine();
}
bw.close();
}
}
学生类:
public class Student {
private String name;
private int age;
private char gender;
private double height;
private String hobby;
}
教师类:
public class Teacher {
private String name;
private double salary;
}