Java基础-反射
反射是什么?
反射就是在运行状态中,对于任意的一个类,我们都能够知道这个类的所有属性和方法。对于任意一个对象都能调用他们任意的方法,并且能够改变它的属性。注意反射一定是在运行时。
反射的意义,如何使用。
一般情况下我们使用某个类就必须对这个类进行实例化,但是在某些情况下你无法实例化对象的时候,但是你又想对这个类进行相关操作。我们就需要使用JDK提供的反射的API来进行调用。Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:
Field :可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
Method :可以使用 invoke() 方法调用与 Method 对象关联的方法;
Constructor :可以用 Constructor 的 newInstance() 创建新的对象。
JDK提供的反射API主要有以下实现帮助我们实现各种需求:
①在运行时,提供构造方法,能够使你实例化对象。
②在运行时,提供调用对象方法的方法。能够让你操作对象的方法。
③在运行时,提供获取和修改对象属性的方法。能够让你操作对象的属性。
缺陷:会产生大量的临时对象,导致频繁GC。
具体使用
使用反射首先需要知道我们操作的对象是什么,所以我们需要得到一个class对象。
获得class对象后,可以通过class对象获取class对象的方法和对象属性。进行你想要的操作,如获取方法和值,运行方法或者改变值等。
获得class对象后,拿到class对象后,可以通过class对象的构造方法,获得对象实例。
class对象的3种获取方法。
①通过全类名获取。Class c1=Class.forName("com.package.classname")
②通过对象获取 Class c2= test.getClass(); Test test;
③通过类型获取 Class c3=Test.class;
拓展:isInstance(Object) 判断是否为某个对象实例。 isAssignableFrom(Object)判断是否为某个类的类型。
①在运行时,提供构造方法,能够使你实例化对象。
主要通过newInstance()来实现对象的实例化。
无参的构造函数,获取实例化对象。
(1)当Class对象拥有一个无参的构造函数时。我们可以直接通过Class 对象的newInstance来实现对象的实例化。
Test test=(Test)c3.newInstance();
获取指定参数的构造函数,获取实例化对象。
(2)当我们需要初始化一个有参的对象时。我们可以获取该Class对象指定的构造函数,我们需要获取共有的构造函数。
Constructor constructor=c3.getConstructor(String.class);//获取形参为String 类型的构造函数 的构造器
Test t3=(Test)constructor.newInstance("1123");//通过Constructor 对象的newInstance 方法实例化对象
t3.showLog();//测试实例化对象的使用 调用方法。
Array类
(3)数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference 其中的Array类为
java.lang.reflect.Array类。我们通过Array.newInstance()创建数组对象。
Object array= Array.newInstance(int.class,10);//创建一个长度为10的int数组
Array.set(array,5,1);//设置指定位置值
Log.e("value",String.valueOf(Array.get(array,5)));//获取指定位置值
构造函数获取,方法介绍:
公有构造方法
Constructor getConstructor(Class[] params) -- 获得指定带参共公共(自己和父类的public)构造函数
Constructor[] getConstructors() -- 获得类的所有公共(自己和父类的public)构造函数
私有构造方法
Constructor getDeclaredConstructor(Class[] params) --获得指定带参构造函数 (包含自己私有的,不包含父类)
Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数 (包含自己私有的,不包含父类)
拓展:
public native boolean isInstance(Object obj);//判断是否为某个类的实例
public boolean isAssignableFrom(Class cls);//判断是否为某个类的类型
②在运行时,提供调用对象方法的方法。能够让你操作对象的方法。
(1)Method method=c3.getMethod("showLog");//公有 无参
method.invoke(t3);
(2)Method method=c3.getMethod("showLog",String.class);//公有 带参
method.invoke(t3,"执行showLog");
(3)Method method=c3.getDeclaredMethod("showLog",String.class);//私有 带参
method.setAccessible(true);//允许操作访问私有域
method.invoke(t3,"执行showLog");
对象内方法获取,方法介绍:
公有方法获取
Method getMethod(String name, Class[] params) -- 使用特定的参数类型,获得命名的公共(自己和父类的public)构造函数方法
Method[] getMethods() -- 获得类的所有公共(自己和父类的public)构造函数方法
私有方法获取
Method getDeclaredMethod(String name, Class[] params) -- 使用特写的参数类型,获得类声明的命名的方法(包含自己私有的,不包含父类)
Method[] getDeclaredMethods() -- 获得类声明的所有方法(包含自己私有的,不包含父类)
③在运行时,提供获取和修改对象属性的方法。能够让你操作对象的属性。
公有对象属性
(1) Field field=c3.getField("pbName");//获取指定名字 共有Class对象属性
Log.e("filedPb", field.getName());//获取对象属性 名称
Log.e("filedPb", (String) field.get(t3));//获取对象该指定属性值
私有对象属性
(2)Field field1=c3.getDeclaredField("prName");//获取指定名字 私有对象属性
Log.e("filedPr", field.getName());
Log.e("filedPr", (String) field.get(t3));//打印改变前属性值
field1.setAccessible(true);//设置作用域 可操作性私有
field1.set(t3,"33333");//更改对象变量属性
Log.e("filedPr", (String) field1.get(t3)); //打印改变后属性值
对象属性获取,方法介绍:
公有对象属性
Field getField(String name) -- 获得命名的公共自己和父类的public)字段
Field[] getFields() -- 获得类的所有公共自己和父类的public)字段
私有对象属性
Field getDeclaredField(String name) -- 获得类声明的命名的字段(包含自己私有的,不包含父类)
Field[] getDeclaredFields() -- 获得类声明的所有字段(包含自己私有的,不包含父类)
反射和泛型结合使用场景。获取泛型类的类型。(以后补充)
Type直接子接口(Gson泛型解析会使用)
TypeVariable 泛型类型变量。可以泛型上下限等信息;
ParameterizedType 具体的泛型类型,可以获得元数据中泛型签名类型(泛型真实类型)
ParameterizedType genType = (ParameterizedType) getClass().getGenericSuperclass();
GenericArrayType 当需要描述的类型是泛型类的数组时,比如List[],Map[],此接口会作为Type的实现。
WildcardType 通配符泛型,获得上下限信息;