本来打算写一篇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("脱光光,洗白白...");}@Overridepublic 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 通过forNameClass<?> c2 = Class.forName("test.Mouse");// 方式3 直接通过类获取Class<Mouse> 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.NoSuchFieldException  getField不能获取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 根据构造函数参数获取构造函数 一般直接用DeclaredXXXConstructor<?> constructor = c2.getDeclaredConstructor(String.class);System.out.println("获取参数是String的构造函数:"+constructor);}
}输出结果:
包名.类名test.Mouse
类名Mouse
包名.类名test.Mouse
包名.类名test.Mouse
字段名称:password
字段名称:name
name的注解:@test.MyFiledAnotation(value=字段注解测试)
可以根据注解获取自定义相关内容:字段注解测试
异常: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 直接调用newInstanceMouse 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");// 普通属性不需要设置Accessiblepassword.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 <annotations.length ; i++) {Annotation annotation = annotations[i];System.out.println(annotation);// 通过instanceof 来判断是否是自己需要的注解if (annotation instanceof MyAnotation) {MyAnotation my = (MyAnotation)annotation;// 获取自己注解的方法 我之前写过一个文章 redis锁防止重复点击 就用到了自定义注解System.out.println(my.value());}}// 1.2 获取指定注解MyAnotation myannotation = c2.getAnnotation(MyAnotation.class);System.out.println(myannotation.value());// 2. 获取方法注解// 使用getMethod 会报错 ---》 Exception in thread "main" java.lang.NoSuchMethodException: test.Mouse.takeAShower()// 上边说过了 getMethod不能获取private方法Method takeAShower = c2.getDeclaredMethod("takeAShower");// 2.1 获取所有注解Annotation[] MethodAnnotations = takeAShower.getAnnotations();for (int i = 0; i < MethodAnnotations.length; i++) {Annotation annotation = MethodAnnotations[i];System.out.println(annotation);// 通过instanceof 来判断是否是自己需要的注解if (annotation instanceof MyMethodAnotation) {MyMethodAnotation my = (MyMethodAnotation)annotation;System.out.println(my.value());}}// 2.2 指定注解获取MyMethodAnotation myAnnotation = takeAShower.getAnnotation(MyMethodAnotation.class);System.out.println(myAnnotation);// 3. 字段注解Field name = c2.getDeclaredField("name");// 3.1 获取指定字段全部注解Annotation[] FiledAnnotations = name.getAnnotations();for (int i = 0; i < FiledAnnotations.length; i++) {Annotation annotation = FiledAnnotations[i];System.out.println(annotation);// 通过instanceof 来判断是否是自己需要的注解if (annotation instanceof MyFiledAnotation) {MyFiledAnotation my = (MyFiledAnotation)annotation;System.out.println(my.value());}}// 3.2 获取指定类型注解MyFiledAnotation annotation = name.getAnnotation(MyFiledAnotation.class);System.out.println("获取指定注解:"+annotation.value());}
}
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<String,Mouse> test(List<Short> list, DD<Mouse> dd, Integer i) {return null;}
}interface AA extends BB{}
interface BB{}
class CC{}
package test;/*** @author 发现更多精彩  关注公众号:木子的昼夜编程* 一个生活在互联网底层,做着增删改查的码农,不谙世事的造作*/
public class DD<T> {}
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兜底Type  t = 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 instanceof  ParameterizedType) {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引入

<dependencies><dependency><groupId>org.reflections</groupId><artifactId>reflections</artifactId><version>0.9.11</version></dependency>
</dependencies>
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{@MyMethodAnotationpublic void test01(String str, Integer integer) {}@MyMethodAnotationpublic 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={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={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<Class<? extends Father>> subTypesOf = reflections.getSubTypesOf(Father.class);subTypesOf.stream().forEach(System.out::println);// 2. 根据方法参数扫描符合参数的方法//扫描不同的类型 需要不同的扫描工具//需要指定 setScanners(new MethodParamterScanner()) 否则报错:Scanner MethodParameterScanner was not configuredreflections = new Reflections(new ConfigurationBuilder().forPackages("com.freeedu.test") // 指定扫描包// 指定多中扫描工具.setScanners(new MethodParameterScanner(),new TypeAnnotationsScanner(),new SubTypesScanner()));Set<Method> methodsMatchParams = reflections.getMethodsMatchParams(String.class, Integer.class);methodsMatchParams.stream().forEach(System.out::println);// 3. 获取类上有指定注解的类 class com.freeedu.test.Person// 同理可以获取方法、属性上都指定注解的方法和属性Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(MyClassAnnotation.class);typesAnnotatedWith.forEach(System.out::println);// 4. 获取指定返回值的方法Set<Method> methodsReturn = reflections.getMethodsReturn(String.class);methodsReturn.forEach(System.out::println);// 其实官方已经给了我们一个很好用的Utils ---> ReflectionUtils// 获取某个类的方法 指定可见性+入参个数+前缀Set<Method> 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;@Overridepublic 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.AbstractTransferHelperpool.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 AbstractTransferHelperCtClass 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<String,Object> 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<String,Object> 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<String, Object> map, Class<TestPO> 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> PO Method02(Map<String, Object> map, Class<PO> 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> PO Method03(Map<String, Object> map, AbstractTransferHelper helper) throws Exception {return  (PO) helper.transfer(map);}
}

javaassist的功能远远大于我写的这个demo 有兴趣的读者自行研究~~

四、唠唠

我看过一些源码,其实一般都只会用到

反射可能会带来一些安全问题,我们一般在重构项目或者是处理一个很复杂的业务的时候才会使用,一般情况我们写业务代码用不到反射。

源代码地址:
https://github.com/githubforliming/ReflectionTest.git
https://github.com/githubforliming/JavassistTest.git

面试问反射 你能跟面试官聊多少呢相关推荐

  1. 前端社招第一次面试问到的题【面试通过5k】

    前端社招第一次面试问到的题[面试通过,工资5k] 1.px跟em的区别? 答:px就是一个绝对像素单位,是固定值,而em是相对单位值,如果自身定义了font-size,则em会根据font-sizef ...

  2. 你问我答,准备面试需要做哪些技术储备,面试官更加关心什么方面的技术点?...

    这个系列整理了关于如何进入大厂的一些问题,包含了技术储备,面试官更加关心什么方面的技术点等等 一 第一个问题: 准备面试,工作 3 年了想面个大厂,现在那面试官会更注重问哪方面呢?是算法还是那些框架原 ...

  3. 面试问外观模式???这不就是设计模式里面的吗?我给你上一课吧,面试官

    面试问外观模式???这不就是设计模式里面的吗?我给你上一课吧,面试官 外观模式 介绍 实现 步骤 1 Shape.java 步骤 2 Rectangle.java Square.java Circle ...

  4. 别看是面试问烂的题目,一面试你照样还是不会系列MySQL四种隔离级别,看完吊打面试官!

    别看是面试问烂的题目,一面试你照样还是不会系列MySQL四种隔离级别,看完吊打面试官! 什么是事务 事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消.也 ...

  5. mysql 查看表v空间自增涨_面试问烂的 MySQL 查询优化,看完屌打面试官!

    Java技术栈 www.javastack.cn 优秀的Java技术公众号 作者:唐立勇 https://segmentfault.com/a/1190000013672421 什么影响了数据库查询速 ...

  6. 面试问烂的 MySQL 查询优化,看完屌打面试官!

    Java大数据修炼之道 优秀的Java技术公众号 作者:唐立勇 https://segmentfault.com/a/1190000013672421 相关阅读 面试问烂的 MySQL 四种隔离级别, ...

  7. 问遍了身边的面试官朋友,我整理出这份 Java 集合高频面试题(2022年最新版)

    微信搜索[程序员囧辉],关注这个坚持分享技术干货的程序员. 我的最新文章:百万级QPS,支撑淘宝双11商品浏览需要哪些技术 前言 大家好,我是囧辉,面试系列开篇:Java 基础高频面试题(2021年最 ...

  8. 字节跳动面试,两面+HR面,面试官很棒!

    简单记一下,后面补全 2021年3月13日11:13:03 首先看看两次面试的题目,个人感觉比较看重平时的积累,比如Full GC和对线程池的理解等, 知其然,还得知其所以然啊 字节一面 介绍一下自己 ...

  9. 京东某程序员哀叹:在大厂快待废了,出去面试问自己kafka,竟然全忘了!

    在一家公司待久了就容易变得懒惰,原来的许多知识都会慢慢遗忘,这种情况并不少见. 一个京东员工发帖吐槽:感觉在大厂快待废了,出去面试问自己kafka,自己都忘记了.平时用的时候都是别人的中间件,用法不难 ...

  10. 编程猫python讲师面试_【编程猫教师面试】在BOSS问了我很多,问我为什么选择编程猫,问我了解编程猫吗?-看准网...

    985师范本加硕,想要从事k12教育,坚挺到最后一轮但是未通过的小姐姐掩面飘过,来谈谈我的面试感受吧.个人觉得猫厂管培生的面试整体流程安排挺合理的,有感觉确实是在用心的挑选人才,然后所有的面试官都很n ...

最新文章

  1. phpsso.php 注入漏洞,PHPCMS各种注入漏洞补丁
  2. SOCKET用法详解
  3. led灯条维修_常见的LED透明屏型号规格,影响LED透明屏价格因素
  4. FPGA自定义UART传输(包含:matlab数据拆分)
  5. 大数据方面核心技术有哪些?新人必读
  6. flutter刷新页面_Flutter BottomNavigationBar切换会刷新当前页面解决方
  7. 对路径的访问被拒绝怎么办_学习了解ACL—扩展访问控制列表,就在网工知识角...
  8. C语言写的程序如何控制计算机硬件
  9. Nginx-Lua模块的执行顺序
  10. jquery关于多个显示隐藏
  11. rsync和inotify实时同步配置 exclude排除多个文件夹
  12. MySQL模糊查询的那些谣言
  13. linux mv复制命令,linux中删除复制移动文件rm,mv,cp命令详解linux操作系统 -电脑资料...
  14. Jquery的ajax 三级联动 03
  15. 恩智浦智能车入门——一定避免那些坑
  16. bin文件用cad打开_bin文件怎么打开?实测可靠方法
  17. pycharm远程控制服务器(局域网 内网穿透)
  18. python---之scipy.ndimage.measurements.label
  19. 微博商城开启社会化电商之路
  20. Mysql索引:图文并茂,深入探究索引的原理和使用

热门文章

  1. _search.php_wholesale_search.php
  2. Oracle 11G安装出错(Oracle执行先决条件检查失败)
  3. 一些大牛的博客推荐,排名不分先后
  4. 信息系统项目管理师(2022年) —— 第 3 章 项目立项管理
  5. python 内存文件_python基础知识-7-内存、深浅、文件操作
  6. 杨韬的Markdown自定义CSS样式
  7. 治近视的秘方!1000度近视降到只有200度,不知道有没有用,试试(转)
  8. 阿里云Nginx配置
  9. 计算机汉字录入试题,上机试题:汉字录入题.doc.doc
  10. 如何改变计算机桌面字体,怎么调整电脑桌面字体