java反射机制解析 港控/mmm° 2023-07-25 11:15 4阅读 0赞 **1.什么是反射** \* JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; \* 对于任意一个对象,都能够调用它的任意一个方法和属性; \* 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明 的,想要获取任何东西都可以。 \*网上查阅得到理解 如何理解反射?简单的一句话解释,将传统的开发思路反向逆转。 传统的方式是通过类创建对象:类 ---> 对象。 反射就是将这个过程逆转,通过对象得到类:对象 ---> 类。 通过对象得到的这个类该如何表示? 使用Class类来表示,此类是Java反射的源头,是用来描述其他类的类,Class类的每一个实例化对象就是对其他类的描述。 在Object类中定义了以下的方法,此方法将被所有子类继承: public final Class getClass()。 也就是说每一个类,都可以调用getClass()方法获取对应的Class对象,用来描述目标类,我们将这个Class类叫做目标类的运行时类。 \* 要想解剖一个类,必须先要获取到该类的字节码文件对象。 \* 而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象 \*获取字节码对象的三种方式: ➢ a:Object类的getClass()方法,判断两个对象是否是同一个字节码文件 ➢ b:静态属性class,锁对象 ➢c:Class类中静态方法forName(),读取配置文件 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xicWx6Y2g_size_16_color_FFFFFF_t_70][] **2.反射演示** (1) package com.hbsi.reflect; import com.hbsi.demo.Person; public class Demo1 { public static void main(String[] args) throws ClassNotFoundException { Class clazz1 = Class.forName("com.hbsi.demo.Person");//读取配置文件 Class clazz2 = Person.class;//当做静态方法的锁对象 Class clazz3 = new Person().getClass();//判断是否是同一个字节码对象 System.out.println(clazz1==clazz2); System.out.println(clazz2==clazz3); } } (2)通过反射获取构造方法并使用 <table style="width:499px;"> <tbody> <tr> <td>Class类的newInstance()方法</td> <td style="width:253px;">使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数, 就不能这样创建了</td> </tr> <tr> <td>Class类的getConstructor(String.class,int.class)方法</td> <td style="width:253px;"> <p style="margin-left:0cm;">可以调用Class类的getConstructor(String.class,int.class)方法获取一个指定的构造函数,然后再调用Constructor类的newInstance("张三",20)方法创建对象</p> </td> </tr> </tbody> </table> package com.hbsi.demo; //无參构造方法 alt shift s c 有參alt shift s o equal方法 alt shift s h public class Person { private String name; private int age; //其他省略不写 public void eat(){ System.out.println("今天吃了一顿金钱豹"); } public void eat(int num){ System.out.println("今天吃了"+num +"顿金钱豹"); } } package com.hbsi.reflect; //通过反射获取构造方法并使用 import java.lang.reflect.Constructor; import com.hbsi.demo.Person; /* * Class类的newInstance()方法是使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数, 就不能这样创建了,可以调用Class类的getConstructor(String.class,int.class) 方法获取一个指定的构造函数然后再调用Constructor类的newInstance("张三",20)方法创建对象*/ public class Demo4 { public static void main(String[] args) throws Exception { Class clazz = Class.forName("com.hbsi.demo.Person"); // Class类的newInstance()方法是使用该类无参的构造函数创建对象, // Person p = (Person) clazz.newInstance(); // System.out.println(p); Constructor c = clazz.getConstructor(String.class, int.class);//获取有参构造 Person p = (Person) c.newInstance("张三", 23);//通过有参构造创建对象 System.out.println(p); } } (3)通过反射获取成员变量并使用 <table style="width:500px;"> <tbody> <tr> <td>Class.getField(String)方法</td> <td>可以获取类中的指定字段(可见的)</td> </tr> <tr> <td>Class.getDeclaedField(String)方法</td> <td>可以获取类中的指定字段(私有的)</td> </tr> </tbody> </table> 通过set(obj, "李四")方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值 mport java.lang.reflect.Constructor; import java.lang.reflect.Field; import com.hbsi.demo.Person; //Field //* Class.getField(String)方法可以获取类中的指定字段(可见的), //如果是私有的可以用getDeclaedField("name")方法获取,通过set(obj, "李四") //方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限, //用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值 //通过反射获取成员变量并使用 public class Demo5 { public static void main(String[] args) throws Exception { Class clazz = Class.forName("com.hbsi.demo.Person"); Constructor c = clazz.getConstructor(String.class,int.class); Person p = (Person) c.newInstance("张三",11); //Field f = clazz.getField("name");//获取姓名字段 共有的 Field f = clazz.getDeclaredField("name");//暴力反射获取私有字段 f.setAccessible(true);//去除私有权限 f.set(p,"李四"); f.get(p); System.out.println(p); } } (4)通过反射获取方法并使用 <table style="width:500px;"> <tbody> <tr> <td> <p style="margin-left:0cm;">getMethod<code>(String name, 类<?>... parameterTypes)</code></p> </td> <td> <p style="margin-left:0cm;">返回一个 <code>方法</code>对象,它反映此表示的类或接口的指定公共成员方法 <code>类</code>对象</p> </td> </tr> <tr> <td> <p style="margin-left:0cm;">getDeclaredMethod<code>(String name, 类<?>... parameterTypes)</code></p> </td> <td> <p style="margin-left:0cm;">返回一个 <code>方法</code>对象,它反映此表示的类或接口的指定声明的方法 <code>类</code>对象</p> </td> </tr> </tbody> </table> package com.hbsi.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import com.hbsi.demo.Person; //通过反射获取方法 //Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...) //方法可以获取类中的指定方法,调用invoke(Object, Object...)可以调用该方法,Class.getMethod("eat") //invoke(obj) Class.getMethod("eat",int.class) invoke(obj,10) public class Demo6 { public static void main(String[] args) throws Exception { Class clazz = Class.forName("com.hbsi.demo.Person"); Constructor c = clazz.getConstructor(String.class,int.class); Person p = (Person) c.newInstance("张三",11); Method m =clazz.getMethod("eat");//获取eat方法、 m.invoke(p);//执行eat方法 Method m1 =clazz.getMethod("eat",int.class);//获取eat方法 m1.invoke(p,10);//执行eat方法 } } (5)通过反射越过泛型检查 \* ArrayList<Integer>的一个对象,在这个集合中添加一个字符串数据,如何实现呢? package com.hbsi.reflect; import java.lang.reflect.Method; import java.util.ArrayList; //* ArrayList<Integer>的一个对象,在这个集合中添加一个字符串数据,如何实现呢? //泛型只在编译期间有效,运行期会被擦出掉,字节码文件是运行期 所有不会报错 public class Demo7 { public static void main(String[] args) throws Exception { ArrayList<Integer> list = new ArrayList<>(); list.add(111); Class clazz = Class.forName("java.util.ArrayList");//获取字节码对象 Method m = clazz.getMethod("add", Object.class);//获取list的add方法 m.invoke(list, "abc"); System.out.println(list); } } (6)反射(动态代理的概述和实现) \* A:动态代理概述 \* 代理:本来应该自己做的事情,请了别人来做,被请的人就是代理对象。 \* 举例:春节回家买票让人代买 \* 真实对象:被代理的对象 \*代理对象: 代理对象代理真实对象,达到增强真实对象功能的目的。 用户调用代理对象,代理对象调用真实对象。 \* 动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理 \* 在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象 \* public static Object newProxyInstance(ClassLoader loader,Class<?>\[\] interfaces,InvocationHandler h) \* 最终会调用InvocationHandler的方法 \* InvocationHandler Object invoke(Object proxy,Method method,Object\[\] args) 我们来举一个卖电脑的例子 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xicWx6Y2g_size_16_color_FFFFFF_t_70 1][] ➢接口SaleComputer package com.hbsi.proxy; public interface SaleComputer { public String sale(double money); public void show(); } ➢实现类 package com.hbsi.proxy; public class Lenovo implements SaleComputer{ @Override public String sale(double money) { // TODO Auto-generated method stub System.out.println("花了"+money+"元买了一台电脑"); return "联想电脑"; } @Override public void show() { // TODO Auto-generated method stub System.out.println("展示电脑......."); } } ➢动态代理测试类(对sale()方法进行增强) package com.hbsi.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //代理对象代理真实对象,达到增强真实对象功能的目的。 /** * * @author lbq 静态代理:有一个类文件描述成代理模式 动态代理:在内存中形成代理类,并不能看到这个代理类文件 */ public class ProxyTest { public static void main(String[] args) { // 1.代理对象和真实对象实现相同的接口 // 2.通过Proxy.newProxyInstance() 获取代理对象 // 3.使用代理对象调用方法 // 4.增强方法 //真实对象 目标类 Lenovo lenovo = new Lenovo(); // 代理类 将目标类(切入点) 和切面类(通知)结合 ------>切面 //lenovo.getClass().getInterfaces()代理对象实现的接口们 和真实对象一样 SaleComputer proxy_lenovo =(SaleComputer)Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() { //代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行 // proxy:代理对象 // method:代理对象调用的方法,被封装为对象 // args:代理对象调用的方法时,传递的实际参数 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub if(method.getName().equals("sale")){ //1.增强参数 double money = (double)args[0]; money = money*0.85; System.out.println("专车接送你");//2,增强方法体 //使用真实对象调用该方法 String obj = (String) method.invoke(lenovo, money); System.out.println("免费送货");//增强方法体 //3.增强返回值 return obj+"_鼠标垫"; }else{ Object obj = method.invoke(lenovo, args); return obj; } } }); //代理对象调用方法 String computer = proxy_lenovo.sale(8000); System.out.println(computer); proxy_lenovo.show(); } } 结果展示:专车接送你 花了6800.0元买了一台电脑 免费送货 联想电脑\_鼠标垫 展示电脑....... [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xicWx6Y2g_size_16_color_FFFFFF_t_70]: /images/20230528/64b6c38ebddf441384a055420c0842f7.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xicWx6Y2g_size_16_color_FFFFFF_t_70 1]: /images/20230528/6bb036cccf1d48e8b3f7e5893283ca04.png
相关 Java反射机制实例解析 Java的反射机制是一种强大的工具,它允许我们在运行时检查类、方法和字段等对象的信息。以下是一些实例解析: 1. **获取类信息**: ```java Class<?> cl 墨蓝/ 2024年10月08日 20:18/ 0 赞/ 67 阅读
相关 Java反射机制常见问题解析 Java的反射机制在开发中经常被使用,但有时也会遇到一些问题。以下是常见的几个问题及解析: 1. **问题:找不到类或者方法** **解析:**使用了错误的类名或方法名 一时失言乱红尘/ 2024年09月22日 16:21/ 0 赞/ 74 阅读
相关 Java反射机制常见问题解析 Java反射机制是Java语言强大的工具,它允许我们在运行时获取类的信息、对象的属性和方法等。然而,在使用反射时也可能会遇到一些常见问题,以下是对这些问题的解析: 1. ** 太过爱你忘了你带给我的痛/ 2024年09月20日 13:15/ 0 赞/ 70 阅读
相关 Java反射机制实例解析 Java反射机制是Java语言提供的一种能力,允许程序在运行时检查类的信息(如方法、属性等)并动态调用这些信息。 下面是一个简单的实例解析: ```java // 创建一个 我就是我/ 2024年09月16日 21:51/ 0 赞/ 94 阅读
相关 Java反射机制深入解析 Java的反射机制是一种强大的工具,它允许我们在运行时检查类、方法和字段的信息。以下是反射机制深入解析的关键点: 1. 类加载:当Java应用需要访问一个类时,Java虚拟机 亦凉/ 2024年09月15日 05:03/ 0 赞/ 71 阅读
相关 Java反射机制深入解析 Java的反射机制是一种强大的工具,它允许程序在运行时检查和修改类、对象及方法的信息。下面对Java反射机制进行深入解析: 1. **Class**:这是反射的主要对象类型, 忘是亡心i/ 2024年09月11日 19:57/ 0 赞/ 103 阅读
相关 java反射机制解析 1.什么是反射 \ JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; \ 对于任意一个对象,都能够调用它的任意一个方法和属性; \ 港控/mmm°/ 2023年07月25日 11:15/ 0 赞/ 5 阅读
相关 Java反射机制解析 首先在反射之前我们要先了解java类的整个加载机制:我们的.java源码文件通过编译之后会生成一个JVM可识别的二进制字节码.class文件,每一个类都会产生一个Class对象 - 日理万妓/ 2022年04月23日 12:36/ 0 赞/ 299 阅读
相关 java反射机制详细解析 (一)什么是反射机制? 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动 喜欢ヅ旅行/ 2021年09月15日 02:32/ 0 赞/ 386 阅读
还没有评论,来说两句吧...