面试官问你反射,你能回答多少

本来打算写一篇Mybatis的Mapper代理源码简单阅读,发现其中有用到动态代理,想着要不先写一篇动态代理吧,结果发现Jdk的动态代理涉及到反射的知识,所以最后决定写一篇反射相关的文章。
读者朋友,在学习技术的时候千万不要像我写文章这样,学一个知识点不要被其他知识点困死,陷入无限循环中。
对于动态代理和反射大概知道做啥的就能妥妥的看Mybatis的源码。
一、对于反射的理解 1. 什么是反射 Java的反射机制是运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。对于任意一个对象,都能够调用他的任意方法、获取他的属性、修改部分类信息,这种动态获取信息以及动态调用对象方法的功能成为Java语言的反射机制。
一句话就是:运行时动态调用某个类或对象的方法、获取属性、修改部分类信息等。
2. 什么时候用 我理解的第一是获取某个类的私有属性或方法,第二是很多框架中通过配置文件加载Java对象的时候需要。
3. 还有什么 不要陷死到理论中,就很不错了。
二、 反射我来了 小白鼠类:

package test; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 */ @MyAnotation("测试注解") public class Mouse { public Mouse(){} private Mouse(String name) { this.name = name; } // 私有变量 private String password = "123456"; @MyFiledAnotation("字段注解测试") public String name = "小小太阳"; // public void say(String msg){ System.out.println(msg+"叨逼叨叨逼叨..."); }// public void run(){ System.out.println("奔跑吧,向着太阳奔跑..."); }@MyMethodAnotation("方法注解测试") private void takeAShower(){ System.out.println("脱光光,洗白白..."); }@Override public String toString() { return "Mouse{" + "password='" + password + '\'' + ", name='" + name + '\'' + '}'; } }

package test; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 分享一个生活在互联网底层做着增删改查的码农的感悟与学习 * ---》类注解 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnotation { String value() default "默认值"; }

package test; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 分享一个生活在互联网底层做着增删改查的码农的感悟与学习 * --》 方法注解 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyMethodAnotation { String value() default "默认值"; }

package test; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 分享一个生活在互联网底层做着增删改查的码农的感悟与学习 * --> 字段注解 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface MyFiledAnotation { String value() default "默认值"; }

2.1 获取Class对象
import test.Mouse; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 */ public class Test { public static void main(String[] args) throws ClassNotFoundException { // 方式1 通过对象获取 Mouse mouse = new Mouse(); Class c1 = mouse.getClass(); // 方式2 通过forName Class c2 = Class.forName("test.Mouse"); // 方式3 直接通过类获取 Class c3 = Mouse.class; System.out.println("c1 == c2 :" + (c1 == c2)); System.out.println("c2 == c3 :" + (c2 == c3)); // 输出: // c1 == c2 :true // c2 == c3 :true } }

2.2 看看Class都有哪些东西
import test.MyFiledAnotation; import test.MyMethodAnotation; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 */ public class Test02 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException { Class c2 = Class.forName("test.Mouse"); // 1. 类名 System.out.println("包名.类名"+c2.getName()); System.out.println("类名"+c2.getSimpleName()); System.out.println("包名.类名"+c2.getTypeName()); System.out.println("包名.类名"+c2.getCanonicalName()); // 2. 获取所有属性 包括private // c2.getFields() 不能获取private的属性 Field[] declaredFields = c2.getDeclaredFields(); for (int i = 0; i < declaredFields.length; i++) { Field filed = declaredFields[i]; System.out.println("字段名称:"+filed.getName()); Annotation[] annotations = filed.getAnnotations(); for (int j = 0; j < annotations.length; j++) { Annotation annotation = annotations[j]; System.out.println(filed.getName()+"的注解:"+annotation); if (annotation instanceof MyFiledAnotation) { MyFiledAnotation my = (MyFiledAnotation) annotation; System.out.println("可以根据注解获取自定义相关内容:"+my.value()); } } } // // 2.2通过指定字段名获取 // 抛异常:java.lang.NoSuchFieldExceptiongetField不能获取private属性 try { Field name01 = c2.getField("password"); } catch (Exception e) { System.out.println("异常:"+e); } // 2.3 getDeclaredField可以获取private的属性 Field name02 = c2.getDeclaredField("password"); System.out.println("getField可以获取private属性:"+name02); // 3. 获取所有方法 // getMethods 获取不到private的方法,getDeclaredMethods可以 Method[] methods = c2.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { Method method = methods[i]; String name = method.getName(); // 无关的方法wait equals hashCode toString getClass notify notifyAll 等 if (!"say".equals(name) && !"run".equals(name) && !"takeAShower".equals(name)) { continue; } System.out.println("方法名:"+method.getName()); Annotation[] annotations = method.getAnnotations(); for (int j = 0; j < annotations.length; j++) { Annotation annotation = annotations[j]; System.out.println(name+"注解:"+annotation); if(annotation instanceof MyMethodAnotation) { MyMethodAnotation my = (MyMethodAnotation) annotation; System.out.println("可以根据注解获取自定义相关内容:"+my.value()); } } } // 3.2 获取指定方法getDeclaredMethod(方法名,可变长度参数列表) // 与获取Filed一样 getMethod(方法名,可变长度参数列表) 也不能获取 Method say = c2.getDeclaredMethod("say", String.class); Method run = c2.getDeclaredMethod("run", null); System.out.println("say:"+say); System.out.println("run:"+run); // 4. 特殊的方法 -》 构造方法 // 同理getConstructors不能获取private的构造方法 Constructor[] constructors = c2.getDeclaredConstructors(); for (int i = 0; i < constructors.length; i++) { Constructor c = constructors[i]; System.out.println(c); } // 4.2 根据构造函数参数获取构造函数 一般直接用DeclaredXXX Constructor constructor = c2.getDeclaredConstructor(String.class); System.out.println("获取参数是String的构造函数:"+constructor); } }输出结果: 包名.类名test.Mouse 类名Mouse 包名.类名test.Mouse 包名.类名test.Mouse 字段名称:password 字段名称:name name的注解:@test.MyFiledAnotation(value=https://www.it610.com/article/字段注解测试) 可以根据注解获取自定义相关内容:字段注解测试 异常:java.lang.NoSuchFieldException: password getField可以获取private属性:private java.lang.String test.Mouse.password 方法名:run 方法名:say 方法名:takeAShower takeAShower注解:@test.MyMethodAnotation(value=方法注解测试) 可以根据注解获取自定义相关内容:方法注解测试 say:public void test.Mouse.say(java.lang.String) run:public void test.Mouse.run() public test.Mouse() private test.Mouse(java.lang.String) 获取参数是String的构造函数:private test.Mouse(java.lang.String)注意:一定要自己亲自运行代码试试 看到的永远是你觉得会了的,但是不一定是你会了的。

2.3 动态调用
import test.Mouse; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 */ public class Test03 { public static void main(String[] args) throws Exception { Class c2 = Class.forName("test.Mouse"); // 1. 动态创建对象 // 1.1 直接调用newInstance Mouse o1 = (Mouse)c2.newInstance(); System.out.println(o1); // 1.2 通过构造 Mouse o2 = (Mouse)c2.getConstructor().newInstance(); System.out.println(o2); // can not access a member of class test.Mouse with modifiers "private" // 应对策略:setAccessible(true)Constructor dc = c2.getDeclaredConstructor(String.class); dc.setAccessible(true); Mouse o3 = (Mouse)dc.newInstance("构造反射创建对象name字段值"); System.out.println(o3); // 2. 获取属性值/修改属性值 // 获取password不能直接获取 // System.out.println(o3.password); Field password = c2.getDeclaredField("password"); // 普通属性不需要设置Accessible password.setAccessible(true); System.out.println("反射获取私有属性:"+ password.get(o3)); // 修改属性值 password.setAccessible(true); password.set(o3, "----------通过反射修改咯--------"); System.out.println("反射修改后的属性值:"+ password.get(o3)); // 3. 动态调用方法(这个非常重要了 动态代理就会用到) // 3.1 普通方法 Method say = c2.getDeclaredMethod("say", String.class); say.invoke(o3, "说点什么呢:"); // 3.2 私有方法 Method takeAShower = c2.getDeclaredMethod("takeAShower"); // 解决Class Test03 can not access a member of class test.Mouse with modifiers "private" takeAShower.setAccessible(true); takeAShower.invoke(o3); } }

2.4 反射获取注解 【面试官问你反射,你能回答多少】其实这个我们已经在上边写过了,这里统一写一下简单使用,包括字段、方法、类注解。
import test.Mouse; import test.MyAnotation; import test.MyFiledAnotation; import test.MyMethodAnotation; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 */ public class Tes04 { public static void main(String[] args) throws Exception { Class c2 = Class.forName("test.Mouse"); // 1. 获取类注解 // 1.1 获取所有注解 Annotation[] annotations = c2.getAnnotations(); for (int i = 0; i

2.5 泛型 看到一篇文章里边写了反射操作泛型,我也尝试简单写写
package test; import java.beans.IntrospectionException; import java.util.List; import java.util.Map; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 */ public class Person extends CC implements AA { public Map test(List list, DD dd, Integer i) { return null; } }interface AA extends BB{} interface BB{} class CC{}

package test; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 */ public class DD {}

import test.DD; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 */ public class Test05 { public static void main(String[] args) throws Exception { Class c2 = Class.forName("test.Person"); // 1. 获取类实现的接口 Type[]interfaces = c2.getGenericInterfaces(); for (int i = 0; i < interfaces.length; i++) { System.out.println(interfaces[i]); } // 2. 获取类继承的父类 如果没有extends CC 这里会获取到java.lang.Object // 也就是说他至少会输出一个类 java.lang.Object兜底 Typet = c2.getGenericSuperclass(); System.out.println(t); // 3.1 某个方法的参数泛型 Method test = c2.getMethod("test", List.class, DD.class, Integer.class); Type[] genericParameterTypes = test.getGenericParameterTypes(); for (int i = 0; i < genericParameterTypes.length; i++) { Type gt = genericParameterTypes[i]; System.out.println("没过滤:"+gt); if (gt instanceof ParameterizedType) { System.out.println("过滤:"+gt); ParameterizedType pgt = (ParameterizedType) gt; Type[] arg = pgt.getActualTypeArguments(); for (int j = 0; j < arg.length; j++) { System.out.println("过滤后获取的真实泛型类型:"+arg[j]); } } }// 3.2 某个方法的返回值泛型 Type grt = test.getGenericReturnType(); System.out.println("grt:"+grt); if (grt instanceofParameterizedType) { ParameterizedType pgt = (ParameterizedType) grt; Type[] arg = pgt.getActualTypeArguments(); for (int j = 0; j < arg.length; j++) { System.out.println("返回真实泛型类型:"+j+" "+arg[j]); } }} }

三、扩展 3.1 org.reflections.reflections reflections可以扫描出指定包下的指定类
示例:
pom.xml引入
org.reflections reflections 0.9.11

package com.freeedu.test; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 */ public class Father {}

package com.freeedu.test; import com.sun.istack.internal.NotNull; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 * @create 2021-10-10 15:07 */ @MyClassAnnotation public class Person extends Father{@MyMethodAnotation public void test01(String str, Integer integer) {}@MyMethodAnotation public String test02(@MyParamterAnotation String str, Integer integer) { return null; } }

package com.freeedu.test; /** * @author 发现更多精彩关注公众号:木子的昼夜编程分享一个生活在互联网底层做着增删改查的码农的感悟与学习 */ public @interface MyClassAnnotation { }

package com.freeedu.test; import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; /** * @author 发现更多精彩关注公众号:木子的昼夜编程分享一个生活在互联网底层做着增删改查的码农的感悟与学习 */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(value=https://www.it610.com/article/{METHOD}) public @interface MyMethodAnotation { }

package com.freeedu.test; import java.lang.annotation.*; import static java.lang.annotation.ElementType.METHOD; /** * @author 发现更多精彩关注公众号:木子的昼夜编程分享一个生活在互联网底层做着增删改查的码农的感悟与学习 * @create 2021-10-10 15:39 */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(value=https://www.it610.com/article/{ElementType.PARAMETER}) public @interface MyParamterAnotation { }

下边我简单写集中我自己玩儿的方法,如果有其他需要直接.提示猜测有没有对应方法
或者点进源码看看,你需要的大概率这里都能提供
import com.freeedu.test.*; import com.sun.istack.internal.NotNull; import org.reflections.ReflectionUtils; import org.reflections.Reflections; import org.reflections.scanners.MethodParameterScanner; import org.reflections.scanners.SubTypesScanner; import org.reflections.scanners.TypeAnnotationsScanner; import org.reflections.util.ConfigurationBuilder; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Set; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 */ public class Test { public static void main(String[] args) { // 初始化 默认扫描com.freeedu.test包 Reflections reflections = new Reflections("com.freeedu.test"); // 1. 扫描某些类的子类 Father的子类 Set> subTypesOf = reflections.getSubTypesOf(Father.class); subTypesOf.stream().forEach(System.out::println); // 2. 根据方法参数扫描符合参数的方法 //扫描不同的类型 需要不同的扫描工具 //需要指定 setScanners(new MethodParamterScanner()) 否则报错:Scanner MethodParameterScanner was not configured reflections = new Reflections( new ConfigurationBuilder() .forPackages("com.freeedu.test") // 指定扫描包 // 指定多中扫描工具 .setScanners(new MethodParameterScanner(), new TypeAnnotationsScanner(), new SubTypesScanner()) ); Set methodsMatchParams = reflections.getMethodsMatchParams(String.class, Integer.class); methodsMatchParams.stream().forEach(System.out::println); // 3. 获取类上有指定注解的类 class com.freeedu.test.Person // 同理可以获取方法、属性上都指定注解的方法和属性 Set> typesAnnotatedWith = reflections.getTypesAnnotatedWith(MyClassAnnotation.class); typesAnnotatedWith.forEach(System.out::println); // 4. 获取指定返回值的方法 Set methodsReturn = reflections.getMethodsReturn(String.class); methodsReturn.forEach(System.out::println); // 其实官方已经给了我们一个很好用的Utils ---> ReflectionUtils // 获取某个类的方法 指定可见性+入参个数+前缀 Set test = ReflectionUtils.getAllMethods(Person.class, ReflectionUtils.withModifier(Modifier.PUBLIC), // 修饰符 ReflectionUtils.withPrefix("test"), // 方法前缀 ReflectionUtils.withParametersCount(2),// 参数总数 ReflectionUtils.withReturnType(String.class),// 返回值类型 ReflectionUtils.withParameters(String.class, Integer.class),// 方法参数类型 ReflectionUtils.withAnnotation(MyMethodAnotation.class),// 方法注解 为什么不识别 我加上了呀~~! ReflectionUtils.withAnyParameterAnnotation(MyParamterAnotation.class)// 方法参数注解 // 还有各式各样的过滤 有兴趣或有需要的朋友可以自己找找自己感兴趣的 ); System.out.println("符合条件的方法:"); test.forEach(System.out::println); // } }

3.2 org.javassist.javassist javassist是一个很牛X的东西。
先搞一个demo大家瞅瞅,传入一个Map key值对应实体类TestPO字段名称 Value值对应实体类TestPO字段值
我们怎么把数据设置到实体类中呢
/** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 */ public class TestPO { public Integer id; public String name; public Integer age; @Override public String toString() { return "TestPO{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }

手动编码(硬)+反射编码(软)+高级反射编码(软变硬)面试官问你反射,你能回答多少
文章图片

package test; import java.util.Map; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 * @create 2021-10-10 19:41 */ public abstract class AbstractTransferHelper { public abstract Object transfer(Map map) throws Exception; }

package test; import javassist.*; import java.io.IOException; import java.lang.reflect.Field; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 * @create 2021-10-10 20:10 */ public class TransferUtil { // 这里用到了javaassist // 这个就是有近似于写死代码的性能 有近似于反射的适配性 如果再加字段 这里是不用修改的 // 判空什么的就先不做了 主要讲使用方式 public static AbstractTransferHelper getTransferHelper(Class clazz) throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException, IOException { ClassPool pool = ClassPool.getDefault(); pool.appendSystemPath(); // 导包 //import java.util.HashMap; //import java.util.Map; pool.importPackage("java.util.Map"); pool.importPackage("java.util.HashMap"); //import test.AbstractTransferHelper pool.importPackage("test.AbstractTransferHelper"); //import test.TestPO; pool.importPackage(clazz.getName()); pool.importPackage(AbstractTransferHelper.class.getName()); // 父类 CtClass superClass = pool.getCtClass(AbstractTransferHelper.class.getName()); // 自定义动态创建的类名 String className = clazz.getName()+"TransferHelper"; // 创建类 指定父类superClass // Class XXXTransferHelper extends AbstractTransferHelper CtClass myclass = pool.makeClass(className, superClass); // 构造函数 public XXXTransferHelper(){} CtConstructor ctConstructor = new CtConstructor(new CtClass[0], myclass); ctConstructor.setBody("{}"); myclass.addConstructor(ctConstructor); // 方法--- StringBuilder sb = new StringBuilder(); sb.append("public Object transfer(Map map) throws Exception {\n"); // 类似:TestPO obj = new TestPO(); sb.append(clazz.getName() +" obj = new "+clazz.getName()+"(); \n"); // 设置属性值 Field[] fields = clazz.getFields(); String strF = "obj.%s = map.get(\"%s\") == null ? null : String.valueOf(map.get(\"%s\")); \n"; String strI = "obj.%s = map.get(\"%s\") == null ? null : Integer.valueOf(map.get(\"%s\").toString()); \n"; for (int i = 0; i < fields.length; i++) { Field field = fields[i]; String name = field.getName(); Class type = field.getType(); // 这里只写String Integer 类型 其他我就不写了 if (type == String.class) { // 类似obj.name = map.get("name") == null ? null : String.valueOf(map.get("name")); String format = String.format(strF, field.getName(), field.getName(), field.getName()); sb.append(format); } else if (type == Integer.class) { // 类似obj.name = map.get("name") == null ? null : Integer.valueOf(map.get("name").toString()); String format = String.format(strI, field.getName(), field.getName(), field.getName()); sb.append(format); } }sb.append("return obj; \n"); sb.append("}"); // 创建方法 CtMethod method = CtMethod.make(sb.toString(), myclass); myclass.addMethod(method); // 创建实体 Class aClass = myclass.toClass(); // myclass.writeFile("E:\\MyNote\\test"); System.out.println(aClass); return (AbstractTransferHelper)aClass.newInstance(); } }

import test.AbstractTransferHelper; import test.TestPO; import test.TransferUtil; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; /** * @author 发现更多精彩关注公众号:木子的昼夜编程 * 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作 * @create 2021-10-10 16:24 */ public class Test {public static void main(String[] args) throws Exception { // 参数 /*Map map =new HashMap<>(); long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { TestPO res = Method02(map, TestPO.class); } long end = System.currentTimeMillis(); System.out.println(end-start); */Map map =new HashMap<>(); AbstractTransferHelper helper = TransferUtil.getTransferHelper(TestPO.class); long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { TestPO res = Method03(map, helper); } long end = System.currentTimeMillis(); System.out.println(end-start); }// 手动编码 一百万次30毫秒左右 private static TestPO Method01(Map map, Class testPOClass) { TestPO res =new TestPO(); res.id = map.get("id") == null ? null : Integer.valueOf(map.get("id").toString()) ; res.name = map.get("name") == null ? null : String.valueOf(map.get("name").toString()) ; res.age = map.get("age") == null ? null : Integer.valueOf(map.get("age").toString()) ; return res; }// 反射 一百万次200~300毫秒 // 这个有什么好处呢 如果添加字段 这个方法是不需要修改的 而Method01的硬编码是需要修改的 private static PO Method02(Map map, Class clazz) throws Exception { Object res = clazz.newInstance(); Field[] fields = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; field.setAccessible(true); // 获取字段名称 String name = field.getName(); // 获取字段类型 Class type = field.getType(); // 从Map中获取值 if (type ==Integer.class) { field.set(res, map.get(name) == null ? null : Integer.valueOf(Integer.valueOf(map.get(name).toString()))); } else if(type ==String.class){ field.set(res, map.get(name) == null ? null : String.valueOf(String.valueOf(map.get(name)))); } } return (PO) res; }// 反射 高级版 --> 软变硬 一百万次40毫秒左右 private static PO Method03(Map map, AbstractTransferHelper helper) throws Exception { return(PO) helper.transfer(map); } }

javaassist的功能远远大于我写的这个demo 有兴趣的读者自行研究~~
四、唠唠 我看过一些源码,其实一般都只会用到1. 动态创建实例 2. 动态调用方法
反射可能会带来一些安全问题,我们一般在重构项目或者是处理一个很复杂的业务的时候才会使用,一般情况我们写业务代码用不到反射。
如果面试的时候问到了面试,你最好能提前准备一个工作中用反射解决项目问题的例子。
还能跟面试官谈到设计模式(动态代理),如果你都懂得话,可以跟面试官谈Java动态代理与CGLIB动态代理。
还可以结合你看过的某些框架源码中哪儿用到了反射,这样会让面试官觉得你是真的用过学过,而不是背过。
源代码地址:
https://github.com/githubforl...
https://github.com/githubforl...
本文由博客一文多发平台 OpenWrite 发布!

    推荐阅读