安卓面经_Android面经(15/20)反射机制解析

牛客高级系列专栏:

安卓(安卓系统开发也要掌握)

嵌入式

  • 本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业安卓开发经验,该专栏整理本人从嵌入式Linux转Android系统开发过程中对常见安卓系统开发面试题的理解;
  • 1份外卖价格助您提高安卓面试准备效率,为您面试保驾护航!!

正文开始⬇

面试题预览

  1. 什么是Java反射机制? ⭐⭐⭐
  2. 如何获取Java类的信息?⭐⭐⭐
  3. 如何获取Java字段的信息?⭐⭐⭐
  4. 如何获取Java方法的信息?⭐⭐⭐
  5. 如何创建Java对象通过反射?⭐⭐⭐
  6. 如何调用Java方法通过反射?⭐⭐⭐
  7. 如何获取Java注解的信息?⭐⭐⭐
  8. 如何操作Java数组通过反射?⭐⭐⭐
  9. 如何使用Java反射机制来创建泛型对象?⭐⭐
  10. 如何在运行时修改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 对应的一些方法 alt

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 参考

  1. Android反射机制
  2. android中反射机制

面试题解析

回答是作者根据自己知识来回答的,没有标准答案,仅供参考:

  1. 什么是Java反射机制? ⭐⭐⭐

回答:Java反射机制是指在运行时获取对象的信息并操作对象的一种能力。它允许程序在运行时操作类、对象、方法、属性和注解等信息,而不需要在编译时确定这些信息。Java中的反射机制主要由以下类与接口提供:Class、Constructor、Method、Field、Annotation、Parameter等。

  1. 如何获取Java类的信息?⭐⭐⭐

回答:使用反射机制可以获取Java类的信息,可以使用Java中的Class类来获取类的信息,例如:

Class clazz = MyClass.class; // 获取MyClass类的Class对象
String name = clazz.getName(); // 获取类的名称
Package pack = clazz.getPackage(); // 获取类所在的包
Class superClass = clazz.getSuperclass(); // 获取父类的Class对象
...
  1. 如何获取Java字段的信息?⭐⭐⭐

回答:可以使用Java中的Field类来获取字段的信息,例如:

Class clazz = MyClass.class;
Field field = clazz.getDeclaredField("myField"); // 获取名为myField的字段
String fieldName = field.getName(); // 获取字段的名称
Class fieldType = field.getType(); // 获取字段的类型
...
  1. 如何获取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(); // 获取方法的参数类型列表
...
  1. 如何创建Java对象通过反射?⭐⭐⭐

回答:可以使用Java中的Constructor类来创建对象,例如:

Class clazz = MyClass.class;
Constructor constructor = clazz.getConstructor(argTypes); // 获取参数类型为argTypes的构造方法
Object obj = constructor.newInstance(args); // 创建对象
  1. 如何调用Java方法通过反射?⭐⭐⭐

回答:可以使用Java中的Method类来调用方法,例如

Class clazz = MyClass.class;
Method method = clazz.getDeclaredMethod("myMethod", argTypes); // 获取名为myMethod的方法
Object obj = clazz.newInstance(); // 创建对象
Object result = method.invoke(obj, args); // 调用方法
  1. 如何获取Java注解的信息?⭐⭐⭐

回答:可以使用Java中的Annotation类来获取注解的信息,例如:

Class clazz = MyClass.class;
Annotation[] annotations = clazz.getAnnotations(); // 获取类上所有的注解
Annotation annotation = clazz.getAnnotation(MyAnnotation.class); // 获取名为MyAnnotation的注解
  1. 如何操作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
  1. 如何使用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
    }
}
  1. 如何在运行时修改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); // 允许调用私有方法

alt

#如果再来一次,你还会学硬件吗##硬件人绝对不能踩的坑##一人推荐一个值得去的通信/硬件公司##许乔丹安卓面经##安卓系统面经#
全部评论

相关推荐

牛客许愿真的很灵,稍微整理了一下来还愿了,希望能够帮到还在找实习的牛友-&nbsp;4.28&nbsp;一面总共80分钟,用钉钉视频面试的,没赶上笔试所以直接先手撕,大概笔试第二题的难度-&nbsp;为什么会想到做操作系统内核的项目-&nbsp;为什么会想到做安卓开发-&nbsp;目前有没有开始去了解一些移动端的相关知识操作系统-&nbsp;用户态到内核态是怎么进行切换的→除了系统调用还有没有其他的手段触发切换-&nbsp;什么叫中断→什么是硬中断和软中断-&nbsp;在做操作系统实验或平时日常学习中有用到系统调用吗-&nbsp;lru算法是一种什么算法→描述一下如何去实现这个算法-&nbsp;虚拟内存起什么作用-&nbsp;假设32位上的系统,有多大的虚拟内存空间→如果虚拟内存不够,还在程序中申请内存会发生什么问题-&nbsp;进程的fork操作是起到什么作用→fork创建的父子进程之间有没有什么相似之处→为什么fork是一个耗时的操作-&nbsp;原子操作是什么意思→多核处理器是如何保证原子操作的-&nbsp;什么是页表→程序运行的过程中,寻找到物理地址总共需要几步-&nbsp;MMU是存放在哪里的C++-&nbsp;平时做项目比如操作系统实验的时候使用的是C语言,那么为什么选择C++-&nbsp;面向对象和面向过程的区别→把大象放到冰箱需要几个类其他-&nbsp;设计模式有了解过吗-&nbsp;数据库有了解过吗算法-&nbsp;什么是二叉查找树→作用是什么-&nbsp;有向无环图→和图相关的还有了解其他的吗-&nbsp;5.13&nbsp;二面总共80多分钟,主要拷打项目-&nbsp;对自己的职业规划是什么-&nbsp;目前有保研的打算吗-&nbsp;对于客户端的了解-&nbsp;介绍自己比较好的项目→项目拷打-&nbsp;如何进行学习的-&nbsp;哈希表的实现原理→主要是用到了哪些数据结构-&nbsp;面向对象的抽象类和接口的概念、作用、使用场景和区别-&nbsp;堆和栈的区别-&nbsp;有没有了解常见的设计模式-&nbsp;http和https的区别-&nbsp;get和post的区别-&nbsp;tcp和udp的区别-&nbsp;死锁是怎么产生的-&nbsp;最有成就感和最沮丧的事-&nbsp;实习的最大收获→代码量-&nbsp;在班里的成绩排名-&nbsp;手撕题&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;给定单调递增的数组,找出和为k的连续子数组,直接暴力两层for循环做的-&nbsp;5.14&nbsp;三面二十多分钟,无技术问题,主要是问问个人性格,平时喜欢做什么,之后的职业发展之类的-&nbsp;5.17&nbsp;hr面-&nbsp;5.21&nbsp;收到意向
查看36道真题和解析
点赞 评论 收藏
转发
1 6 评论
分享
正在热议
# 牛客帮帮团来啦!有问必答 #
1148828次浏览 17132人参与
# 通信和硬件还有转码的必要吗 #
11126次浏览 101人参与
# 不去互联网可以去金融科技 #
19871次浏览 253人参与
# 和牛牛一起刷题打卡 #
18651次浏览 1632人参与
# 实习与准备秋招该如何平衡 #
203110次浏览 3622人参与
# 大厂无回复,继续等待还是奔赴小厂 #
4859次浏览 30人参与
# OPPO开奖 #
19039次浏览 265人参与
# 通信硬件薪资爆料 #
265632次浏览 2483人参与
# 国企是理工四大天坑的最好选择吗 #
2190次浏览 34人参与
# 互联网公司评价 #
97553次浏览 1279人参与
# 简历无回复,你会继续海投还是优化再投? #
25008次浏览 354人参与
# 0offer是寒冬太冷还是我太菜 #
454578次浏览 5122人参与
# 国企和大厂硬件兄弟怎么选? #
53836次浏览 1010人参与
# 参加过提前批的机械人,你们还参加秋招么 #
14624次浏览 349人参与
# 硬件人的简历怎么写 #
82272次浏览 852人参与
# 面试被问第一学历差时该怎么回答 #
19371次浏览 213人参与
# 你见过最离谱的招聘要求是什么? #
27720次浏览 247人参与
# 学历对求职的影响 #
161115次浏览 1804人参与
# 你收到了团子的OC了吗 #
538411次浏览 6385人参与
# 你已经投递多少份简历了 #
343915次浏览 4961人参与
# 实习生应该准时下班吗 #
96900次浏览 722人参与
# 听劝,我这个简历该怎么改? #
63487次浏览 622人参与
牛客网
牛客企业服务