反射
1. 反射的定义
- 反射即反向探知,有点类似考古学家根据发掘的物品来探知以前的事情
- 在Java程序运行状态中:
- 对于给定的一个类(Class)对象,可以获得这个类(Class)对象的所有属性和方法;
- 对于给定的一个对象( new ClassName < ? extends Object> ),都能够调用它的任意一个属性和方法
这种动态获取类的内容以及动态调用对象的方法和获取属性的机制,就叫做JAVA的反射机制。
2. 反射的优缺点
优点:
- 增加程序的灵活性,避免固有逻辑写死到程序中
- 代码相对简洁,可以提高程序的复用性
| public interface Ball { |
| public void playBall(); |
| } |
| |
| class BasketBall implements Ball { |
| @Override |
| public void playBall() { |
| System.out.println("一起打篮球。。。。"); |
| } |
| } |
| class FootBall implements Ball { |
| @Override |
| public void playBall() { |
| System.out.println("一起踢足球。。。。"); |
| } |
| } |
| class BallMain { |
| public static void main(String[] args) throws Exception { |
| System.out.println(getNewInstanceByKey("BasketBall")); |
| System.out.println(getNewInstanceByKey("FootBall")); |
| } |
| public static Ball getInstanceByKey (String key) { |
| if ("BasketBall".equals(key)) { |
| return new BasketBall(); |
| } else if ("FootBall".equals(key)) { |
| return new FootBall(); |
| } |
| |
| return null; |
| } |
| public static Ball getNewInstanceByKey (String key) throws Exception { |
| String basePackage = "com.elian.reflex"; |
| Ball ball = null; |
| Class<?> clazz = Class.forName(basePackage + "." + key); |
| ball = (Ball) clazz.newInstance(); |
| return ball; |
| } |
| } |
缺点:
- 相比于直接调用,反射有比较大的性能消耗
- 内部暴露和安全隐患
反射到底慢在哪里?
- 调用了native方法
- 每次new Instance都会做安全检查 比较耗时
3. 深入class内部

3.1 基本操作
1) 获取类对象的4种方式
| public class ReflexTest { |
| public static void main(String[] args) throws Exception { |
| Class<Person> p1 = Person.class; |
| Class<?> p2 = Class.forName("com.elian.reflex.Person"); |
| Class<? extends Person> p3 = new Person().getClass(); |
| Class<?> p4 = ReflexTest.class.getClassLoader().loadClass("com.elian.reflex.Person"); |
| } |
| } |
2) 基本操作
| |
| int modifiers = p1.getModifiers(); |
| p1.getPackage() |
| p1.getName() |
| p1.getSuperclass() |
| p1.getClassLoader() |
| p1.getSimpleName() |
| p1.getInterfaces() |
| p1.getAnnotations() |
3) 字段的操作
| public static void main(String[] args) throws Exception { |
| |
| Class<Person> clazz = Person.class; |
| Person person = clazz.newInstance(); |
| |
| Field[] clazzFields = clazz.getFields(); |
| Field[] declaredFields = clazz.getDeclaredFields(); |
| |
| for (Field field : |
| clazzFields) { |
| System.out.println(field.getModifiers() + " " + field.getName()); |
| } |
| System.out.println( "========" ); |
| for (Field field : |
| declaredFields) { |
| System.out.println(field.getModifiers() + " " + field.getName()); |
| } |
| |
| Field nameField = clazz.getDeclaredField("name"); |
| nameField.setAccessible(true); |
| nameField.set(person, "Elian"); |
| |
| |
| Field addressField = clazz.getDeclaredField("address"); |
| addressField.set(null, "北京通州"); |
| } |
4) 对方法的操作
| public static void main(String[] args) throws Exception { |
| Person person = new Person(); |
| Class<Person> clazz = Person.class; |
| Method[] methods = clazz.getMethods(); |
| Method[] declaredMethods = clazz.getDeclaredMethods(); |
| for (Method method : |
| methods) { |
| System.out.println( method.getModifiers() + " " + method.getName() ); |
| } |
| System.out.println( "================" ); |
| for (Method method : |
| declaredMethods) { |
| System.out.println( method.getModifiers() + " " + method.getName() ); |
| } |
| |
| Method jump = clazz.getDeclaredMethod("jump"); |
| jump.invoke(person); |
| |
| Field address = clazz.getDeclaredField("address"); |
| address.setAccessible(true); |
| address.set(null, "北京通州"); |
| |
| Method getAddress = clazz.getDeclaredMethod("getAddress"); |
| getAddress.setAccessible(true); |
| System.out.println(getAddress.invoke(null)); |
| } |
5) 对构造器的 操作
| public static void main(String[] args) throws Exception { |
| Class<Person> clazz = Person.class; |
| Constructor<?>[] constructors = clazz.getConstructors(); |
| Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); |
| for (Constructor constructor : |
| constructors) { |
| System.out.println(constructor.getModifiers() + " " + constructor.getName()); |
| } |
| System.out.println("==============="); |
| for (Constructor constructor : |
| declaredConstructors) { |
| System.out.println(constructor.getModifiers() + " " + constructor.getName()); |
| } |
| |
| |
| |
| Person person1 = clazz.newInstance(); |
| |
| |
| Constructor<Person> declaredConstructor = clazz.getDeclaredConstructor(String.class); |
| declaredConstructor.setAccessible(true); |
| Person person2 = declaredConstructor.newInstance("Elian"); |
| System.out.println(person2.getName()); |
| } |
漏洞:对于单例的对象来说,能够调用私有的构造器创建新的对象,比较危险,所以应在代码中控制对象的创建。
| public class SinglePerson { |
| private static final SinglePerson instance = new SinglePerson(); |
| |
| public static SinglePerson getInstance() { |
| return instance; |
| } |
| |
| private SinglePerson() { |
| if (instance != null) |
| throw new RuntimeException( "The instance of SinglePerson has been created and cannot be created it again" ); |
| } |
| |
| public static void main(String[] args) { |
| SinglePerson s1 = SinglePerson.getInstance(); |
| SinglePerson s2 = SinglePerson.getInstance(); |
| |
| System.out.println(s1); |
| System.out.println(s2); |
| } |
| } |
3.2 反射的使用场景
- jdbc的封装
- Spring中的IoC
- jdbcTemplate
- MyBatis
4. SpringIoC中反射的应用
| public void refresh() throws BeansException, IllegalStateException { |
| synchronized (this.startupShutdownMonitor) { |
| prepareRefresh(); |
| |
| |
| ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); |
| prepareBeanFactory(beanFactory); |
| try { |
| postProcessBeanFactory(beanFactory); |
| invokeBeanFactoryPostProcessors(beanFactory); |
| registerBeanPostProcessors(beanFactory); |
| initMessageSource(); |
| initApplicationEventMulticaster(); |
| |
| onRefresh(); |
| registerListeners(); |
| |
| finishBeanFactoryInitialization(beanFactory); |
| finishRefresh(); |
| } |
| catch (BeansException ex) { |
| if (logger.isWarnEnabled()) { |
| logger.warn("Exception encountered during context initialization - " + |
| "cancelling refresh attempt: " + ex); |
| } |
| destroyBeans(); |
| cancelRefresh(ex); |
| throw ex; |
| } |
| |
| finally { |
| resetCommonCaches(); |
| } |
| } |
| } |
| |
| '===========================' |
| |
| public abstract class BeanUtils { |
| |
| |
| public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException { |
| Assert.notNull(ctor, "Constructor must not be null"); |
| try { |
| ReflectionUtils.makeAccessible(ctor); |
| return ctor.newInstance(args); |
| } |
| catch (InstantiationException ex) { |
| throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex); |
| } |
| catch (IllegalAccessException ex) { |
| throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex); |
| } |
| catch (IllegalArgumentException ex) { |
| throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex); |
| } |
| catch (InvocationTargetException ex) { |
| throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException()); |
| } |
| } |
| |
| |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)