反射学习笔记
动态代理
程序为什么需要代理
特点:无侵入式的给代理增加额外的功能
代理长什么样
代理里面就是对象要被代理的方法。
对象有什么方法想要被代理,代理就一定要有对应的方法。代理通过接口得知需要被代理的方法。
jJava通过什么来保证代理的样子?
通过接口保证,后米娜的对象和代理需要实现同一个接口,接口中就是被代理的所有方法。
如何为Java对象创建一个代理对象?
java.lang.reflect.Proxy类
提供了为对象产生代理对象的方法:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
动态代理的代码实现
接口
public interface Star {
// 我们可以把所有要被代理的方法定义在接口当中
// 唱歌
abstract String sing(String name);
// 跳舞
abstract void dance();
}
被代理的对象
public class BigStar implements Star {
private String name;
public BigStar() {
}
public BigStar(String name) {
this.name = name;
}
/**
* 唱歌
* @param name
* @return
*/
@Override
public String sing(String name) {
System.out.println(this.name + "正在唱" + name);
return "谢谢";
}
/**
* 唱歌
* @param name
* @return
*/
@Override
public void dance() {
System.out.println(this.name + "正在跳");
}
public String getName() {
return name;
}
public BigStar setName(String name) {
this.name = name;
return this;
}
}
代理类
public class ProxyUtil {
/**
* 方法的作用:
* 给一个明星的对象,创建一个代理
* @param bigStar 被代理的对象
* @return 给明星创建的代理
*/
public static Star createProxy(BigStar bigStar) {
/**
* java.lang.reflect.Proxy类,提供了为对象产生代理对象的方法:
* public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
*/
Star star = (Star) Proxy.newProxyInstance(
// 参数一:用于指定用哪个类加载器,去加载生成的代理类
ProxyUtil.class.getClassLoader(),
// 参数二:指定接口,这些接口用于指定生成的代理长什么样,也就是有哪些方法
new Class[]{Star.class},
// 参数三:用来指定生成的代理对象要干什么事情
new InvocationHandler() {
@Override
public Object invoke(
// 参数一:代理的对象
Object proxy,
// 参数二:要运行的方法 sing
Method method,
// 参数三:调用sing方法时,传递的实参
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;
}
}
测试类
/*
* 需求:
* 外面的人想要大明星唱一首歌
* 1、ProxyUtil.createProxy(大明星的对象);
* 2、再调用代理的唱歌方法
* 代理对象.唱歌的方法("只因你太美");
*/
public class Test {
public static void main(String[] args) {
// 1、获取代理的对象
BigStar bigStar = new BigStar("坤坤");
Star proxy = ProxyUtil.createProxy(bigStar);
// 2、调用唱歌的方法
String result = proxy.sing("只因你太美");
System.out.println(result);
// 3、调用跳舞的方法
proxy.dance();
}
}
执行结果
反射
什么是反射
反射允许对封装类的字段、方法和构造函数的信息进行编程访问。
获取class对象的三种方式
- Class.forName(“全类名”);
- 类名.class;
- 对象.getClass();
代码实现
public static void main(String[] args) throws ClassNotFoundException {
// 1、Class.forName("全类名")
// 最常用的
Class<?> clazz = Class.forName("com.lw.myreflect1.Student");
// 打印
System.out.println(clazz);
// 2、Student.class;
// 一般更多的是当作参数进行传递
Class clazz2 = Student.class;
// 3、对象.getClass();
// 当我们已经有了这个类的对象时,才可以使用
Student student = new Student();
Class clazz3 = student.getClass();
System.out.println(clazz == clazz2);
System.out.println(clazz2 == clazz3);
}
运行结果
利用反射获取构造方法
Class类中用于获取构造方法的方法
-
Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组;
-
Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组;
-
Constructor<?> getConstructor(Class<?>… parameterTypes):返回单个构造方法对象;
-
Constructor<?> getDeclaredConstructor(Class<?>… parameterTypes):返回单个构造方法对象。
Constructor类中用于创建对象的方法
-
T newInstance(Object… initargs):根据指定的构造方法创建对象;
-
setAccessible(boolean flag):设置为true,表示取消访问检查。
代码实现
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 1、获取class字节码文件对象
Class<?> clazz = Class.forName("com.lw.myreflect1.Student");
// 2、获取构造方法
Constructor<?>[] cons = clazz.getConstructors();
for (Constructor<?> con : cons) {
System.out.println(con);
}
System.out.println("--------");
Constructor<?>[] con2 = clazz.getDeclaredConstructors();
for (Constructor<?> con : con2) {
System.out.println(con);
}
System.out.println("--------");
Constructor<?> con3 = clazz.getDeclaredConstructor();
System.out.println(con3);
System.out.println("--------");
Constructor<?> con4 = clazz.getDeclaredConstructor(String.class);
System.out.println(con4);
System.out.println("--------");
Constructor<?> con5 = clazz.getDeclaredConstructor(int.class);
System.out.println(con5);
System.out.println("--------");
Constructor<?> con6 = clazz.getDeclaredConstructor(String.class, int.class);
int modifiers = con6.getModifiers();
System.out.println(modifiers);
Parameter[] parameters = con6.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
con6.setAccessible(true); // 表示临时取消权限校验
Student stu = (Student) con6.newInstance("坤坤", 24);
System.out.println(stu);
}
运行结果
利用反射获取成员变量
Class类中用于获取成员变量的方法
-
Field[] getFields():返回所有公共成员变量对象的数组;
-
Field[] getDeclaredFields():返回所有成员变量的数组;
-
Field[] getField(String name):返回单个公共成员变量对象;
-
Field getDeclaredField(String name):返回单个成员变量对象。
Field类用于创建对象的方法
-
void set(Object obj, Object value):赋值;
-
Object get(Object obj)获取值。
代码实现
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
// 1、获取class字节码文件的对象
Class<?> clazz = Class.forName("com.lw.myreflect3.Student");
// 2、获取所有的成员变量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("--------");
// 获取单个的成员变量
Field name = clazz.getDeclaredField("name");
System.out.println(name);
System.out.println("--------");
// 获取权限修饰符
int modifiers = name.getModifiers();
System.out.println(modifiers);
System.out.println("--------");
// 获取成员变量的名字
String n = name.getName();
System.out.println(n);
System.out.println("--------");
// 获取成员变量的数据类型
Class<?> type = name.getType();
System.out.println(type);
System.out.println("--------");
// 获取成员变量记录的值
Student student = new Student("kunkun", "男");
name.setAccessible(true);
String value = (String) name.get(student);
System.out.println(value);
System.out.println("--------");
// 修改对象里面记录的值
name.set(student, "ikun");
System.out.println(student);
}
运行结果
利用反射获取成员方法
Class类中用于获取成员方法的方法
Method[] getMethods():返回公共成员方法对象的数组,包括继承的;
Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的;
Method getMethod(String name, Class<?>… parameterTypes):返回单个公共成员方法对象;
Method getDeclaredMethod(String name, Class<?>… parameterTypes):返回单个成员方法对象。
Method类中用于创建对象的方法
Object invoke(Object obj, Object… args):运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不用写)
返回值:方法的返回值(如果没有就不用写)
代码实现
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// 1、获取class字节码文件的对象
Class<?> clazz = Class.forName("com.lw.myreflect4.Student");
// 2、获取里面所有的方法对象(包含父类中所有的公共方法)
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("--------");
// 获取里面所有的方法对象(不能获取父类的,但是可以获取本类中私有的方法)
Method[] methodss = clazz.getDeclaredMethods();
for (Method method : methodss) {
System.out.println(method);
}
System.out.println("--------");
// 获取指定的单一方法
Method m = clazz.getDeclaredMethod("sing", String.class);
System.out.println(m);
System.out.println("--------");
// 获取方法的修饰符
int modifiers = m.getModifiers();
System.out.println(modifiers);
System.out.println("--------");
// 获取方法的名字
String name = m.getName();
System.out.println(name);
System.out.println("--------");
// 获取方法的形参
Parameter[] parameters = m.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
System.out.println("--------");
// 获取方法抛出的异常
Class<?>[] exceptionTypes = m.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
System.out.println("--------");
// 方法运行
Student student = new Student();
m.setAccessible(true);
String result = (String) m.invoke(student, "kunkun");
System.out.println(result);
}
运行结果
总结
反射的作用
- 获取一个类里面所有的信息,获取到了之后,再执行其它的业务逻辑;
- 结合配置文件,动态的创建对象并调用方法。
获取class字节码对象的三种方式
- Class.forName(“全类名”);
- 类名.class;
- 对象.getClass();
如何获取构造方法、成员方法、成员变量
查看API文档。
常见单词:
- get:获取
- set:设置
- Constructor:构造方法
- Parameter:参数
- Field:成员变量
- Modifiers:修饰符
- Mothod:方法
- Delared:私有的
tln(result);
}
#### 运行结果
[外链图片转存中...(img-ZFfOKFfC-1679477893141)]
## 总结
### 反射的作用
1. 获取一个类里面所有的信息,获取到了之后,再执行其它的业务逻辑;
2. 结合配置文件,动态的创建对象并调用方法。
### 获取class字节码对象的三种方式
1. Class.forName("全类名");
2. 类名.class;
3. 对象.getClass();
### 如何获取构造方法、成员方法、成员变量
查看API文档。
常见单词:
- get:获取
- set:设置
- Constructor:构造方法
- Parameter:参数
- Field:成员变量
- Modifiers:修饰符
- Mothod:方法
- Delared:私有的