安卓面经_Android面经(15/20)反射机制解析
牛客高级系列专栏:
安卓(安卓系统开发也要掌握)
- 想通关安卓面试,请看:《150道安卓高频面试题目录及答案链接》
- 想通关安卓系统面试,请看:《140道安卓系统Framework面试题目录及答案链接》
- 想进阶安卓开发,请看:《Android进阶知识体系解析_15大安卓进阶必备知识点》
- 想了解安卓APP完整开发流程,请看:《安卓APP完整开发流程》
- 想掌握安卓App性能优化,请看:《安卓性能优化讲解和实战专栏》
- 想掌握Gradle语法,制作Gradle插件,请看:《安卓Gradle语法解析和实践大全》
嵌入式
- 想通关嵌入式面试,请看: 《111道嵌入式面试题目录及答案链接》
- 想多掌握几个嵌入式项目,请看:《6个嵌入式项目交流分享(附源码)》
- 本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业安卓开发经验,该专栏整理本人从嵌入式Linux转Android系统开发过程中对常见安卓系统开发面试题的理解;
- 1份外卖价格助您提高安卓面试准备效率,为您面试保驾护航!!
正文开始⬇
面试题预览
- 什么是Java反射机制? ⭐⭐⭐
- 如何获取Java类的信息?⭐⭐⭐
- 如何获取Java字段的信息?⭐⭐⭐
- 如何获取Java方法的信息?⭐⭐⭐
- 如何创建Java对象通过反射?⭐⭐⭐
- 如何调用Java方法通过反射?⭐⭐⭐
- 如何获取Java注解的信息?⭐⭐⭐
- 如何操作Java数组通过反射?⭐⭐⭐
- 如何使用Java反射机制来创建泛型对象?⭐⭐
- 如何在运行时修改Java类的属性和方法?⭐⭐
1. 什么是反射机制?
反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。在计算机科学领域,反射是一类应用,它们能够自描述和自控制。这类应用通过某种机制来实现对自己行为的描述和检测,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制(注意关键词:运行状态)换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
因此,我们可以利用反射机制在Java程序中,动态的去调用一些protected甚至是private的方法或类,这样可以很大程度上满足我们的一些比较特殊需求。
反射机制主要提供的功能:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法
2. java Reflection API简介
- Class类:代表一个类,位于java.lang包下
- Field类:代表类的成员变量(成员变量也称为类的属性)
- Method类:代表类的方法
- Constructor类:代表类的构造方法
- Array类:提供了动态创建数组,以及访问数组的元素的静态方法
3. java中的Class介绍
Class 类十分特殊,它没有共有的构造方法,被jvm调用的(简单的理解:new对象或者被类加载器加载的时候),在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。
在运行期间,如果我们要产生某个类的对象,Java虚拟机(JVM)会检查该类型的Class对象是否已被加载。如果没有被加载,JVM会根据类的名称找到.class文件并加载它。一旦某个类型的Class对象已被加载到内存,就可以用它来产生该类型的所有对象。
class 对应的一些方法
4. 反射中常用的方法
4.1 获取Class方法
//方式一,需要导入class对应的Package
Person person = new Person();
Class<? extends Person> personClazz01 = person.getClass();
//方式二,需要导入class对应的Package
//运用.class的方式来获取Class实例,对于基本数据类型的封装类,
//还可以采用.TYPE来获取相对应的
Class<? extends Person> personClazz03 = Person.class;
//方式二,不需要导入class对应的Package
try {
Class<?> personClazz02 = Class.forName("Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//方式四
ClassLoader classLoader = context.getClassLoader();
@SuppressWarnings("rawtypes")
Class SystemProperties = classLoader.loadClass("android.os.SystemProperties");
4.2 设置和获取私有成员变量
存在四种获取成员属性的方法:
- Field getField(String name) 根据变量名,返回一个具体的具有public属性的成员变量
- Field[] getFields() 返回具有public属性的成员变量的数组
- Field getDeclaredField(String name) 根据变量名,返回一个成员变量(不分public和非public属性)
- Field[] getDelcaredField() 返回所有成员变量组成的数组(不分public和非public属性)
try {
Field field = person.getClass().getDeclaredField(fieldName);
// 参数值为true,打开禁用访问控制检查
//setAccessible(true) 并不是将方法的访问权限改成了public,而是取消java的权限控制检查。
//所以即使是public方法,其accessible 属相默认也是false
field.setAccessible(true);
field.set(person, "cyy");
return field.get(person);
} catch (Exception e) {
e.printStackTrace();
}
4.3 通过newInstance获取Class对象实例
Class<?> class1 = null;
class1 = Class.forName("com.android.reflect.Person");
//由于这里不能带参数,所以你要实例化的这个类Person,一定要有无参构造函数
Person person = (Person) class1.newInstance();
4.4 通过constructors 获取Class对象实例
class1 = Class.forName("com.android.reflect.Person");
//得到一系列构造函数集合
Constructor<?>[] constructors = class1.getConstructors();
try {
//默认构造函数
person1 = (Person) constructors[0].newInstance();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//带参数的构造函数
person2 = (Person) constructors[1].newInstance(29, "zhuk");
4.5 通过Field操作Class对象成员变量(包括私有变量)
Class<?> class1 = null;
class1 = Class.forName("com.android.reflect.Person");
Object obj = class1.newInstance();
Field nameField = class1.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj, "cyy");
4.6 通过Method操作Class对象方法
与获取构造方法的方式相同,存在四种获取成员方法的方式。
- Method getMethod(String name, Class[] params) 根据方法名和参数,返回一个具体的具有public属性的方法
- Method[] getMethods() 返回所有具有public属性的方法数组
- Method getDeclaredMethod(String name, Class[] params) 根据方法名和参数,返回一个具体的方法(不分public和非public属性)
- Method[] getDeclaredMethods() 返回该类中的所有的方法数组(不分public和非public属性)
Object instance = class1.newInstance();
//调用无参数方法fly
Method method = class1.getMethod("fly");
method.invoke(instance );
//调用带int参数smoke
method = class1.getMethod("smoke", int.class);
method.invoke(instance , 100);
在获取类的成员方法时,有一个地方值得大家注意,就是getMethods()方法和getDeclaredMethods()方法。
- getMethods():用于获取类的所有的public修饰域的成员方法,包括从父类继承的public方法和实现接口的public方法;
- getDeclaredMethods():用于获取在当前类中定义的所有的成员方法和实现的接口方法,不包括从父类继承的方法。
大家可以查考一下开发文档的解释:
getMethods() - Returns an array containing Method objects for all public methods for the class C represented by this Class. Methods may be declared in C, the interfaces it implements or in the superclasses of C. The elements in the returned array are in no particular order.
getDeclaredMethods() - Returns a Method object which represents the method matching the specified name and parameter types that is declared by the class represented by this Class.
5 参考
面试题解析
回答是作者根据自己知识来回答的,没有标准答案,仅供参考:
- 什么是Java反射机制? ⭐⭐⭐
回答:Java反射机制是指在运行时获取对象的信息并操作对象的一种能力。它允许程序在运行时操作类、对象、方法、属性和注解等信息,而不需要在编译时确定这些信息。Java中的反射机制主要由以下类与接口提供:Class、Constructor、Method、Field、Annotation、Parameter等。
- 如何获取Java类的信息?⭐⭐⭐
回答:使用反射机制可以获取Java类的信息,可以使用Java中的Class类来获取类的信息,例如:
Class clazz = MyClass.class; // 获取MyClass类的Class对象
String name = clazz.getName(); // 获取类的名称
Package pack = clazz.getPackage(); // 获取类所在的包
Class superClass = clazz.getSuperclass(); // 获取父类的Class对象
...
- 如何获取Java字段的信息?⭐⭐⭐
回答:可以使用Java中的Field类来获取字段的信息,例如:
Class clazz = MyClass.class;
Field field = clazz.getDeclaredField("myField"); // 获取名为myField的字段
String fieldName = field.getName(); // 获取字段的名称
Class fieldType = field.getType(); // 获取字段的类型
...
- 如何获取Java方法的信息?⭐⭐⭐
回答:可以使用Java中的Method类来获取方法的信息,例如:
Class clazz = MyClass.class;
Method method = clazz.getDeclaredMethod("myMethod", argTypes); // 获取名为myMethod的方法
String methodName = method.getName(); // 获取方法的名称
Class returnType = method.getReturnType(); // 获取方法的返回类型
Class[] parameterTypes = method.getParameterTypes(); // 获取方法的参数类型列表
...
- 如何创建Java对象通过反射?⭐⭐⭐
回答:可以使用Java中的Constructor类来创建对象,例如:
Class clazz = MyClass.class;
Constructor constructor = clazz.getConstructor(argTypes); // 获取参数类型为argTypes的构造方法
Object obj = constructor.newInstance(args); // 创建对象
- 如何调用Java方法通过反射?⭐⭐⭐
回答:可以使用Java中的Method类来调用方法,例如
Class clazz = MyClass.class;
Method method = clazz.getDeclaredMethod("myMethod", argTypes); // 获取名为myMethod的方法
Object obj = clazz.newInstance(); // 创建对象
Object result = method.invoke(obj, args); // 调用方法
- 如何获取Java注解的信息?⭐⭐⭐
回答:可以使用Java中的Annotation类来获取注解的信息,例如:
Class clazz = MyClass.class;
Annotation[] annotations = clazz.getAnnotations(); // 获取类上所有的注解
Annotation annotation = clazz.getAnnotation(MyAnnotation.class); // 获取名为MyAnnotation的注解
- 如何操作Java数组通过反射?⭐⭐⭐
回答:可以使用Java中的Array类来操作数组,例如:
int[] arr = new int[] {1, 2, 3};
Class clazz = arr.getClass();
int len = Array.getLength(arr); // 获取数组长度
int val = (int) Array.get(arr, 0); // 获取数组第一个元素的值
Array.set(arr, 1, 4); // 设置数组第二个元素的值为4
- 如何使用Java反射机制来创建泛型对象?⭐⭐
回答:可以使用Java中的ParameterizedType和Type类来创建泛型对象,例如:
import java.lang.reflect.*;
public class MyClass<T> {
public T value;
public MyClass(T value) {
this.value = value;
}
public static void main(String[] args) throws Exception {
Type[] typeArgs = {String.class};
ParameterizedType parameterizedType = TypeUtils.parameterize(MyClass.class, typeArgs);
Constructor constructor = parameterizedType.getRawType().getDeclaredConstructor(typeArgs);
MyClass obj = (MyClass)constructor.newInstance("Hello World");
System.out.println(obj.value); // 输出Hello World
}
}
- 如何在运行时修改Java类的属性和方法?⭐⭐
回答:可以使用Java中的Field和Method类来修改类的属性和方法,例如:
Class clazz = MyClass.class;
Field field = clazz.getDeclaredField("myField"); // 获取名为myField的字段
field.setAccessible(true); // 允许修改私有字段
Object obj = clazz.newInstance(); // 创建对象
field.set(obj, "new value"); // 修改字段的值
Method method = clazz.getDeclaredMethod("myMethod", argTypes); // 获取名为myMethod的方法
method.setAccessible(true); // 允许调用私有方法
#如果再来一次,你还会学硬件吗##硬件人绝对不能踩的坑##一人推荐一个值得去的通信/硬件公司##许乔丹安卓面经##安卓系统面经#