一、JAVA反射思维和NDK开发
Java反射定义:java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意类的静态属性和方法,都能够完成对静态属性的获取和设置以及静态方法的调用:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
1.1 JAVA反射使用的相关类(部分)
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类的属性 ) |
Method类 | 代表类的方法 |
Constructo | 代表类的构造方法 |
1.1.1 获得class类
代表类的实体,在运行的Java应用程序中表示类和接口
获取类相关的方法(主要)
getClassLoader() : 获得类的加载器
getClasses() : 返回一个数组,包含该类中的所有公共类和接口类的对象
getDeclaredClasses(): 返回一个数组,包含该类中的所有类和接口类的对象
gerName(): 获得类的完整路径名字
getPackage(): 获得类的包名
1.1.2 获得类的属性
getField(String name) | 获取某个公有的属性对象 |
---|---|
getFields() | 获取所有公有属性对象 |
getDeclaredField(String name) | 获得某个属性对象 |
getDeclaredFields() | 获得所有属性对象 |
1.1.3 获取类中的方法
getMethod(String name, Class….<?> parameterTypes) | 获得该类某个公有的方法 |
---|---|
getMethods() | 获得该类所有公有的方法 |
getDeclaredMethod(String name, Class…<?> parameterTypes) | 获得该类某个方法 |
getDeclaredMethods() | 获得该类所有方法 |
1.1.4 获取类中的构造方法
getConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 |
---|---|
getConstructors() | 获得该类的所有公有构造方法 |
getDeclaredConstructor(Class…<?>parameterTypes) | 获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructors() | 获得该类所有构造方法 |
1.1.5 类中其他重要的方法
isAnnotation()isAnnotation() | 如果是注解类型则返回true |
---|---|
isAnnotationPresent(Class<? extends Annotation>annotationClass) | 如果是指定类型注解类型则返回true |
isAnonymousClass() | 如果是匿名类则返回true |
isArray() | 如果是一个数组类则返回true |
isEnum() | 如果是枚举类则返回true |
islnstance(Object obj) | 如果obj是该类的实例则返回true |
isInterface() | 如果是接口类则返回true |
isLocalClass() | 如果是局部类则返回true |
isMemberClass() | 如果是内部类则返回true |
1.1.6 Field类
equals(Object obj) 属性与obj相等则返回true get(Object obj)获得obi中对应的属性值 set(Object obj, Object value)设置obj中对应属性值
1.1.7 Method类
invoke : 传递Object对象及参数调用该对象对应的方法
1.1.8 访问private域和方法
类AccessibleObject中有函数public void setAccessible(boolean flag),该函数在传入true作为参数后,让访问private修饰的域和函数成为可能。而Method、Field和Constructor类共同继承了Accessibleobject类,该基类有两个setAccessible方法能在运行时压制Java语言访问控制检查(Javalanguage access control checks),从而能任意调用被私有化保护的方法域和构造方法
首先新建一个Moonlight类,代码如下
package com.example.reflection;
import android.util.Log;
public class MoonlightTest {
public String flag = null;
public MoonlightTest(){
flag = "MoonlightTest()";
}
public MoonlightTest(String content){
flag = "public MoonlightTest(String content)";
}
public MoonlightTest(String content,int arg){
flag = "public MoonlightTest(String content,int arg)";
}
public static StringpublicStaticField= "I am public StaticField";
public String publicNotStaticField = "I am public Not StaticField";
private static StringprivateStaticField= "I am private StaticField";
private String privateNotStaticField = "I am private Not StaticField";
public static void publicStaticFunction(){
Log.i("Moonlight","I am from publicStaticFunction");
}
public void publicNotStaticFunction(){
Log.i("Moonlight","I am from publicNotStaticFunction");
}
private static void privateStaticFunction(){
Log.i("Moonlight","I am from privateStaticFunction");
}
private void privateNotStaticFunction(){
Log.i("Moonlight","I am from privateNotStaticFunction");
}
}
里面包括了常用的构造方法,字段和方法
然后再JAVA层反射调用Moonlight类中的方法和属性
二、获取类加载器
2.1 第一种方式
使用getClassLoader来获取指定的类,getClassLoader() : 获得类的加载器
Class testJavaReClazz;
testJavaReClazz = MainActivity.class.getClassLoader().loadClass("com.example.reflection.MoonlightTest");
2.2 第二种方式
Class.forName返回一个给定类或者接口的一个 Class 对象,如果没有给定 classloader, 那么会使用根类加载器
Class testJavaReClazz2;
testJavaReClazz2 = Class.forName("com.example.reflection.MoonlightTest");
2.3 第三种方式
this指的是当前正在访问这段代码的对象,当在内部类中使用this指的就是内部类的对象, 为了访问外层类对象,就可以使用外层类名.this来访问,一般也只在这种情况下使用这种形式
Class testJavaReClazz3;
testJavaReClazz3 = MoonlightTest.class;
三、Java层反射调用Field属性
getDeclaredFields():获取某个类的自身的所有字段,不包括父类的字段。
Field publicStaticField_field = testJavaReClazz3.getDeclaredField("publicStaticField");
Field[] fields = testJavaReClazz3.getDeclaredFields();
for(Field i:fields){
Log.i("Moonlight","getDeclaredFields()-> "+i);
}
getFields(): 获取某个类的所有的public字段,其中是包括父类的public字段的。
Field[] fields_2 = testJavaReClazz3.getFields();
for(Field i:fields_2){
Log.i("Moonlight","getFields()-> "+i);
}
执行后,可以发现
getDeclaredFields :获得所有属性对象
getFields : 获取公有属性的对象
从上面就可以看出来,getDeclaredFields 可以获取所有属性对象,
当我们需要获取到某个指定的属性时,我们应该如何去获取呢?当然也比较简单,需要在getDeclaredFields 和 getFields 方法中指定需要使用的属性名称。
Field publicStaticField_field = testJavaReClazz3.getDeclaredField("publicStaticField");
Field privateStaticField_field = testJavaReClazz3.getDeclaredField("privateStaticField");
Log.i("Moonlight","publicStaticField_field-> "+ publicStaticField_field);
Log.i("Moonlight","privateStaticField_field-> "+ privateStaticField_field);
编译后运行,可以看见结果已经打印出来了
那么还存在一个问题,如果用getField去获得一个私有属性(上面说过它只能访问公有属性)。那么会怎么样呢,代码如下:
Field privateField_field = testJavaReClazz3.getField("privateStaticField");
Log.i("Moonlight","getField->privateStaticField_field-> "+ privateField_field);
结果就是程序异常崩溃!!
3.1 获取私有属性和公有属性的值
在上面已经获取到了属性Field,那么如果获取他们的值呢。
公有属性的值:
Field publicStaticField_field = testJavaReClazz3.getDeclaredField("publicStaticField");
String publicStaticField_content = (String)publicStaticField_field.get(null);
Log.i("Moonlight","publicStaticField_content-> "+ publicStaticField_content);
获取私有属性的值:
需要设置权限
Field privateStaticField_field = testJavaReClazz3.getDeclaredField("privateStaticField");
privateStaticField_field.setAccessible(true); //访问私有属性时,记得加上setAccessible,设置它的权限检查
String privateStaticField_content = (String)privateStaticField_field.get(null);
Log.i("Moonlight","privateStaticField_content-> "+ privateStaticField_content);
编译运行—>结果
可以看到值已经获取到了,
3.2 改变私有属性和公有属性的值
上面说到获取到一个私有属性和公有属性的值,那么如何去改变属性的值呢,那么就是set啦。
publicStaticField_field.set(null,"publicStaticField->modified");
privateStaticField_field.set(null,"privateStaticField->modified");
set方法,第一个参数为对象,第二个参数即为需要更改的值
注意,如果是非静态的属性,对象不能为null,
四、Java层反射调用Method方法
4.1 反射访问指定类中所有方法
在反射Java层方法时,需要引入几个方法
getDeclaredMethods
:获取该类的所有方法
getField : 获取该类的所有公有方法(其中包括在反射过程中所使用到的公有方法)
首先编写代码如下:
public void TestJavaMethod(){
Class MoonlightTestClazz = MoonlightTest.class;
Method[] getDeclaredMethods = MoonlightTestClazz.getDeclaredMethods();
for(Method i : getDeclaredMethods){
Log.i("Moonlight","getDeclaredMethods-> "+i);
}
Method[] getMethods = MoonlightTestClazz.getMethods();
for(Method i : getMethods){
Log.i("Moonlight","getMethods-> "+i);
}
}
编译—>查看日志
getDeclaredMethods()
获取了该类的所有方法,而getMethods
则只获取在反射过程中的所有公有方法,
那么我们就去找找 getMethods
是不是 只获取在反射过程中的所有公有方法?
找到 Object.class文件,新建一个Object 对象,点击就可以进入Object 。打开Object.class文件,可以发现getClass是一个公有的方法,那么,证明了getMethods
会打印反射过程中的所有公有方法
4.2 反射访问类中指定方法
代码如下所示:
Method publicStaticFunction_method = MoonlightTestClazz.getDeclaredMethod("publicStaticFunction");
publicStaticFunction_method.invoke(null); //获取公有静态的无参方法,直接写null即可
Method privateStaticFunction_method = MoonlightTestClazz.getDeclaredMethod("privateStaticFunction");
privateStaticFunction_method.setAccessible(true);//和访问静态属性一致,需要设置权限
privateStaticFunction_method.invoke(null);
其中,getDeclaredMethod方法,定义如下
public Method getDeclaredMethod(@RecentlyNonNull String name, @RecentlyNullable Class<?>... parameterTypes)
第一个参数为类名,之后的参数都为所调用参数的参数值
4.3 反射访问类中构造方法
Constructor[] constructors = MoonlightTestClazz.getDeclaredConstructors(); //获取所有的构造函数
Constructor MoonlightTestConstructors = MoonlightTestClazz.getDeclaredConstructor(String.class); //获取指定的构造函数
Log.i("Moonlight","MoonlightTestConstructors-> "+MoonlightTestConstructors);
for(Constructor i : constructors){
Log.i("Moonlight","getDeclaredConstructors-> "+i);
}
访问私有属性
Object MoonlightTestObj = MoonlightTestConstructors.newInstance("MoonLight"); //建立一个obj对象
Field privateNotStaticField_field = MoonlightTestClazz.getDeclaredField("privateNotStaticField");
privateNotStaticField_field.setAccessible(true); //设置权限
String privateNotStaticField_field_content = (String) privateNotStaticField_field.get(MoonlightTestObj);
Log.i("Moonlight","privateNotStaticField_field_content-> "+privateNotStaticField_field_content);
其中,newInstance()方法和new关键字除了一个是方法,一个是关键字外,最主要有什么区别?它们的区别在于创建对象的方式不一样,前者newInstance()是使用类加载机制(重点),后者new关键字是创建一个新类
但是使用newInstance时候,就必须保证:
1、这个类已经加载;
2、这个类已经连接了。
newInstance(): 弱类型。低效率。是实现IOC、反射、面对接口编程和依赖倒置等技术方法的必然选择!
new: 强类型。相对高效。能调用任何public构造。new只能实现具体类的实例化,不适合于接口编程