四、反射机制 阳光穿透心脏的1/2处 2022-11-05 08:48 241阅读 0赞 # 1. 定义 # * 反向探知,在程序运行过程中动态获取类的相关属性。 * 对于给定的一个类,可以获取类的所有属性和方法。 # 2. 使用 # public class User { public void sayHello() { System.out.println("hello"); } } public class Test { public static void main(String[] args) throws Exception { Class<User> clazz = User.class; //获取一个类对象 User user = clazz.newInstance(); //获取一个实例对象 Method method = clazz.getDeclaredMethod("sayHello"); //获取类中的方法 method.invoke(user); //通过反射执行方法 } } # 3. 反射的优缺点 # ## 优点 ## * 增加程序的灵活性,避免固有逻辑写死到程序中 * 代码相当简洁,可以提高程序的复用性 public class Test { public static void main(String[] args) throws Exception { Animal animal = sayHello("cat"); animal.sayHello(); } // 现在Animal下有两个实现类,两个判断,但是如果新添加一个实现类,还需要再次修改这块代码,不够灵活 public static Animal sayHello(String name) { if ("dog".equals(name)) { return new Dog(); } if ("cat".equals(name)) { return new Cat(); } return null; } } 使用反射改进,增加灵活性 public class Test { public static void main(String[] args) throws Exception { Animal animal = sayHello(Cat.class.getName()); animal.sayHello(); } // 添加新的实现类,只需要传入新实现类的全路径名即可,不用修改这块代码 public static Animal sayHello(String name) { try { // 根据类的全路径名反射获取类 Class clazz = Class.forName(name); return (Animal) clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); } return null; } } 上面只是举例说明反射的灵活性,实际中并不建议这样用,可以用Java多态的特性“声明接口,创建实现类”实现这一点 public class Test { public static void main(String[] args) throws Exception { Animal animal = new Cat(); //声明接口Animal,创建实现类Cat Animal animal2 = new Dog(); //声明接口Animal,创建实现类Dog animal.sayHello(); animal2.sayHello(); } } ## 缺点 ## * 相比于直接调用,反射有比较大的性能消耗,速度比较慢 * 内部暴露和安全隐患 性能比较 public class Test { public static void main(String[] args) throws Exception { long startTime = System.currentTimeMillis(); int length = 10000; for (int i = 0; i < length; i++) { Animal animal = new Cat(); animal.sayHello(); } long endTime = System.currentTimeMillis(); System.out.println("对象调用"+ length +"次耗时:" + (endTime-startTime) + " ms"); long startTime2 = System.currentTimeMillis(); for (int i = 0; i < length; i++) { Animal animal = sayHello(Cat.class.getName()); animal.sayHello(); } long endTime2 = System.currentTimeMillis(); System.out.println("反射调用"+ length +"次耗时:" + (endTime2-startTime2) + " ms"); } } ![20210305002357894.png][] ## 反射慢的原因 ## * 调用了native方法 * 每次newInstance都会做安全检查,比较耗时 # 4. 反射的操作 # 反射获取类对象的方式 Class clazz = Cat.class; Class clazz2 = Class.forName("com.lucifer.tree.Cat"); Class clazz3 = new Cat().getClass(); Class clazz4 = clazz3.getClassLoader().loadClass("com.lucifer.tree.Cat"); 反射获取类的相关结构 int clazzModifier = clazz.getModifiers(); // 获取类的修饰符 1 Package clazzPackage = clazz.getPackage(); // package com.lucifer.tree String clazzName = clazz.getName(); // com.lucifer.tree.Cat String canonicalName = clazz.getCanonicalName(); // com.lucifer.tree.Cat String simpleName = clazz.getSimpleName(); // Cat ClassLoader classLoader = clazz.getClassLoader(); // sun.misc.Launcher$AppClassLoader@18b4aac2 Class superClass = clazz.getSuperclass(); // class java.lang.Object Annotation[] annotations = clazz.getAnnotations(); // [Ljava.lang.annotation.Annotation;@677327b6 Class<?>[] interfaces = clazz.getInterfaces(); //[Ljava.lang.Class;@14ae5a5 <table> java.lang.reflect. <a href="https://www.matools.com/file/manual/jdk_api_1.8_google/java/lang/reflect/Modifier.html" rel="nofollow">Modifier</a> <tbody> <tr> <th>Modifier and Type</th> <th>Constant Field</th> <th>Value</th> </tr> </tbody> <tbody> <tr> <td><a rel="nofollow"></a><code>public static final int</code></td> <td><code><a href="https://www.matools.com/file/manual/jdk_api_1.8_google/java/lang/reflect/Modifier.html#ABSTRACT" rel="nofollow">ABSTRACT</a></code></td> <td><code>1024</code></td> </tr> <tr> <td><a rel="nofollow"></a><code>public static final int</code></td> <td><code><a href="https://www.matools.com/file/manual/jdk_api_1.8_google/java/lang/reflect/Modifier.html#FINAL" rel="nofollow">FINAL</a></code></td> <td><code>16</code></td> </tr> <tr> <td><a rel="nofollow"></a><code>public static final int</code></td> <td><code><a href="https://www.matools.com/file/manual/jdk_api_1.8_google/java/lang/reflect/Modifier.html#INTERFACE" rel="nofollow">INTERFACE</a></code></td> <td><code>512</code></td> </tr> <tr> <td><a rel="nofollow"></a><code>public static final int</code></td> <td><code><a href="https://www.matools.com/file/manual/jdk_api_1.8_google/java/lang/reflect/Modifier.html#NATIVE" rel="nofollow">NATIVE</a></code></td> <td><code>256</code></td> </tr> <tr> <td><a rel="nofollow"></a><code>public static final int</code></td> <td><code><a href="https://www.matools.com/file/manual/jdk_api_1.8_google/java/lang/reflect/Modifier.html#PRIVATE" rel="nofollow">PRIVATE</a></code></td> <td><code>2</code></td> </tr> <tr> <td><a rel="nofollow"></a><code>public static final int</code></td> <td><code><a href="https://www.matools.com/file/manual/jdk_api_1.8_google/java/lang/reflect/Modifier.html#PROTECTED" rel="nofollow">PROTECTED</a></code></td> <td><code>4</code></td> </tr> <tr> <td><a rel="nofollow"></a><code>public static final int</code></td> <td><code><a href="https://www.matools.com/file/manual/jdk_api_1.8_google/java/lang/reflect/Modifier.html#PUBLIC" rel="nofollow">PUBLIC</a></code></td> <td><code>1</code></td> </tr> <tr> <td><a rel="nofollow"></a><code>public static final int</code></td> <td><code><a href="https://www.matools.com/file/manual/jdk_api_1.8_google/java/lang/reflect/Modifier.html#STATIC" rel="nofollow">STATIC</a></code></td> <td><code>8</code></td> </tr> <tr> <td><a rel="nofollow"></a><code>public static final int</code></td> <td><code><a href="https://www.matools.com/file/manual/jdk_api_1.8_google/java/lang/reflect/Modifier.html#STRICT" rel="nofollow">STRICT</a></code></td> <td><code>2048</code></td> </tr> <tr> <td><a rel="nofollow"></a><code>public static final int</code></td> <td><code><a href="https://www.matools.com/file/manual/jdk_api_1.8_google/java/lang/reflect/Modifier.html#SYNCHRONIZED" rel="nofollow">SYNCHRONIZED</a></code></td> <td><code>32</code></td> </tr> <tr> <td><a rel="nofollow"></a><code>public static final int</code></td> <td><code><a href="https://www.matools.com/file/manual/jdk_api_1.8_google/java/lang/reflect/Modifier.html#TRANSIENT" rel="nofollow">TRANSIENT</a></code></td> <td><code>128</code></td> </tr> <tr> <td><a rel="nofollow"></a><code>public static final int</code></td> <td><code><a href="https://www.matools.com/file/manual/jdk_api_1.8_google/java/lang/reflect/Modifier.html#VOLATILE" rel="nofollow">VOLATILE</a></code></td> <td><code>64</code></td> </tr> </tbody> </table> 反射获取类的属性 // 获取当前类和父类的公有属性 Field[] fields = clazz.getFields(); // 获取当前类所有属性,包括私有属性 Field[] fields2 = clazz.getDeclaredFields(); // 获取当前类和父类的公有方法 Method[] methods = clazz.getMethods(); // 获取当前类所有方法,包括私有方法 Method[] methods2 = clazz.getDeclaredMethods(); Cat cat = new Cat(); // 调用私有方法 Method privateMethod = clazz.getDeclaredMethod("miaomiao"); privateMethod.setAccessible(true); //获取私有方法需要放开访问权限,否则报错 privateMethod.invoke(cat); // 调用静态方法 Method staticMethod = clazz.getDeclaredMethod("staticMethod"); staticMethod.invoke(null); 反射获取构造器 // 获取所有公有的构造器 Constructor<?>[] constructors = clazz.getConstructors(); // 获取所有构造器,包括私有的 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); // 根据参数类型获取指定构造器 Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class); // 如果是私有构造器,需要放开访问权限 declaredConstructor.setAccessible(true); // 可以通过构造器获取实例对象 declaredConstructor.newInstance("小花"); // 直接通过newInstance获取对象 Cat cat3 = (Cat) clazz.newInstance(); // 底层本质上还是通过构造器获取实例对象 tmpConstructor.newInstance((Object[])null); 单例的漏洞 问题:正常调用单例类对外提供的方法,只能获取到唯一的一个实例,但是通过反射机制可以获取到不同的实例 原因:反射可以调用私有的构造器造成的 // 通过单例对外提供的方法拿到唯一的实例 SingleInstanceClass instanceClass1 = SingleInstanceClass.getInstance(); SingleInstanceClass instanceClass2 = SingleInstanceClass.getInstance(); SingleInstanceClass instanceClass3 = SingleInstanceClass.getInstance(); // 通过反射获取私有构造器,可以获取到新的实例 Constructor declaredConstructor = instanceClass1.getClass().getDeclaredConstructor(); declaredConstructor.setAccessible(true); SingleInstanceClass instanceClass4 = (SingleInstanceClass) declaredConstructor.newInstance(); 解决方法:在私有构造中加入判断逻辑,结合异常处理 public class SingleInstanceClass { public static SingleInstanceClass instance; private SingleInstanceClass() { // 处理通过反射获取实例的漏洞 if (instance != null) { throw new RuntimeException(); } } public static SingleInstanceClass getInstance() { if (instance == null) { instance = new SingleInstanceClass(); } return instance; } } 反射的应用场景 * jdbc封装 Class.forName("com.mysql.cj.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/mysql"; String user = "root"; String pwd = "root"; Connection connection = DriverManager.getConnection(url, user, pwd); * SpringIoC ApplicationContext ac = new ClassPathXmlApplicationContext("spring-ioc.xml"); User user = (User)ac.getBean("user"); // ioc的底层本质上还是反射 public Object getBean(String name) throws BeansException { this.assertBeanFactoryActive(); return this.getBeanFactory().getBean(name); } protected final void refreshBeanFactory() throws BeansException { if (this.hasBeanFactory()) { this.destroyBeans(); this.closeBeanFactory(); } try {// 创建对应IOC容器对象 DefaultListableBeanFactory beanFactory = this.createBeanFactory(); beanFactory.setSerializationId(this.getId()); this.customizeBeanFactory(beanFactory); // 将配置文件中的<bean>解析成一个BeanDefinition对象 this.loadBeanDefinitions(beanFactory); synchronized(this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException var5) { throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5); } } // 获取文件路径 InputStream inputStream = encodedResource.getResource().getInputStream(); // SAX 加载配置文件 Document doc = this.doLoadDocument(inputSource, resource); // 将配置文件解析成BeanDefinition对象 this.registerBeanDefinitions(doc, resource); private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, "import")) { this.importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, "alias")) { this.processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, "bean")) { this.processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, "beans")) { this.doRegisterBeanDefinitions(ele); } } protected abstract Object createBean(String var1, RootBeanDefinition var2, Object[] var3) throws BeanCreationException; Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName); BeanUtils.instantiateClass(constructorToUse, new Object[0]); public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException { ReflectionUtils.makeAccessible(ctor);//放开访问权限 return ctor.newInstance(args);//底层还是使用的反射机制,反射获取构造器获取对象实例 } * jdbcTemplate * Mybatis [20210305002357894.png]: /images/20221023/9abdae39e1b443a7be5496402681e9b3.png
相关 Java 基础学习之反射机制 四(反射机制的深入应用、Array 类常用方法) 反射除了可以取得一个类的完整结构之外,还可以调用类中的指定方法或指定属性,并且可以通过反射完成对数组的操作。 Person 类 package sel... 电玩女神/ 2024年04月17日 22:14/ 0 赞/ 139 阅读
相关 反射机制 反射:框架设计的灵魂 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码 反射:将类的各个组成部分封装为其他对象,这就是反射机制 分手后的思念是犯贱/ 2023年07月02日 12:29/ 0 赞/ 19 阅读
相关 四、反射机制 1. 定义 反向探知,在程序运行过程中动态获取类的相关属性。 对于给定的一个类,可以获取类的所有属性和方法。 2. 使用 public cla 阳光穿透心脏的1/2处/ 2022年11月05日 08:48/ 0 赞/ 242 阅读
相关 反射机制 反射就是加载+解剖 加载类的三种方式 Class person = Class.forName("cn.test.Person"); Class 布满荆棘的人生/ 2022年08月20日 09:16/ 0 赞/ 365 阅读
相关 反射(四) Java 208 道面试题 · 反射 57. 什么是反射? 反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力 Java反射: 在Java运行时环境 秒速五厘米/ 2022年02月21日 06:50/ 0 赞/ 282 阅读
相关 反射机制 概述 定义 JAVA机制反射的英文在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动 比眉伴天荒/ 2021年12月16日 05:18/ 0 赞/ 439 阅读
相关 反射机制 反射是程序可以访问,检测和修改它本身状态或者行为的一种能力。 反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。 然后,可以调用类型的方法或访问其字段和 超、凢脫俗/ 2021年12月04日 07:01/ 0 赞/ 457 阅读
相关 四、反射 四、反射 1. 什么是反射? ![在这里插入图片描述][20190820173254946.png] 1\_1. 对反射机制的理解及其用途? 反射有三种获取 逃离我推掉我的手/ 2021年10月16日 00:48/ 0 赞/ 334 阅读
相关 反射机制 【一】反射机制 Java反射机制是在运行的状态,对于任意一个类(.class文件),都能够知道这个类的所有属性和方法。对于任意一个对象都能够调用它的任意一个方法和属性。这种动 ゝ一世哀愁。/ 2021年10月01日 05:28/ 0 赞/ 474 阅读
相关 反射机制 反射机制是java语言中一个非常重要的特性,它允许程序在运行时进行自我检查,同时也运行对其内部的成员进行操作。 由于反射机制能够实现在运行时对类进行装载,因此能够增 - 日理万妓/ 2021年09月15日 11:56/ 0 赞/ 565 阅读
还没有评论,来说两句吧...