引言:本人学习知识是很disgust去公式化学习,使用一个数年一直重复使用的PPT或者是整一篇长篇大论,没有的信息太多,常常事与愿违。所以我将只针对重点去述说。
在学习前,我们要知道反射是什么?反射能做什么?以及动态代理的创建
什么是反射(Reflection
)
Java 程序在运行期间可以获取到一个对象的全部信息
反射的作用
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时调用任意一个对象的方法。
- 在运行时修改类中的私有属性和方法。
以上说了反射和反射的作用总结起来就是:反射它可以操作一个对象的全部,不管它是公的母的,公共的还是私有的都能给它操作了。所以反射给对象说的话,估计也是
获取Class的对象方式
现在我们就来学习为什么反射可以获取对象的全部信息,其实是通过字节码文件实现的也就是Class
文件,没错就是咱们线程锁synchronized()常用的锁对象:类名.Class
这个 Class
对象就像是一面镜子,我们透过这面镜子可以清楚地看到类的结构信息。因此,我们形象的将获取Class
对象的过程称为:反射
获取Class的三种方法
Class.forName("全类名")
- 类名.class
- 对象.getClass
温馨提示:第一种本人是使用次数较多的,但是在写“全类名”时,能CV就CV,不要自己写。
反射获取构造方法
- Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
- Constructor<?>I] getDeclaredConstructors():返回所有构造方法对象的数组
- Constructor<T> getConstructor(Class<?>..parameterTypes):返回单个公共构造方法对象
- ConstructorxT> getDeclaredConstructor(Class<?>..parameterTypes):返回单个构造方法对象
- Constructor类中用于创建对象的方法
- T newlnstance(Object.. initargs):根据指定的构造方法创建对象
- setAccessible(boolean flag):设置为true,表示取消访问检查
以下为代码展示
package Reflex;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
// 获取Class字节码文件对象
Class c = Class.forName("Reflex.Student");
System.out.println("获取所有公共的构造方法");
// 获取所有公共的构造方法
Constructor[] constructors = c.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("获取所有的构造方法包括私有");
// 获取所有的构造方法包括私有
Constructor[] declaredConstructors = c.getDeclaredConstructors();
for (Constructor constructor : declaredConstructors) {
System.out.println(constructor);
}
System.out.println("获取单个构造方法包括私有");
/*
* getConstructor和getConstructors的区别就在于最后面的s,加了就是全部,不加就是一个/指定
* 指定:通过构造方法的参数来确定,比如String.class int.class
* 如果指定的是私有的构造方法,那么就不能使用getConstructor,要使用getDeclaredConstructor
* */
Constructor constructor = c.getConstructor();
System.out.println(constructor);
System.out.println("获取单个构造方法包括私有-指定Student(int)");
Constructor constructorInt = c.getDeclaredConstructor(int.class);
System.out.println(constructorInt);
}
}
反射获取成员变量/修改成员变量值
- Fieldll getFields():返回所有公共成员变量对象的数组
- Field[l getDeclaredFields():返回所有成员变量对象的数组
- Field getField(String name):返回单个公共成员变量对象
- Field getDeclaredField(String name):返回单个成员变量对象
- Field类中用于创建对象的方法void set(Object obj, Object value)
- 赋值Objectget(Object obj)获取值。
以下为代码展示
package Reflex;
import java.lang.reflect.Field;
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
// 获取Class字节码文件对象
Class c = Class.forName("Reflex.Student");
System.out.println("获取所有公共成员变量对象");
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("获取所有成员变量对象-包括私有");
Field[] fieldsAll = c.getDeclaredFields();
for (Field field : fieldsAll) {
System.out.println(field);
}
System.out.println("获取单个公共成员变量对象");
Field name = c.getField("name");
System.out.println(name);
System.out.println("获取所有成员变量对象-包括私有");
Field nameDeclared = c.getDeclaredField("name");
System.out.println(nameDeclared);
System.out.println("获取单个成员变量对象的值-包括私有");
Student s = new Student("张三",18,'女',165.8,"睡觉");
// 如果想获取私有成员变量对象的值,那么需要添加一行name.setAccessible(true)让它临时取消访问权限
nameDeclared.setAccessible(true);
String value = (String) nameDeclared.get(s);
System.out.println(value);
System.out.println("修改单个成员变量对象的值-包括私有");
nameDeclared.set(s,"zhangsan");
System.out.println(s);
}
}
反射获取成员方法
- Methodll getMethods():返回所有公共成员方法对象的数组,包括继承的
- Methodll getDeclaredMethods):返回所有成员方法对象的数组,不包括继承的
- Method getMethod (String name, Class<?>. parameterTypes):返回单个公共成员方法对象Method getDeclaredMethod(String name, Class<?>.. parameterTypes):返回单个成员方法对象
Method类中用于创建对象的方法
- Object invoke(Object obj, Object..args):运行方法参数一:用obj对象调用该方法
- 参数二:调用方法的传递的参数(如果没有就不写)
- 返回值:方法的返回值(如果没有就不写)
以下为代码展示
package Reflex;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 获取Class字节码文件对象
Class c = Class.forName("Reflex.Student");
System.out.println("获取所有的公共成员方法-包括继承");
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("获取所有的公共成员方法-不包括继承但包括私有");
Method[] declaredMethods = c.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
System.out.println("获取单个的公共成员方法");
/*
* 参数一:方法的名字
* 参数二:方法的形参的字节码-
* */
Method eat = c.getMethod("eat", String.class);
System.out.println(eat);
System.out.println("获取单个的公共成员方法-包括私有");
Method eatDeclared = c.getDeclaredMethod("eat", String.class);
System.out.println(eatDeclared);
System.out.println("运行方法");
Student s = new Student();
eatDeclared.setAccessible(true);
/*
* 参数一:方法的调用者
* 参数二:调用方法传递的实际参数
* */
eatDeclared.invoke(s,"张三");
//如果这个方法有返回值就直接在后面.var接收就OK了
}
}
注意:如果要修改/运行一个私有的成员变量值/方法,需要添加
Field.setAccessible(true);用于临时取消访问权限
动态代理
同样啊,在了解动态代理之前我们要知道动态代理是个啥?为啥要代理?Java通过什么来保证代理的一致性?围绕着以上问题来学习动态代理
动态代理:可以在运行时动态地创建一个实现了指定接口的代理对象,并将对该代理对象的方法调用委托给指定的处理器来处理。
为啥要代理:代理可以无浸入式的给对象增强其他功能
Java通过什么来保证代理的一致性?:通过接口保证,后面的对象和代理需要实现同一个接口接口中就是被代理的所有方法
如何为Java对象创建一个代理对象
java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法
Star star = (Star) Proxy.newProxyInstance(
BigStarProxy.class.getClassLoader(),//第一个参数基本都是固定的
new Class[]{Star.class},//第二个参数:把这个接口中的所有方法斗可以代理
new InvocationHandler() {//第三个参数:这个代理需要做什么事情
// 3.1:这个参数是代理的对象
// 3.2:要运行(代理)的方法
// 3.3:运行时,如果这个方法有参数,那这就是传递的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 如果你代理的是这个方法,那么这个方法你需要怎么写
if ("sing".equals(method.getName())){
System.out.println("准备麦克风,收钱");
} else if ("dance".equals(method.getName())) {
System.out.println("准备场地,收钱");
}
// 代理把它的事情做完,就让🐔哥准备唱歌或者跳舞-如果方法有返回值,那么可以直接放到return里面,如果没有,就不用放在return里面
return method.invoke(bigStar,args);
}
}
);
本人对动态代理不是特别了解,如需深入了解,可点击下方链接跳转至Java进阶 | Proxy动态代理机制详解-知了一笑的博客
尾声:该博客用于在大学期间学习总结,借此平台分享和巩固学之所学,文章中多有借鉴其他优秀博客内容以及写的不好的位置,还望大佬们指出!(抱拳)