JAVA反射机制是在运行状况中,关于恣意一个类,都能够知道这个类的一切特点和办法;关于恣意一个目标,都能够调用它的恣意一个办法和特点;这种动态获取的信息以及动态调用目标的办法的功用称为java言语的反射机制。
要想解剖一个类,有必要先要获取到该类的字节码文件目标。而解剖运用的便是Class类中的办法.所以先要获取到每一个字节码文件对应的Class类型的目标.
以上的总结便是什么是反射
反射便是把java类中的各种成分映射成一个个的Java目标
例如:一个类有:成员变量、办法、结构办法、包等等信息,运用反射技能能够对一个类进行解剖,把个个组成部分映射成一个个目标。(其实:一个类中这些成员办法、结构办法、在加入类中都有一个类来描述)
如图是类的正常加载进程:反射的原理在与class目标。
了解一下加载的时分:Class目标的由来是将class文件读入内存,并为之创建一个Class目标。
二、Java中为什么需求反射?反射要解决什么问题?
Java中编译类型有两种:
静态编译:在编译时确认类型,绑定目标即经过。
动态编译:运行时确认类型,绑定目标。动态编译最大极限地发挥了Java的灵活性,表现了多态的应用,能够减低类之间的耦合性。
Java反射是Java被视为动态(或准动态)言语的一个关键性质。这个机制答应程序在运行时透过ReflectionAPIs取得任何一个已知称号的class的内部信息,包含其modifiers(诸如public、static等)、superclass(例如Object)、完成之interfaces(例如Cloneable),也包含fields和methods的一切信息,并可于运行时改动fields内容或唤起methods。
Reflection能够在运行时加载、探知、运用编译期间完全未知的classes。即Java程序能够加载一个运行时才得知称号的class,获取其完好结构,并生成其目标实体、或对其fields设值、或唤起其methods。
反射(reflection)答应静态言语在运行时(runtime)检查、修改程序的结构与行为。
在静态言语中,运用一个变量时,有必要知道它的类型。在Java中,变量的类型信息在编译时都保存到了class文件中,这样在运行时才干确保准确无误;换句话说,程序在运行时的行为都是固定的。假如想在运行时改动,就需求反射这东西了。
完成Java反射机制的类都坐落java.lang.reflect包中:
Class类:代表一个类
Field类:代表类的成员变量(类的特点)
Method类:代表类的办法
Constructor类:代表类的结构办法
Array类:提供了动态创建数组,以及拜访数组的元素的静态办法
一句话归纳便是运用反射能够赋予jvm动态编译的能力,否则类的元数据信息只能用静态编译的方法完成,例如热加载,Tomcat的classloader等等都无法支撑。目标办法
Java反射机制定义
Java反射机制是在运行状况中,关于恣意一个类,都能够知道这个类中的一切特点和办法;关于恣意一个目标,都能够调用它的恣意一个办法和特点;这种动态获取的信息以及动态调用目标的办法的功用称为java言语的反射机制。
Java反射机制的功用
1.在运行时判别恣意一个目标所属的类。
2.在运行时结构恣意一个类的目标。
3.在运行时判别恣意一个类所具有的成员变量和办法。
4.在运行时调用恣意一个目标的办法。
5.生成动态署理。
Java反射机制的运用场景
1.逆向代码,例如反编译
2.与注解相结合的结构例如Retrofit
3.单纯的反射机制运用结构例如EventBus
4.动态生成类结构例如Gson
二、经过Java反射查看类信息
取得Class目标
每个类被加载之后,体系就会为该类生成一个对应的Class目标。经过该Class目标就能够拜访到JVM中的这个类。
在Java程序中取得Class目标通常有如下三种办法:
1.运用Class类的forName(StringclazzName)静态办法。该办法需求传入字符串参数,该字符串参数的值是某个类的全限定名(必须增加完整包名)。
2.调用某个类的class特点来获取该类对应的Class目标。
3.调用某个目标的getClass()办法。该办法是java.lang.Object类中的一个办法。
//第一种办法经过Class类的静态办法——forName()来完成class1=Class.forName(“com.lvr.reflection.Person”);//第二种办法经过类的class特点class1=Person.class;//第三种办法经过目标getClass办法Personperson=newPerson();Class>class1=person.getClass();
获取class目标的特点、办法、结构函数等
1.获取class目标的成员变量
Field[]allFields=class1.getDeclaredFields();//获取class目标的一切特点Field[]publicFields=class1.getFields();//获取class目标的public特点FieldageField=class1.getDeclaredField(“age”);//获取class指定特点FielddesField=class1.getField(“des”);//获取class指定的public特点
2.获取class目标的办法
Method[]methods=class1.getDeclaredMethods();//获取class目标的一切声明办法Method[]allMethods=class1.getMethods();//获取class目标的一切public办法包括父类的办法Methodmethod=class1.getMethod(“info”,String.class);//返回次Class目标对应类的、带指定形参列表的public办法MethoddeclaredMethod=class1.getDeclaredMethod(“info”,String.class);//返回次Class目标对应类的、带指定形参列表的办法
3.获取class目标的结构函数
Constructor>[]allConstructors=class1.getDeclaredConstructors();//获取class目标的一切声明结构函数Constructor>[]publicConstructors=class1.getConstructors();//获取class目标public结构函数Constructor>constructor=class1.getDeclaredConstructor(String.class);//获取指定声明结构函数ConstructorpublicConstructor=class1.getConstructor(String.class);//获取指定声明的public结构函数
4.其他办法
Annotation[]annotations=(Annotation[])class1.getAnnotations();//获取class目标的一切注解Annotationannotation=(Annotation)class1.getAnnotation(Deprecated.class);//获取class目标指定注解TypegenericSuperclass=class1.getGenericSuperclass();//获取class目标的直接超类的TypeType[]interfaceTypes=class1.getGenericInterfaces();//获取class目标的一切接口的type调集
获取class目标的信息
比较多。
booleanisPrimitive=class1.isPrimitive();//判别是否是根底类型booleanisArray=class1.isArray();//判别是否是调集类booleanisAnnotation=class1.isAnnotation();//判别是否是注解类booleanisInterface=class1.isInterface();//判别是否是接口类booleanisEnum=class1.isEnum();//判别是否是枚举类booleanisAnonymousClass=class1.isAnonymousClass();//判别是否是匿名内部类booleanisAnnotationPresent=class1.isAnnotationPresent(Deprecated.class);//判别是否被某个注解类润饰StringclassName=class1.getName();//获取class姓名包含包名途径PackageaPackage=class1.getPackage();//获取class的包信息StringsimpleName=class1.getSimpleName();//获取class类名intmodifiers=class1.getModifiers();//获取class拜访权限Class>[]declaredClasses=class1.getDeclaredClasses();//内部类Class>declaringClass=class1.getDeclaringClass();//外部类
三、经过Java反射生成并操作目标
生成类的实例目标
1.运用Class目标的newInstance()办法来创立该Class目标对应类的实例。这种办法要求该Class目标的对应类有默许结构器,而执行newInstance()办法时实际上是利用默许结构器来创立该类的实例。
2.先运用Class目标获取指定的Constructor目标,再调用Constructor目标的newInstance()办法来创立该Class目标对应类的实例。经过这种办法能够选择运用指定的结构器来创立实例。
//第一种办法Class目标调用newInstance()办法生成Objectobj=class1.newInstance();//第二种办法目标取得对应的Constructor目标,再经过该Constructor目标的newInstance()办法生成Constructor>constructor=class1.getDeclaredConstructor(String.class);//获取指定声明结构函数obj=constructor.newInstance(“hello”);
调用类的办法
1.经过Class目标的getMethods()办法或者getMethod()办法取得指定办法,返回Method数组或目标。
2.调用Method目标中的Objectinvoke(Objectobj,Object…args)办法。第一个参数对应调用该办法的实例目标,第二个参数对应该办法的参数。
//生成新的目标:用newInstance()办法Objectobj=class1.newInstance();//首要需求取得与该办法对应的Method目标Methodmethod=class1.getDeclaredMethod(“setAge”,int.class);//调用指定的函数并传递参数method.invoke(obj,28);
当经过Method的invoke()办法来调用对应的办法时,Java会要求程序必须有调用该办法的权限。假如程序的确需求调用某个目标的private办法,则能够先调用Method目标的如下办法。
setAccessible(booleanflag):将Method目标的acessible设置为指定的布尔值。值为true,指示该Method在运用时应该取消Java言语的拜访权限查看;值为false,则知识该Method在运用时要施行Java言语的拜访权限查看。
拜访成员变量值
1.经过Class目标的getFields()办法或者getField()办法取得指定办法获取,返回Field数组或目标。
2.Field供给了两组办法来读取或设置成员变量的值:
getXXX(Objectobj):获取obj目标的该成员变量的值。此处的XXX对应8种基本类型。假如该成员变量的类型是引证类型,则取消get后面的XXX。
setXXX(Objectobj,XXXval):将obj目标的该成员变量设置成val值。
//生成新的目标:用newInstance()办法Objectobj=class1.newInstance();//获取age成员变量Fieldfield=class1.getField(“age”);//将obj目标的age的值设置为10field.setInt(obj,10);//获取obj目标的age的值field.getInt(obj);
还有很多其他操作,就不一一介绍了。