安卓面经_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;&nbsp;心态&nbsp;心态&nbsp;心态!秋招没有拿到好的offer,一定要保持好心态,面对春招可以调整自己的面试方向。一、梳理时间线在秋招失败后,就必须开始规划春招了,可以先简单梳理了一下时间线,这个很重要。春招一般从1月份陆续开始,2、3月份集中爆发。所以现在距离春招满打满算也就3个多月时间了,说长不长,说短不短,就看要如何去利用了。虽然春招的机会虽然没有秋招多,但是依然有很多大公司会有招聘通道。企业并不会区别对待春招和秋招拿到offer的同学,入职后都是一样接受一系列培训,成长晋升路径也都是一样。所以,春招的机会绝对值得好好把握。二、调节情绪相信经历过秋招失败同学,挫败感都非常强烈,极易陷入「自抱自泣」的状态,同时看到上面这个时间线的分析,认为时间还早,到了春招再说,就会暂时把求职这事搁在一边,能逃避一会是一会。但是明年春招,你将面对的对手是:考研、考公失失利的同学秋招没有Offer或没有拿下理想Offer的同学竞争是非常激烈的,摆在你面前需要做的事还有很多,时间不允许你陷入情绪之中。接下来这一个月的时间,你没有办法去改变你的学历和专业,但你可以去做接下来这些事情。三、复盘秋招失败总是有原因的,但是你不能笼统地把它概括为:我这不好,那不好。而是要将之细细剖析,找出可控的因素和影响最大的因素出来,并加以调整。比如说,你可以统计自己秋招的面试经历,将每次被淘汰的环节标注出来,看看哪个环节的问题最多。举个例子:①&nbsp;如果是网申的通过率低,那你就要加强网申的技巧;②&nbsp;如果是在笔试中被淘汰,那是不是自己的专业知识还不够扎实,或者行测做得不够多?那就应该多刷题,恶补一下自己的专业知识。除了自己埋头苦***也要善于利用身边的资源。比如,向已经拿到&nbsp;offer&nbsp;的同学取经。在这个时间节点,你们已经不是竞争对手了,他们一般都会乐意分享自己的成功经验。又或者你羞于向同学请教,你可以多参加一些秋招讲座,向一些有经验的前辈分享四、修改简历你的简历应该是多份的,针对不同公司的不同岗位,针对性地准备简历。特别是实践经验部分,它是一份简历最有价值的内容,需要你细细斟酌和深入挖掘,同时要结合你的目标岗位来写,这样匹配度才更高。千万记住不要再海投简历,通过秋招,你应该已经开始清楚自己的职业发展方向,所以有针对性的准备简历,就是要稳准狠。对于简历撰写还是很头疼的同学建议借助工具来辅助,比起自己抓耳挠腮会高效很多。五、笔面环节,逐一击破笔试能力从现在开始累积。超过80%的高淘汰率,想要通过短期内的突击提高笔试能力是不十分现实的,所以现在行动一点都不早!提前刷题一定没错。分享不易,关注我分享更多面试知识,嵌入式c++的同学可以看一下大佬总结的面经&nbsp;&nbsp;c++/嵌入式面经专栏-牛客网 https://www.nowcoder.com/creation/manager/columnDetail/MJNwoM
点赞 评论 收藏
分享
昨天 16:32
门头沟学院 Java
点赞 评论 收藏
分享
2 20 评论
分享
牛客网
牛客企业服务