反射的概述(Java Reflection)
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像以面镜子,透过镜子看到类的结构,所以我们形象的称之为:反射。
正常方式:引入需要的“包类”名称->通过new实例化->取得实例化对象
反射方式:实例化对象->getClass()方法->得到完整的“包类”名称
动态语言vs静态语言
1.动态语言
是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。
主要动态语言:Object-c、C#、JavaScript、PHP、Python、Erlang
2.静态语言
与动态语言相对应,运行时结构不可变的语言就是静态语言如java、c、c++
Java不是动态语言,但Java可以称之为“准动态语言”,即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。Java的动态性让编程的适合更加灵活!
反射机制的研究及应用
Java反射机制提供的功能:
在运行时判断任意一个对象所属的类
在运行是构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时获取泛型的信息
在运行时调用任意一个对象的成员变量和方法
在运行时处理注解
生成动态代理
反射相关的主要API
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造器
| |
| @Test |
| public void test2() throws Exception{ |
| Class clazz = Person.class; |
| |
| Constructor cons = clazz.getConstructor(String.class,int.class); |
| Object obj = cons.newInstance("Tom",12); |
| Person p = (Pserson)obj; |
| System.out.println(obj.toString()); |
| |
| |
| Field age = clazz.getDeclaredField("age"); |
| age.set(p,10); |
| System.out.println(p.toString()); |
| |
| Method show = clazz.getDeclaredMethod("show"); |
| show.invoke(p); |
| |
| |
| Constructor cons1 = clazz.getDeclaredConstructor(String.class); |
| cons1.setAccessiable(true); |
| Person p1 = (Person)cons1.newInstance("Jerry"); |
| System.out.println(p1); |
| |
| Field name = clazz.getDeclaredField("name"); |
| name.setAccessiable(true); |
| name.set(p1,"Hanmeimei"); |
| |
| Method showNation = clazz.getDeclaredMethod("showNation",String.class); |
| showNation.setAccessible(true); |
| String nation = (String)showNation.invoke(p1,"中国"); |
| System.out.println(nation); |
| } |
反射机制与面向对象中的封装性是否是矛盾的,如何看待两个技术。
不矛盾。反射的特性:动态性。反射表现为是否去掉,封装性表现为是否可掉
关于Java.lang.Class的理解:
1.类加载过程:
程序经过javac.exe命令以后,会生成一个活多个字节码文件(.class)结尾,接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载内存中的类,就称为运行时类,此运行时类,就作为Class的一个实例
2.换句话说,Class的实例就对应着一个运行时类。
3.加载到内存中的运行时类,会缓存一定的时间,在此时间之内,我们可以通过不同的方式来获取此运行时类。
| |
| |
| Class<Person> clazz1 = Person.class; |
| System.out.println(clazz1); |
| |
| Person p1 = new Person(); |
| Class clazz2 = p1.getClass(); |
| |
| Class clazz3 = Class.forName("com.java.Person"); |
| System.out.println(clazz3); |
| System.out.println(clazz1==clazz2); |
| System.out.println(clazz1==clazz3); |
| |
| |
| ClassLoader classloader = 当前类.class.getClassLoader(); |
| Class clazz4 = classLoader.loadClass("com.java.Person"); |
| System.out.println(clazz4); |
| System.out.println(clazz1==clazz4); |
| |
类加载器的作用:
类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在队中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。
| Properties pros = new Properties(); |
| |
| |
| |
| |
| ClassLoader classLoader= 当前类.class.getClassLoder(); |
| InputStream is = classLoader.getResourceAsStream("jdbc.properties"); |
| String user = pros.getProperty("user"); |
| System.out.println("user="+user); |
创建运行时类的对象
| @Test |
| public void test1(){ |
| Class clazz = Person.classs; |
| |
| |
| |
| |
| |
| |
| |
| |
| Pserson obj = (Pserson)clazz.newInstance(); |
| System.out.print(obj); |
| } |
| @Test |
| public void test2(){ |
| int num = new Random().nextInt(3); |
| switch(num){ |
| case 0: |
| classPath="java.util.Date"; |
| break; |
| case 1: |
| classPath="java.lang.Object" |
| break; |
| class 2: |
| classPath="com.java.Person"; |
| break; |
| } |
| Object obj = getInstance(classPath); |
| } |
| |
| |
| public Object getInstance(String classPath)throws Exception(){ |
| Class clazz = Class.froName(classPath); |
| return clazz.newInstance(); |
| } |
获取当前运行时类的属性结构
| @Test |
| public void test1(){ |
| Class clazz = Person.class(); |
| |
| |
| Field[] fields = clazz.getFields(); |
| for(Filed f : fields){ |
| System.out.println(f); |
| } |
| |
| Field[] declaredFields = clazz.getDeclaredFields(); |
| for(Field f :declaredFields){ |
| System.out.println(f); |
| } |
| } |
| |
| |
| |
| @Test void test2(){ |
| Class clazz = Person.class; |
| Field[] declaredFields=clazz.getDeclaredFields(); |
| for(Field f : declaredFields){ |
| |
| int modifier = f.getModifiers(); |
| |
| System.out.print(Modifier.toString(modifier)+"\t"); |
| |
| |
| Class type = f.getType(); |
| System.out.print(type.getName()+"\t"); |
| |
| |
| String fName=f.getName(); |
| System.out.print(fName); |
| } |
| } |
获取运行时类的方法结构
| Class clazz = Person.class(); |
| |
| Method[] methods = clazz.getMethods(); |
| for(Method m : methods){ |
| System.out.println(m); |
| } |
| |
| Method[] declaredMethods = clazz.getDeclaredMethods(); |
| for(Method m : declaredMethods){ |
| System.out.println(m); |
| } |
| |
| |
| |
| Class clazz = Person.class; |
| Method[] declaredMethods = clazz.getDeclaredMethods(); |
| for(Method m : declaredMethods){ |
| |
| Annotation[] annos = m.getAnnotations(); |
| for(Annotation a: annos){ |
| System.out.println(a); |
| } |
| |
| System.out.print(Modifier.toString(m.getModifiers())+"\t"); |
| |
| System.out.print(m.getReturnType().getName()+"\t"); |
| |
| System.out.print(m.getName()); |
| System.out.print("("); |
| |
| Class[] parameterTypes = m.getParamterTypes(); |
| if(!(parameterTypes==null && parameterTypes.length==0)){ |
| for(int i=0;i<paramterTypes.length;i++){ |
| if(i==parameterTypes.length-1){ |
| System.out.print(parameterTypes[i].getName()+" args_"+i); |
| break; |
| }else{ |
| System.out.print(parameterTypes[i].getName()+" args_"+i+","); |
| } |
| |
| } |
| } |
| System.out.print(")"); |
| |
| Class[] exceptionTypes = m.getExceptionTypes(); |
| if(exceptionTypes.length>0){ |
| System.out.print("throws "); |
| for(int i=0;i<exceptionTypes.lengvth;i++){ |
| if(i==exceptionTypes.length-1){ |
| System.out.println(exceptionTypes[i].getName()); |
| break(); |
| }else{ |
| System.out.println(exceptionTypes[i].getName()+","); |
| } |
| |
| } |
| } |
| System.out.println(); |
| } |
获取其他
| |
| @Test |
| public void test1(){ |
| Class clazz = Person.class(); |
| |
| Constructor[] constructors = clazz.getConstuctors(); |
| for(Constructor c : constructors){ |
| System.out.println(c); |
| } |
| System.out.println(); |
| |
| Constructor[] declaredConstructors = clazz.getDeclaredConstructors(); |
| for(Constructor c: declaredConstructors){ |
| System.out.println(c); |
| } |
| |
| |
| Class superclass= clazz.getSuperclass(); |
| System.out.println(superclass); |
| |
| |
| Type genericSuperclass = clazz.getGenericSuperclass(); |
| ParameterizedType paramType = (ParameterizedType)genericSuperclass; |
| |
| Type[] actulaTypeArguments = paramType.getActualTypeArguments(); |
| System.out.println(genericSuperclass[0].getTypeName()); |
| |
| |
| Class[] interfaces = clazz.getInterfaces(); |
| for(Class c : interfaces){ |
| System.out.println(c); |
| } |
| System.out.println(); |
| |
| Class[] interfaces1 = clazz.getSuperclass().getInterfaces(); |
| for(Class c: interfaces){ |
| System.out.println(c); |
| } |
| |
| Package pack = clazz.getPackage(); |
| System.out.println(pack); |
| |
| Annotation[] annotations = clazz.getAnnotations(); |
| for(Annotation annos:annotations){ |
| System.out.println(annos); |
| } |
| } |
调用运行时类的指定结构:属性、方法、构造器
| @Test |
| public void testField()throws Exception{ |
| Class clazz = Person.class; |
| |
| |
| |
| Person p = (Person) clazz.newInstance(); |
| |
| |
| |
| Field id = clazz.getField("id"); |
| |
| |
| |
| id.set(p,1001); |
| |
| |
| int pId=(int)id.get(p); |
| } |
| @Test |
| public void testField1() throws Exception{ |
| Class clazz = Person.class; |
| |
| Person p = (Person)clazz.newInstance(); |
| |
| |
| Filed name = clazz.getDeclaredField("name"); |
| |
| name.setAccessiable(true); |
| name.set(p,"Tom"); |
| System.out.println(name.get(p)); |
| } |
| @Test |
| public void testMethod() throws Exception{ |
| |
| Class clazz = Person.class; |
| |
| Person p = (Person)clazz.newInstance(); |
| |
| Method show = clazz.getDeclaredMethod("show",String.class); |
| show.setAccessiable(true); |
| |
| Object returnValue =show.invoke(p,"CHN"); |
| System.out.println(returnValue); |
| |
| |
| |
| Method showDesc = clazz.getDeclaredMethod("showDesc"); |
| showDesc.setAccessible(true); |
| |
| Object returnVal = showDesc.invoke(Person.class); |
| |
| System.out.println(retrurn Val); |
| } |
| |
| @Test |
| public void testConstructor()throws Exception{ |
| Class clazz = Person.class; |
| |
| |
| Constructor constructor = clazz.getDeclaredConstructor(String.class); |
| |
| constructor.setAccessible(true); |
| |
| Person per = (Person)constructor.newInstance("Tom"); |
| System.out.println(per); |
| |
| } |
反射的应用:动态代理:
代理设计模式的原理:
使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以何时将方法调用转到原始对象上。
动态代理指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象
动态代理使用场合:调试/远程方法调用
动态代理相比于静态代理的优点:抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和同意的处理众多的方法。
| |
| |
| interface ClothFactory{ |
| void produceCloth(); |
| } |
| |
| |
| class ProxyClothFactory implements ClotyFactory{ |
| private ClothFactory factory; |
| |
| public ProxyClothFactory(ClothFactory factory){ |
| this.factory = factory; |
| } |
| @Override |
| public void produceCloth(){ |
| System.out.println("代理工厂做一些准备工作"); |
| factory.produceCloth(); |
| System.out.println("代理工厂做一些后续的受委工作"); |
| } |
| } |
| |
| class NikeClothFactory impletements CLothFactory{ |
| |
| @Override |
| public void produceCloth(){ |
| System.out.println("Nike工厂生产一批运动发u") |
| } |
| } |
| |
| public class StaticProxyTest{ |
| public static void main(String[] args){ |
| |
| NikeClothFactory nike = new NikeClothFactory(); |
| |
| ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nike); |
| proxyClothFactory.produceCloth(); |
| } |
| } |
| |
| |
| |
| |
| interface Human{ |
| String getBelief(); |
| void eat(String food); |
| } |
| |
| class HumanUtil{ |
| public void method1(){ |
| System.out.println("=====通用方法1====="); |
| } |
| public void method2(){ |
| System.out.println("======通用方法二====="); |
| } |
| } |
| |
| |
| class SuperMan implements Human{ |
| @Override |
| public String getBelief(){ |
| return "I believe I can fly!"; |
| } |
| |
| @Override |
| public void eat(String food){ |
| System.out.println("我喜欢吃"+food); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| class ProxyFactory{ |
| |
| |
| public static Object getProxyInstance(Object obj){ |
| MyInvocationHandler hander = new MyInvocationHandler(); |
| handler.bind(obj); |
| return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),hander); |
| } |
| } |
| |
| class MyInvocationHandler implements InvocationHandler{ |
| private Object obj; |
| public void bind(Object obj){ |
| this.obj = obj; |
| } |
| |
| |
| |
| |
| @Override |
| public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{ |
| HumanUtil util = new HumanUtil(); |
| |
| |
| util.method2(); |
| Object returnValue = method.invoke(obj,args); |
| return returnValue; |
| } |
| } |
| |
| |
| |
| public class ProxyTest{ |
| public static void main(String[] args){ |
| SuperMan superMan = new SuperMan(); |
| |
| Human proxyInstance = (Human)ProxyFactory.getProxyInstance(superMan); |
| |
| proxyInstance.getBelief(); |
| proxyInstance.eat("四川麻辣烫"); |
| |
| NikeClothFactory nikeClothFactory = new NikeClothFactory(); |
| ClothFactory proxyClothFactory = proxyFactory.getProxyInstance(nikeClothFactory); |
| proxyClothFactory.produceCloth(); |
| } |
| } |
| |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)