【Java】反射详解

【Java】反射详解

Java 反射详解

运行时动态获取类信息、创建对象、调用方法完整教程

目录


一、反射概述

1.1 什么是反射

反射(Reflection)是Java提供的一种机制,允许程序在运行时检查和操作类的结构(类、方法、字段等)。

反射的核心功能:

  • 运行时获取类的信息
  • 动态创建对象
  • 动态调用方法
  • 动态访问和修改字段

1.2 反射的应用场景

  • 框架开发:Spring、Hibernate等框架大量使用反射
  • 动态代理:AOP面向切面编程
  • 注解处理:运行时处理注解
  • 插件系统:动态加载类
  • 序列化/反序列化:JSON、XML转换

1.3 反射的优缺点

优点:

  • 灵活性高,可以动态操作类
  • 降低代码耦合度
  • 适合框架和工具开发

缺点:

  • 性能开销大(比直接调用慢10-100倍)
  • 破坏封装性(可访问私有成员)
  • 代码可读性差
  • 编译时无法检查类型安全

二、获取Class对象

2.1 三种获取方式

publicclassGetClassDemo{publicstaticvoidmain(String[] args)throwsException{// 方式1:通过类名.classClass<String> clazz1 =String.class;// 方式2:通过对象.getClass()String str ="Hello";Class<?extendsString> clazz2 = str.getClass();// 方式3:通过Class.forName()Class<?> clazz3 =Class.forName("java.lang.String");// 三种方式获取的是同一个Class对象System.out.println(clazz1 == clazz2);// trueSystem.out.println(clazz2 == clazz3);// true}}

2.2 获取类信息

publicclassClassInfoDemo{publicstaticvoidmain(String[] args){Class<String> clazz =String.class;// 类名System.out.println("简单名: "+ clazz.getSimpleName());// StringSystem.out.println("全限定名: "+ clazz.getName());// java.lang.StringSystem.out.println("规范名: "+ clazz.getCanonicalName());// java.lang.String// 包信息System.out.println("包名: "+ clazz.getPackage().getName());// java.lang// 父类System.out.println("父类: "+ clazz.getSuperclass());// class java.lang.Object// 接口Class<?>[] interfaces = clazz.getInterfaces();for(Class<?> i : interfaces){System.out.println("接口: "+ i.getName());}// 修饰符int modifiers = clazz.getModifiers();System.out.println("是否public: "+java.lang.reflect.Modifier.isPublic(modifiers));System.out.println("是否final: "+java.lang.reflect.Modifier.isFinal(modifiers));System.out.println("是否abstract: "+java.lang.reflect.Modifier.isAbstract(modifiers));System.out.println("是否interface: "+java.lang.reflect.Modifier.isInterface(modifiers));}}

2.3 判断类型

publicclassTypeCheckDemo{publicstaticvoidmain(String[] args){Class<String> clazz =String.class;// 判断类型System.out.println("是否接口: "+ clazz.isInterface());// falseSystem.out.println("是否数组: "+ clazz.isArray());// falseSystem.out.println("是否枚举: "+ clazz.isEnum());// falseSystem.out.println("是否注解: "+ clazz.isAnnotation());// falseSystem.out.println("是否基本类型: "+ clazz.isPrimitive());// false// 数组类型Class<?> arrayClass =int[].class;System.out.println("是否数组: "+ arrayClass.isArray());// trueSystem.out.println("数组元素类型: "+ arrayClass.getComponentType());// int// 判断继承关系System.out.println("String是否是Object的子类: "+Object.class.isAssignableFrom(String.class));// trueSystem.out.println("Object是否是String的子类: "+String.class.isAssignableFrom(Object.class));// false}}

2.4 获取注解

importjava.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@interfaceAuthor{Stringname();Stringdate();}@Author(name ="张三", date ="2025-01-01")classMyClass{}publicclassAnnotationDemo{publicstaticvoidmain(String[] args){Class<MyClass> clazz =MyClass.class;// 判断是否有注解if(clazz.isAnnotationPresent(Author.class)){// 获取注解Author author = clazz.getAnnotation(Author.class);System.out.println("作者: "+ author.name());System.out.println("日期: "+ author.date());}// 获取所有注解Annotation[] annotations = clazz.getAnnotations();for(Annotation ann : annotations){System.out.println("注解: "+ ann);}}}

三、构造方法反射

3.1 获取构造方法

importjava.lang.reflect.Constructor;publicclassPerson{privateString name;privateint age;publicPerson(){}publicPerson(String name){this.name = name;}publicPerson(String name,int age){this.name = name;this.age = age;}privatePerson(int age){this.age = age;}}publicclassConstructorDemo{publicstaticvoidmain(String[] args)throwsException{Class<Person> clazz =Person.class;// 获取所有public构造方法Constructor<?>[] constructors = clazz.getConstructors();for(Constructor<?> c : constructors){System.out.println(c);}// 获取所有构造方法(包括私有)Constructor<?>[] allConstructors = clazz.getDeclaredConstructors();// 获取指定参数的public构造方法Constructor<Person> constructor1 = clazz.getConstructor();// 无参Constructor<Person> constructor2 = clazz.getConstructor(String.class);// 一参Constructor<Person> constructor3 = clazz.getConstructor(String.class,int.class);// 两参// 获取私有构造方法Constructor<Person> privateConstructor = clazz.getDeclaredConstructor(int.class);}}

3.2 创建对象

publicclassCreateInstanceDemo{publicstaticvoidmain(String[] args)throwsException{Class<Person> clazz =Person.class;// 方式1:使用无参构造Person p1 = clazz.getDeclaredConstructor().newInstance();// 方式2:使用有参构造Constructor<Person> constructor = clazz.getConstructor(String.class,int.class);Person p2 = constructor.newInstance("张三",25);// 方式3:访问私有构造方法Constructor<Person> privateConstructor = clazz.getDeclaredConstructor(int.class); privateConstructor.setAccessible(true);// 取消访问检查Person p3 = privateConstructor.newInstance(30);System.out.println(p2);}}

四、字段反射

4.1 获取字段

importjava.lang.reflect.Field;publicclassStudent{publicString name;privateint age;protectedString school;staticString country ="China";}publicclassFieldDemo{publicstaticvoidmain(String[] args)throwsException{Class<Student> clazz =Student.class;// 获取所有public字段(包括继承的)Field[] fields = clazz.getFields();// 获取所有字段(不包括继承的)Field[] allFields = clazz.getDeclaredFields();// 获取指定字段Field nameField = clazz.getField("name");// public字段Field ageField = clazz.getDeclaredField("age");// 私有字段// 字段信息System.out.println("字段名: "+ nameField.getName());System.out.println("字段类型: "+ nameField.getType());System.out.println("修饰符: "+ nameField.getModifiers());}}

4.2 访问和修改字段

publicclassFieldAccessDemo{publicstaticvoidmain(String[] args)throwsException{Student student =newStudent();Class<Student> clazz =Student.class;// 访问public字段Field nameField = clazz.getField("name"); nameField.set(student,"李四");String name =(String) nameField.get(student);System.out.println("姓名: "+ name);// 访问private字段Field ageField = clazz.getDeclaredField("age"); ageField.setAccessible(true);// 取消访问检查 ageField.set(student,20);int age =(int) ageField.get(student);System.out.println("年龄: "+ age);// 访问静态字段Field countryField = clazz.getDeclaredField("country"); countryField.set(null,"USA");// 静态字段传nullString country =(String) countryField.get(null);System.out.println("国家: "+ country);}}

五、方法反射

5.1 获取方法

importjava.lang.reflect.Method;publicclassCalculator{publicintadd(int a,int b){return a + b;}privateintsubtract(int a,int b){return a - b;}publicstaticintmultiply(int a,int b){return a * b;}}publicclassMethodDemo{publicstaticvoidmain(String[] args)throwsException{Class<Calculator> clazz =Calculator.class;// 获取所有public方法(包括继承的)Method[] methods = clazz.getMethods();// 获取所有方法(不包括继承的)Method[] allMethods = clazz.getDeclaredMethods();// 获取指定方法Method addMethod = clazz.getMethod("add",int.class,int.class);Method subtractMethod = clazz.getDeclaredMethod("subtract",int.class,int.class);// 方法信息System.out.println("方法名: "+ addMethod.getName());System.out.println("返回类型: "+ addMethod.getReturnType());System.out.println("参数类型: "+Arrays.toString(addMethod.getParameterTypes()));}}

5.2 调用方法

publicclassMethodInvokeDemo{publicstaticvoidmain(String[] args)throwsException{Calculator calculator =newCalculator();Class<Calculator> clazz =Calculator.class;// 调用public方法Method addMethod = clazz.getMethod("add",int.class,int.class);Object result1 = addMethod.invoke(calculator,10,20);System.out.println("10 + 20 = "+ result1);// 30// 调用private方法Method subtractMethod = clazz.getDeclaredMethod("subtract",int.class,int.class); subtractMethod.setAccessible(true);Object result2 = subtractMethod.invoke(calculator,30,10);System.out.println("30 - 10 = "+ result2);// 20// 调用静态方法Method multiplyMethod = clazz.getMethod("multiply",int.class,int.class);Object result3 = multiplyMethod.invoke(null,5,6);// 静态方法传nullSystem.out.println("5 * 6 = "+ result3);// 30}}

六、实战案例

6.1 通用对象打印器

importjava.lang.reflect.Field;publicclassObjectPrinter{publicstaticvoidprint(Object obj)throwsException{Class<?> clazz = obj.getClass();System.out.println("=== "+ clazz.getSimpleName()+" ===");Field[] fields = clazz.getDeclaredFields();for(Field field : fields){ field.setAccessible(true);String name = field.getName();Object value = field.get(obj);System.out.println(name +" = "+ value);}}publicstaticvoidmain(String[] args)throwsException{Person person =newPerson("张三",25);print(person);}}

6.2 简单依赖注入

importjava.lang.annotation.*;importjava.lang.reflect.Field;// 自定义注解@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)@interfaceInject{}// 服务类classUserService{publicvoidsave(){System.out.println("保存用户");}}// 控制器类classUserController{@InjectprivateUserService userService;publicvoidregister(){ userService.save();}}// 依赖注入容器publicclassSimpleContainer{publicstaticvoidinject(Object obj)throwsException{Class<?> clazz = obj.getClass();Field[] fields = clazz.getDeclaredFields();for(Field field : fields){if(field.isAnnotationPresent(Inject.class)){ field.setAccessible(true);Class<?> fieldType = field.getType();Object instance = fieldType.getDeclaredConstructor().newInstance(); field.set(obj, instance);}}}publicstaticvoidmain(String[] args)throwsException{UserController controller =newUserController();inject(controller);// 注入依赖 controller.register();// 保存用户}}

6.3 通用对象复制

importjava.lang.reflect.Field;publicclassObjectCopier{publicstatic<T>Tcopy(T source)throwsException{Class<?> clazz = source.getClass();// 创建新对象@SuppressWarnings("unchecked")T target =(T) clazz.getDeclaredConstructor().newInstance();// 复制所有字段Field[] fields = clazz.getDeclaredFields();for(Field field : fields){ field.setAccessible(true);Object value = field.get(source); field.set(target, value);}return target;}publicstaticvoidmain(String[] args)throwsException{Person original =newPerson("张三",25);Person copied =copy(original);System.out.println("原对象: "+ original);System.out.println("复制对象: "+ copied);System.out.println("是否同一对象: "+(original == copied));// false}}

6.4 动态代理

importjava.lang.reflect.*;// 接口interfaceUserDao{voidsave();voiddelete();}// 实现类classUserDaoImplimplementsUserDao{@Overridepublicvoidsave(){System.out.println("保存用户");}@Overridepublicvoiddelete(){System.out.println("删除用户");}}// 代理处理器classLogHandlerimplementsInvocationHandler{privateObject target;publicLogHandler(Object target){this.target = target;}@OverridepublicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable{System.out.println(">>> 方法开始: "+ method.getName());Object result = method.invoke(target, args);System.out.println("<<< 方法结束: "+ method.getName());return result;}}// 测试publicclassProxyDemo{publicstaticvoidmain(String[] args){UserDao userDao =newUserDaoImpl();// 创建代理对象UserDao proxy =(UserDao)Proxy.newProxyInstance( userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(),newLogHandler(userDao));// 调用代理方法 proxy.save();System.out.println(); proxy.delete();}}

6.5 配置文件加载

importjava.io.InputStream;importjava.lang.reflect.Field;importjava.util.Properties;// 配置类classAppConfig{privateString appName;privateint port;privateString database;// getters...}// 配置加载器publicclassConfigLoader{publicstatic<T>Tload(Class<T> clazz,String configFile)throwsException{// 读取配置文件Properties props =newProperties();InputStream is = clazz.getClassLoader().getResourceAsStream(configFile); props.load(is);// 创建对象T instance = clazz.getDeclaredConstructor().newInstance();// 设置字段值Field[] fields = clazz.getDeclaredFields();for(Field field : fields){ field.setAccessible(true);String key = field.getName();String value = props.getProperty(key);if(value !=null){// 类型转换if(field.getType()==int.class){ field.set(instance,Integer.parseInt(value));}elseif(field.getType()==String.class){ field.set(instance, value);}}}return instance;}}

七、高级应用

7.1 泛型信息获取

importjava.lang.reflect.*;importjava.util.*;publicclassGenericDemo{// 带泛型的字段privateList<String> stringList;privateMap<String,Integer> map;// 带泛型的方法publicList<String>getList(){returnnull;}public<T>TgenericMethod(T param){return param;}publicstaticvoidmain(String[] args)throwsException{Class<GenericDemo> clazz =GenericDemo.class;// 1. 获取字段的泛型类型Field field = clazz.getDeclaredField("stringList");Type genericType = field.getGenericType();if(genericType instanceofParameterizedType){ParameterizedType pt =(ParameterizedType) genericType;System.out.println("原始类型: "+ pt.getRawType());// interface java.util.ListType[] actualTypes = pt.getActualTypeArguments();System.out.println("泛型参数: "+ actualTypes[0]);// class java.lang.String}// 2. 获取Map的泛型类型Field mapField = clazz.getDeclaredField("map");Type mapType = mapField.getGenericType();if(mapType instanceofParameterizedType){ParameterizedType pt =(ParameterizedType) mapType;Type[] types = pt.getActualTypeArguments();System.out.println("Key类型: "+ types[0]);// class java.lang.StringSystem.out.println("Value类型: "+ types[1]);// class java.lang.Integer}// 3. 获取方法返回值的泛型类型Method method = clazz.getMethod("getList");Type returnType = method.getGenericReturnType();System.out.println("返回类型: "+ returnType);// 4. 获取方法的泛型参数Method genericMethod = clazz.getMethod("genericMethod",Object.class);TypeVariable<?>[] typeParams = genericMethod.getTypeParameters();for(TypeVariable<?> tv : typeParams){System.out.println("泛型参数名: "+ tv.getName());// T}}}

7.2 数组操作

importjava.lang.reflect.Array;publicclassArrayReflectionDemo{publicstaticvoidmain(String[] args){// 1. 创建数组Object intArray =Array.newInstance(int.class,5);Array.set(intArray,0,10);Array.set(intArray,1,20);System.out.println("第一个元素: "+Array.get(intArray,0));// 10System.out.println("数组长度: "+Array.getLength(intArray));// 5// 2. 创建多维数组Object multiArray =Array.newInstance(int.class,3,4);System.out.println("多维数组类型: "+ multiArray.getClass());// class [[I// 3. 动态扩展数组int[] oldArray ={1,2,3};int[] newArray =(int[])expandArray(oldArray,6);System.out.println("新数组长度: "+ newArray.length);// 6System.out.println("第一个元素: "+ newArray[0]);// 1}// 通用数组扩展方法publicstaticObjectexpandArray(Object oldArray,int newLength){Class<?> componentType = oldArray.getClass().getComponentType();int oldLength =Array.getLength(oldArray);Object newArray =Array.newInstance(componentType, newLength);// 复制旧数组内容System.arraycopy(oldArray,0, newArray,0,Math.min(oldLength, newLength));return newArray;}}

7.3 性能优化

importjava.lang.reflect.*;importjava.util.concurrent.ConcurrentHashMap;publicclassReflectionCache{// 缓存Class对象privatestaticfinalConcurrentHashMap<String,Class<?>> classCache =newConcurrentHashMap<>();// 缓存Method对象privatestaticfinalConcurrentHashMap<String,Method> methodCache =newConcurrentHashMap<>();// 缓存Field对象privatestaticfinalConcurrentHashMap<String,Field> fieldCache =newConcurrentHashMap<>();// 获取Class(带缓存)publicstaticClass<?>getClass(String className)throwsClassNotFoundException{return classCache.computeIfAbsent(className, key ->{try{returnClass.forName(key);}catch(ClassNotFoundException e){thrownewRuntimeException(e);}});}// 获取Method(带缓存)publicstaticMethodgetMethod(Class<?> clazz,String methodName,Class<?>... paramTypes){String key = clazz.getName()+"#"+ methodName;return methodCache.computeIfAbsent(key, k ->{try{Method method = clazz.getMethod(methodName, paramTypes); method.setAccessible(true);// 提前设置,避免每次调用return method;}catch(NoSuchMethodException e){thrownewRuntimeException(e);}});}// 获取Field(带缓存)publicstaticFieldgetField(Class<?> clazz,String fieldName){String key = clazz.getName()+"#"+ fieldName;return fieldCache.computeIfAbsent(key, k ->{try{Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true);return field;}catch(NoSuchFieldException e){thrownewRuntimeException(e);}});}// 性能测试publicstaticvoidmain(String[] args)throwsException{Class<String> clazz =String.class;Method method = clazz.getMethod("length");// 测试1:不使用缓存long start1 =System.nanoTime();for(int i =0; i <100000; i++){Method m = clazz.getMethod("length");}long end1 =System.nanoTime();System.out.println("不使用缓存: "+(end1 - start1)/1000000+"ms");// 测试2:使用缓存long start2 =System.nanoTime();for(int i =0; i <100000; i++){Method m =getMethod(clazz,"length");}long end2 =System.nanoTime();System.out.println("使用缓存: "+(end2 - start2)/1000000+"ms");}}

7.4 方法句柄(MethodHandle)

MethodHandle 是 JDK 7 引入的,性能比反射更好。

importjava.lang.invoke.*;publicclassMethodHandleDemo{publicstaticvoidmain(String[] args)throwsThrowable{// 1. 获取MethodHandles.LookupMethodHandles.Lookup lookup =MethodHandles.lookup();// 2. 查找方法MethodType mt =MethodType.methodType(int.class);MethodHandle mh = lookup.findVirtual(String.class,"length", mt);// 3. 调用方法String str ="Hello";int length =(int) mh.invoke(str);System.out.println("字符串长度: "+ length);// 5// 4. 性能对比performanceTest();}publicstaticvoidperformanceTest()throwsThrowable{String str ="Hello World";int iterations =10000000;// 直接调用long start1 =System.nanoTime();for(int i =0; i < iterations; i++){int len = str.length();}long end1 =System.nanoTime();System.out.println("直接调用: "+(end1 - start1)/1000000+"ms");// 反射调用Method method =String.class.getMethod("length");long start2 =System.nanoTime();for(int i =0; i < iterations; i++){int len =(int) method.invoke(str);}long end2 =System.nanoTime();System.out.println("反射调用: "+(end2 - start2)/1000000+"ms");// MethodHandle调用MethodHandles.Lookup lookup =MethodHandles.lookup();MethodType mt =MethodType.methodType(int.class);MethodHandle mh = lookup.findVirtual(String.class,"length", mt);long start3 =System.nanoTime();for(int i =0; i < iterations; i++){int len =(int) mh.invoke(str);}long end3 =System.nanoTime();System.out.println("MethodHandle: "+(end3 - start3)/1000000+"ms");}}

性能对比结果(参考):

  • 直接调用:~5ms
  • MethodHandle:~50ms(比直接调用慢10倍)
  • 反射调用:~500ms(比直接调用慢100倍)

7.5 简单ORM框架

importjava.lang.annotation.*;importjava.lang.reflect.*;importjava.sql.*;importjava.util.*;// 表名注解@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@interfaceTable{Stringvalue();}// 列名注解@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)@interfaceColumn{Stringvalue();}// 实体类@Table("users")classUser{@Column("id")privateLong id;@Column("username")privateString username;@Column("age")privateInteger age;// getters and setters...publicLonggetId(){return id;}publicvoidsetId(Long id){this.id = id;}publicStringgetUsername(){return username;}publicvoidsetUsername(String username){this.username = username;}publicIntegergetAge(){return age;}publicvoidsetAge(Integer age){this.age = age;}@OverridepublicStringtoString(){return"User{id="+ id +",+ username +"', age="+ age +"}";}}// 简单ORMpublicclassSimpleORM{// 查询所有publicstatic<T>List<T>findAll(Class<T> clazz,Connection conn)throwsException{// 获取表名Table table = clazz.getAnnotation(Table.class);String tableName = table.value();// 执行查询String sql ="SELECT * FROM "+ tableName;Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery(sql);// 映射结果List<T> results =newArrayList<>();while(rs.next()){T obj =mapResultSet(clazz, rs); results.add(obj);} rs.close(); stmt.close();return results;}// 根据ID查询publicstatic<T>TfindById(Class<T> clazz,Connection conn,Object id)throwsException{Table table = clazz.getAnnotation(Table.class);String tableName = table.value();String sql ="SELECT * FROM "+ tableName +" WHERE id = ?";PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setObject(1, id);ResultSet rs = pstmt.executeQuery();T result =null;if(rs.next()){ result =mapResultSet(clazz, rs);} rs.close(); pstmt.close();return result;}// 插入publicstatic<T>voidinsert(T obj,Connection conn)throwsException{Class<?> clazz = obj.getClass();Table table = clazz.getAnnotation(Table.class);String tableName = table.value();// 构建SQLStringBuilder columns =newStringBuilder();StringBuilder values =newStringBuilder();List<Object> params =newArrayList<>();Field[] fields = clazz.getDeclaredFields();for(Field field : fields){if(field.isAnnotationPresent(Column.class)){Column column = field.getAnnotation(Column.class); field.setAccessible(true);Object value = field.get(obj);if(value !=null){if(columns.length()>0){ columns.append(", "); values.append(", ");} columns.append(column.value()); values.append("?"); params.add(value);}}}String sql ="INSERT INTO "+ tableName +" ("+ columns +") VALUES ("+ values +")";PreparedStatement pstmt = conn.prepareStatement(sql);for(int i =0; i < params.size(); i++){ pstmt.setObject(i +1, params.get(i));} pstmt.executeUpdate(); pstmt.close();}// 映射ResultSet到对象privatestatic<T>TmapResultSet(Class<T> clazz,ResultSet rs)throwsException{T obj = clazz.getDeclaredConstructor().newInstance();Field[] fields = clazz.getDeclaredFields();for(Field field : fields){if(field.isAnnotationPresent(Column.class)){Column column = field.getAnnotation(Column.class);String columnName = column.value(); field.setAccessible(true);Object value = rs.getObject(columnName); field.set(obj, value);}}return obj;}// 测试(需要数据库连接)publicstaticvoidmain(String[] args){// 示例代码,实际需要数据库连接System.out.println("简单ORM框架示例");System.out.println("使用反射实现对象关系映射");}}

7.6 Bean拷贝工具

importjava.lang.reflect.Field;importjava.util.*;publicclassBeanUtils{// 浅拷贝publicstatic<T>TshallowCopy(T source)throwsException{if(source ==null)returnnull;@SuppressWarnings("unchecked")Class<T> clazz =(Class<T>) source.getClass();T target = clazz.getDeclaredConstructor().newInstance();Field[] fields = clazz.getDeclaredFields();for(Field field : fields){ field.setAccessible(true);Object value = field.get(source); field.set(target, value);}return target;}// 属性拷贝(不同类型)publicstaticvoidcopyProperties(Object source,Object target)throwsException{if(source ==null|| target ==null)return;Class<?> sourceClass = source.getClass();Class<?> targetClass = target.getClass();Field[] sourceFields = sourceClass.getDeclaredFields();Map<String,Field> targetFieldMap =newHashMap<>();for(Field field : targetClass.getDeclaredFields()){ targetFieldMap.put(field.getName(), field);}for(Field sourceField : sourceFields){String fieldName = sourceField.getName();Field targetField = targetFieldMap.get(fieldName);if(targetField !=null&& sourceField.getType()== targetField.getType()){ sourceField.setAccessible(true); targetField.setAccessible(true);Object value = sourceField.get(source); targetField.set(target, value);}}}// 对象转MappublicstaticMap<String,Object>toMap(Object obj)throwsException{if(obj ==null)returnnull;Map<String,Object> map =newHashMap<>();Class<?> clazz = obj.getClass();Field[] fields = clazz.getDeclaredFields();for(Field field : fields){ field.setAccessible(true);String key = field.getName();Object value = field.get(obj); map.put(key, value);}return map;}// Map转对象publicstatic<T>TfromMap(Map<String,Object> map,Class<T> clazz)throwsException{if(map ==null)returnnull;T obj = clazz.getDeclaredConstructor().newInstance();Field[] fields = clazz.getDeclaredFields();for(Field field : fields){ field.setAccessible(true);String key = field.getName();Object value = map.get(key);if(value !=null){ field.set(obj, value);}}return obj;}publicstaticvoidmain(String[] args)throwsException{// 测试对象转MapUser user =newUser(); user.setId(1L); user.setUsername("张三"); user.setAge(25);Map<String,Object> map =toMap(user);System.out.println("对象转Map: "+ map);// 测试Map转对象User user2 =fromMap(map,User.class);System.out.println("Map转对象: "+ user2);}}

八、最佳实践与注意事项

8.1 性能优化建议

publicclassReflectionBestPractices{// ❌ 不推荐:每次都获取MethodpublicvoidbadPractice(Object obj)throwsException{for(int i =0; i <10000; i++){Method method = obj.getClass().getMethod("toString"); method.invoke(obj);}}// ✅ 推荐:缓存Method对象privatestaticfinalMap<String,Method> methodCache =newConcurrentHashMap<>();publicvoidgoodPractice(Object obj)throwsException{Method method = methodCache.computeIfAbsent( obj.getClass().getName()+"#toString", k ->{try{Method m = obj.getClass().getMethod("toString"); m.setAccessible(true);// 提前设置return m;}catch(NoSuchMethodException e){thrownewRuntimeException(e);}});for(int i =0; i <10000; i++){ method.invoke(obj);}}}

性能优化要点:

  1. 缓存 Class、Method、Field、Constructor 对象
  2. 提前调用 setAccessible(true),避免每次检查
  3. 使用 MethodHandle 替代反射(JDK 7+)
  4. 避免在循环中使用反射
  5. 考虑使用字节码生成(如 ASM、Javassist)

8.2 异常处理

反射操作会抛出多种异常,需要妥善处理。

publicclassReflectionExceptionHandling{publicstaticObjectinvokeMethod(Object obj,String methodName,Object... args){try{Class<?> clazz = obj.getClass();Class<?>[] paramTypes =newClass[args.length];for(int i =0; i < args.length; i++){ paramTypes[i]= args[i].getClass();}Method method = clazz.getMethod(methodName, paramTypes);return method.invoke(obj, args);}catch(NoSuchMethodException e){System.err.println("方法不存在: "+ methodName);}catch(IllegalAccessException e){System.err.println("无法访问方法: "+ methodName);}catch(InvocationTargetException e){System.err.println("方法执行异常: "+ e.getCause());}catch(Exception e){System.err.println("未知异常: "+ e.getMessage());}returnnull;}}

常见异常:

异常说明解决方案
ClassNotFoundException类不存在检查类名和类路径
NoSuchMethodException方法不存在检查方法名和参数类型
NoSuchFieldException字段不存在检查字段名
IllegalAccessException无法访问使用 setAccessible(true)
InvocationTargetException方法执行异常获取 getCause() 查看真实异常
InstantiationException无法实例化确保有无参构造方法

8.3 安全性考虑

publicclassReflectionSecurity{publicstaticvoidmain(String[] args){// 1. 检查SecurityManagerSecurityManager sm =System.getSecurityManager();if(sm !=null){try{ sm.checkPermission(newReflectPermission("suppressAccessChecks"));}catch(SecurityException e){System.err.println("没有反射权限");return;}}// 2. 谨慎使用setAccessibletry{Field field =SomeClass.class.getDeclaredField("privateField");// ⚠️ 破坏封装性,谨慎使用 field.setAccessible(true);}catch(Exception e){ e.printStackTrace();}// 3. 验证输入String className =getUserInput();if(!isValidClassName(className)){thrownewIllegalArgumentException("非法类名");}}privatestaticbooleanisValidClassName(String className){// 白名单验证return className.matches("^[a-zA-Z0-9.]+$");}privatestaticStringgetUserInput(){return"com.example.MyClass";}staticclassSomeClass{privateString privateField;}}

安全建议:

  • 不要反射用户输入的类名(可能导致代码注入)
  • 谨慎使用 setAccessible(true)
  • 在生产环境考虑禁用反射
  • 使用白名单验证类名和方法名
  • 注意 SecurityManager 的限制

8.4 线程安全

publicclassReflectionThreadSafety{// ✅ 线程安全:使用ConcurrentHashMapprivatestaticfinalConcurrentHashMap<String,Method> cache =newConcurrentHashMap<>();// ❌ 不安全:HashMap在多线程下可能出问题// private static final HashMap<String, Method> cache = new HashMap<>();publicstaticMethodgetMethod(Class<?> clazz,String methodName)throwsNoSuchMethodException{String key = clazz.getName()+"#"+ methodName;return cache.computeIfAbsent(key, k ->{try{return clazz.getMethod(methodName);}catch(NoSuchMethodException e){thrownewRuntimeException(e);}});}}

8.5 常见陷阱

publicclassReflectionPitfalls{publicstaticvoidmain(String[] args)throwsException{// 陷阱1:基本类型 vs 包装类型Method method1 =MyClass.class.getMethod("method",int.class);// ✅ 正确// Method method2 = MyClass.class.getMethod("method", Integer.class); // ❌ 错误// 陷阱2:数组类型Method arrayMethod =MyClass.class.getMethod("arrayMethod",int[].class);// ✅ 正确// Method arrayMethod2 = MyClass.class.getMethod("arrayMethod", int.class); // ❌ 错误// 陷阱3:可变参数Method varargMethod =MyClass.class.getMethod("varargMethod",String[].class);// ✅ 正确// 陷阱4:私有构造方法Constructor<MyClass> constructor =MyClass.class.getDeclaredConstructor(); constructor.setAccessible(true);// 必须设置MyClass obj = constructor.newInstance();// 陷阱5:静态字段/方法Field staticField =MyClass.class.getDeclaredField("staticField"); staticField.set(null,"new value");// 静态字段传nullMethod staticMethod =MyClass.class.getMethod("staticMethod"); staticMethod.invoke(null);// 静态方法传null}staticclassMyClass{privatestaticString staticField ="old value";privateMyClass(){}publicvoidmethod(int param){}publicvoidarrayMethod(int[] array){}publicvoidvarargMethod(String... args){}publicstaticvoidstaticMethod(){}}}

九、快速参考

反射核心类

说明主要方法
Class类的字节码对象forName(), newInstance(), getMethod()
Constructor构造方法newInstance(), setAccessible()
Field字段get(), set(), setAccessible()
Method方法invoke(), setAccessible()
Modifier修饰符工具类isPublic(), isStatic(), isFinal()

常用方法对比

方法说明访问范围
getXxx()获取public成员public(含继承)
getDeclaredXxx()获取所有成员所有(不含继承)

获取Class对象的三种方式

// 方式1:类名.class(编译时已知)Class<String> clazz1 =String.class;// 方式2:对象.getClass()(运行时获取)String str ="Hello";Class<?extendsString> clazz2 = str.getClass();// 方式3:Class.forName()(动态加载)Class<?> clazz3 =Class.forName("java.lang.String");

反射操作速查表

操作代码示例
创建对象clazz.getDeclaredConstructor().newInstance()
获取字段值field.get(obj)
设置字段值field.set(obj, value)
调用方法method.invoke(obj, args)
访问私有成员member.setAccessible(true)
判断类型clazz.isAssignableFrom(subClass)
获取注解clazz.getAnnotation(Ann.class)
获取泛型field.getGenericType()

性能对比(参考值)

操作方式相对性能适用场景
直接调用1x(基准)常规开发
MethodHandle10x需要动态调用且关注性能
反射(有缓存)50x框架开发
反射(无缓存)100x避免使用

最佳实践清单

✅ 推荐做法:

  • 仅在必要时使用反射(框架、工具类)
  • 缓存 Class、Method、Field 对象
  • 提前调用 setAccessible(true)
  • 使用 try-catch 处理所有可能的异常
  • 考虑使用 MethodHandle 替代反射
  • 在性能敏感场景避免使用反射
  • 使用白名单验证类名和方法名
  • 充分的代码注释和文档

❌ 避免做法:

  • 不要在循环中频繁使用反射
  • 不要反射用户输入的类名(安全风险)
  • 不要忽略异常处理
  • 不要在性能关键路径使用反射
  • 不要过度使用 setAccessible(true)
  • 不要在多线程环境使用非线程安全的缓存

十、总结

本文档全面介绍了 Java 反射机制的核心知识:

1. 反射概述

  • 反射的定义和核心功能
  • 应用场景(框架开发、动态代理、注解处理)
  • 优缺点分析

2. 获取Class对象

  • 三种获取方式及使用场景
  • 获取类信息(名称、包、父类、接口、修饰符)
  • 类型判断和继承关系检查
  • 注解获取

3. 构造方法反射

  • 获取构造方法(public和private)
  • 创建对象的多种方式
  • 访问私有构造方法

4. 字段反射

  • 获取字段信息
  • 访问和修改字段值
  • 处理静态字段

5. 方法反射

  • 获取方法信息
  • 调用方法(public、private、static)
  • 方法参数和返回值处理

6. 实战案例

  • 通用对象打印器
  • 简单依赖注入
  • 通用对象复制
  • 动态代理
  • 配置文件加载

7. 高级应用

  • 泛型信息获取
  • 数组操作
  • 性能优化(缓存机制)
  • MethodHandle(性能更好的替代方案)
  • 简单ORM框架
  • Bean拷贝工具

8. 最佳实践

  • 性能优化建议
  • 异常处理
  • 安全性考虑
  • 线程安全
  • 常见陷阱

关键要点

主题核心内容
获取Class三种方式:类名.class、对象.getClass()、Class.forName()
访问控制使用 setAccessible(true) 访问私有成员
性能优化缓存反射对象,考虑使用 MethodHandle
异常处理处理多种反射异常,获取真实异常原因
安全性验证输入,谨慎使用 setAccessible
线程安全使用 ConcurrentHashMap 缓存

使用场景

场景是否使用反射说明
框架开发✅ 推荐Spring、Hibernate等
动态代理✅ 推荐AOP实现
注解处理✅ 推荐运行时处理注解
插件系统✅ 推荐动态加载类
序列化✅ 推荐JSON、XML转换
常规业务❌ 不推荐性能差,可读性差
性能敏感❌ 不推荐使用直接调用

学习路径

  1. 入门阶段:掌握Class对象获取、基本的字段和方法操作
  2. 进阶阶段:理解构造方法、注解、泛型信息获取
  3. 高级阶段:掌握性能优化、MethodHandle、动态代理
  4. 实战阶段:实现简单框架(依赖注入、ORM)

推荐资源

  • Java官方文档 - Reflection API
  • 《Java核心技术》卷1 - 第5章
  • 《Effective Java》- 第65条:优先考虑接口而不是反射
  • 《深入理解Java虚拟机》- 第7章

下一步

  • 深入学习动态代理(JDK动态代理、CGLIB)
  • 了解字节码操作(ASM、Javassist、ByteBuddy)
  • 学习注解处理器(APT)
  • 研究主流框架的反射应用(Spring、MyBatis)
  • 实践:开发一个简单的依赖注入容器

记住:反射是一把双刃剑,强大但有代价。在追求灵活性的同时,要权衡性能、安全性和代码可维护性。只在真正需要的地方使用反射,并遵循最佳实践。

Read more

基于腾讯云HAI + DeepSeek快速设计自己的个人网页

基于腾讯云HAI + DeepSeek快速设计自己的个人网页

前言:通过结合腾讯云HAI 强大的云端运算能力与DeepSeek先进的 AI技术,本文介绍高效、便捷且低成本的设计一个自己的个人网页。你将了解到如何轻松绕过常见的技术阻碍,在腾讯云HAI平台上快速部署DeepSeek模型,仅需简单几步,就能获取一个包含个人简介、技能特长、项目经历及联系方式等核心板块的响应式网页。 目录 一、DeepSeek模型部署在腾讯云HAI 二、设计个人网页 一、DeepSeek模型部署在腾讯云HAI 把 DeepSeek 模型部署于腾讯云 HAI,用户便能避开官网访问限制,直接依托腾讯云 HAI 的超强算力运行 DeepSeek-R1 等模型。这一举措不仅降低了技术门槛,还缩短了部署时间,削减了成本。尤为关键的是,凭借 HAI 平台灵活且可扩展的特性,用户能够依据自身特定需求定制专属解决方案,进而更出色地适配特定业务场景,满足各类技术要求 。 点击访问腾讯云HAI控制台地址: 算力管理 - 高性能应用服务 - 控制台 腾讯云高性能应用服务HAI已支持DeepSeek-R1模型预装环境和CPU算力,只需简单的几步就能调用DeepSeek - R1

By Ne0inhk
AI革命先锋:DeepSeek与蓝耘通义万相2.1的无缝融合引领行业智能化变革

AI革命先锋:DeepSeek与蓝耘通义万相2.1的无缝融合引领行业智能化变革

云边有个稻草人-ZEEKLOG博客 目录 引言 一、什么是DeepSeek? 1.1 DeepSeek平台概述 1.2 DeepSeek的核心功能与技术 二、蓝耘通义万相2.1概述 2.1 蓝耘科技简介 2.2 蓝耘通义万相2.1的功能与优势 1. 全链条智能化解决方案 2. 强大的数据处理能力 3. 高效的模型训练与优化 4. 自动化推理与部署 5. 行业专用解决方案 三、蓝耘通义万相2.1与DeepSeek的对比分析 3.1 核心区别 3.2 结合使用的优势 四、蓝耘注册流程 五、DeepSeek与蓝耘通义万相2.1的集成应用 5.1 集成应用场景 1. 智能医疗诊断

By Ne0inhk
如何通过 3 个简单步骤在 Windows 上本地运行 DeepSeek

如何通过 3 个简单步骤在 Windows 上本地运行 DeepSeek

它是免费的——社区驱动的人工智能💪。         当 OpenAI 第一次推出定制 GPT 时,我就明白会有越来越多的人为人工智能做出贡献,并且迟早它会完全由社区驱动。         但从来没有想过它会如此接近😂让我们看看如何在 Windows 机器上完全免费使用第一个开源推理模型!  步骤 0:安装 Docker 桌面         我确信很多人已经安装了它,所以可以跳过,但如果没有 — — 这很简单,只需访问Docker 的官方网站,下载并运行安装 👍         如果您需要一些特定的设置,例如使用 WSL,那么有很多指导视频,请查看!我将继续下一步。 步骤 1:安装 CUDA 以获得 GPU 支持         如果您想使用 Nvidia 显卡运行 LLM,则必须安装 CUDA 驱动程序。(嗯……是的,它们需要大量的计算能力)         打开CUDA 下载页面,

By Ne0inhk
在 VSCode 中本地运行 DeepSeek,打造强大的私人 AI

在 VSCode 中本地运行 DeepSeek,打造强大的私人 AI

本文将分步向您展示如何在本地安装和运行 DeepSeek、使用 CodeGPT 对其进行配置以及开始利用 AI 来增强您的软件开发工作流程,所有这些都无需依赖基于云的服务。  步骤 1:在 VSCode 中安装 Ollama 和 CodeGPT         要在本地运行 DeepSeek,我们首先需要安装Ollama,它允许我们在我们的机器上运行 LLM,以及CodeGPT,它是集成这些模型以提供编码辅助的 VSCode 扩展。 安装 Ollama Ollama 是一个轻量级平台,可以轻松运行本地 LLM。 下载Ollama 访问官方网站:https://ollama.com * 下载适合您的操作系统(Windows、macOS 或 Linux)的安装程序。 * 验证安装 安装后,打开终端并运行: ollama --version  如果 Ollama 安装正确,

By Ne0inhk