java反射
场景:
1 C++调java
2 注解
3 很多框架 如retrofit 体现在解析网络接口方法上注解中包含的数据,获取请求的数据。
优点:
增加程序的灵活性,避免将程序写死到代码里,可以在运行时获取一个类的所有方法和变量(包括私有)
缺点:
1 会模糊程序内部逻辑,不易于代码维护
2 性能较差
反射为什么性能较差(耗时)
invoke()的时候:
1 要校验 校验方法的可见性,校验参数的类型
2 要对invoke的参数进行装箱和拆箱
3 无法进行JIT优化(JIT在运行时将字节码生成机器码,会对代码进行优化提高性能)
反射性能优化
1 其实频率低 1s调用几百上千次以内都基本无差别
2 做好类和方法的缓存
3
原理
反射机制: JVM会持有加载的类的对象,反射就是可以运行时(动态地)获取类对象或者创建对象并且进行方法的调用。
1 获取Class对象 Class<?>就是一个对象
先去方法区查找,若类没被加载过,则通过jvm先进行ClassLoader类加载
2 获取属性和方法
通过Class对象直接获取其方法和属性
3 方法的调用
通过MethodAccessor对象(所有同名method共享的一个实例)的invoke方法
调用次数小于等于15次,通过native方式来调用 (还是系统提供的函数)
高于15次,通过java方式来调用
破坏封装性和安全性吗?
封装性,是将具体的实现细节隐藏,而把功能作为整体提供给类的外部使用,也就是说,公有方法能够完成类所具有的功能。当别人使用这个类时,如果通过反射直接调用私有方法,可能根本实现不了类的功能,甚至可能会出错,因此通过反射调用私有方法可以说是没有任何用处的,开发人员没有必要故意去破坏封装好的类。从这点上看,封装性并没有被破坏。
安全性,如果意思是保护实现源码不被别人看见,那没有作用。不用反射也能轻易获取源码。
Java反射可以访问和修改私有成员变量,那封装成private还有意义么?
既然小偷可以访问和搬走私有成员家具,那封装成防盗门还有意义么?这是一样的道理,并且Java从应用层给我们提供了安全管理机制——安全管理器,每个Java应用都可以拥有自己的安全管理器,它会在运行阶段检查需要保护的资源的访问权限及其它规定的操作权限,保护系统免受恶意操作攻击,以达到系统的安全策略。所以其实反射在使用时,内部有安全控制,如果安全设置禁止了这些,那么反射机制就无法访问私有成员
Java反射基本使用
1 获取class的对象
(1)Class<?> kclass = Class.forName("接口或者类名")
使用Class类的中静态forName()方法获得与字符串对应的Class对象
(2) Class<?> kclass = 类名.class
(3) Class<?> kclass = 对象.getClass()
可以用kclass.toString() 去输出查看 获取的class
2 判断是否为某个类的实例对象
类名.isInstance(对象名)
要反射得到的类 而不是随便的java类名
3 创建实例
(1)
Class<?> c = String.class;
Object str = c.newInstance();
要反射得到的类 而不是随便的java类名
(2)通过constructor方式
Class<?> c = String.class;
//带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
Object obj = constructor.newInstance("23333");
4 获取类的成员变量
(1)getDeclaredFields
获取所有成员变量。但不能得到其父类的成员变量
(2)getFileds
访问公有的成员变量
(3)getFiled
获取指定的public属性
(4) getDeclaredField
获取指定的属性可以为private等
返回值为 Field 或者 Field[]
获取属性具体的值:
// 静态属性则传null
String xx = field.get(object);
设置属性具体的值:
// 若是private的 加上:
field.setAccessible(true);
field.set(object, xxValue);
5 获取方法
(1)getDeclaredMethods
获取所有方法(除了继承的的父类的方法)
(2)getMethods
获取所有public方法和其继承的父类的公有方法
(3)getMethod(String name, Class<?>... parameterTypes)
获取指定的public的方法
第一个参数为方法名称,后面的参数为方法的参数对应Class的对象 如int.class
(4)getDeclaredMethod
获取指定的方法 可以private
method.toString()查看获取的具体方法名
静态方法则传null
6 调用方法
反射调用方法时可以忽略权限检查
// 可以传入自己通过new创建的对象 也可以传入通过反射创建的对象 若不用创建对象的,直接写null
// 若方法并没有参数 则不用写第二个参数 不是传null
(强转返回类型) 方法.invoke(object obj(获取的类对象),该方法的实参)
7 创建数组
利用 java.lang.reflect.Array类
// 第一个参数为class对象 第二个参数为数组长度
Array.newInstance(Class<?> componentType, int length)
kotlin反射基本使用
要导入包 挺大的 所以尽量还是在java类中用
1 获取kotlin的kclass类的引用:
val c = MyClass::class
2 获取java的类的引用:
val c = MyClass::class.java
Class.forName("xxx.xxx.xxx")
3 获取java类的属性
同java
4 获取kotlin类的属性
val hClass_2=Human::class
val allFields_2=hClass_2.declaredMemberProperties//获取KClass对象的所有属性
val publicFields_2=hClass_2.memberProperties//获取KClass对象的public属性
val extensionFields=hClass_2.declaredMemberExtensionProperties//获取KClass对象的扩展成员变量
val nameField_2=publicFields_2.stream().filter { it.name=="name" }.findAny().get().javaField//获取KClass对象的指定属性,
将KProperty属性类型转换后的类型是java中的Field类型
5 获取java的类的方法
同java
6 获取kotlin类的方法:
//获取KClass对象的所有声明方法,包括父类的方法
val methods_2 = hClass_2.memberFunctions
//获取KClass对象的所有声明方法
val allMethods_2 = hClass_2.declaredMemberFunctions
//返回KClass对象中指定方法名的方法,
将KFunction方法类型转换后的类型是java中的Method类型
val method_2 = methods_2.stream().filter { it.name == "say" }.findAny().get().javaMethod