【Android面试题】2023最新面试专题:Java反射类加载与动态代理(二)

4 ClassNotFound的有可能的原因是什么?(阿里)

这道题想考察什么?

类加载流程

考察的知识点

  1. 反射机制
  2. 反射在框架中的应用
  3. 获取Class类的主要方式

考生应该如何回答

ClassNotFoundException表示虚拟机加载指定的类时,如果没有找到对应的Class文件时,抛出的异常。以Android为例,出现此异常的原因可能有:

1、APK中dex未包含需要加载的类数据,导致类加载器无法加载;

2、Android Dalvik下,使用dex分包,在Secondary DEX 加载之前,需要使用不在主dex中的类

3、类数据不合法验证失败导致加载失败。此时能够在Log中看到:

Failure to verify dex file '/data/app/xxxxx/base.apk'

5 odex了解吗?解释型和编译型有什么区别?

这道题想考察什么?

是否了解Android 类处理过程,有编程语言的基础认识

考察的知识点

  1. APK安装过程
  2. 编程语言的分类

考生应该如何回答

odex

odex全称:OptimizedDEX,表示经过优化的dex文件。

Android APK就是一个Zip压缩包 ,Android 虚拟机每次需要从Zip压缩中读取classes.dex文件完成类加载。而odex就是把 .dex 文件从Zip压缩包中的提取,这样运行时无需再次从 APK 提取 。

解释型语言和编译型语言

在开发中,无论我们使用Java、C++还是其他语言,实际上我们写的代码都是给人看的。然后我们的运行设备并没有人这么聪明,只能够看懂一些特定的简单的指令。因此在程序真正运行之前需要先将源代码转换成这种运行设备能够识别的二进制指令,也就是机器码。

但是不同的语言对什么时候、怎么转换成机器码又有不同的处理,我们按照对不同处理方式可以把语言分类为:解释型语言和编译型语言

  • 编译型语言:利用编译器将源码一次性全部转换成二进制指令,生成可执行程序,如C/C++等。
  • 解释型语言:边执行,边使用解释器转换,如JavaScript、PHP等

在这里插入图片描述

不管是编译器还是解释器实际上都是把人能看懂的代码,翻译成CPU能够识别的指令(机器码)。但是编译型语言需要在开发完成以后将所有的源代码都转换成可执行程序 ,而可执行程序里面包含的就是机器码 。不同操作系统对可执行文件的内部结构有不同的要求,彼此之间无法兼容,因此编译型语言一般是不能跨平台的,需要在不同平台运行,需要根据不同的平台生成对应平台的可执行文件。

相比于编译型语言,解释型语言几乎都能跨平台。解释型语言之所以能够跨平台,是因为有了解释器这个中间层。在不同的平台下,解释器会将相同的源代码转换成不同的机器码。

6 说说反射的应用场景,哪些框架?

这道题想考察什么?

是否了解反射相关的理论知识

考察的知识点

  1. 反射机制
  2. 反射在框架中的应用
  3. 获取Class类的主要方式

考生应该如何回答

反射是Java程序开发语言的特征之一,它允许动态地发现和绑定类、方法、字段,以及所有其他的由于有所产生的的元素。通过反射,能够在需要时完成创建实例、调用方法和访问字段的工作。

反射机制主要提供功能有:

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的方法,通过反射甚至可以调用到private修饰的方法
  • 生成动态代理

反射在框架中用的非常多。我们可以利用反射机制在Java程序中,动态的去调用一些protected甚至是private的方法或类,这样可以很大程度上满足我们的一些比较特殊需求。例如Activity的启动过程中Activity的对象的创建。

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    
    

        //省略
        Activity activity = null;
        try {
    
    
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
    
    
                r.state.setClassLoader(cl);
            }
        } 
    
    //上面代码可知Activity在创建对象的时候调用了mInstrumentation.newActivity();
    
    public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
    
    
            //这里的className就是在manifest中注册的Activity name.
        return (Activity)cl.loadClass(className).newInstance();
    }
    //Activity对象的创建是通过反射完成的。java程序可以动态加载类定义,而这个动态加载的机制就是通过ClassLoader来实现的.

Java的每个.class文件里承载了类的所有信息内容,包含父类、接口、属性、构造、方法等;这些class文件会在程序运行状态下通过ClassLoad类机制加载到虚拟机内存中并产生一个对象实例,然后这个对象就可以对这块内存地址进行引用;一般我们通过New一个对象创建就行,而利用反射我们通过JVM查找并指定加载的类名,就可以创建对象实例,而在java中,类的对象被实例化可以在内存中被引用时,就可以获取该类的所有信息。可以说反射是所有插件化框架的基础。

//反射获取类的实例化对象
Class<?> cls=Class.forName("com.fanshe.Person"); //forName(包名.类名)
Person p=(Person)cls.newInstance();
//或
Person p = new Person();
Class<?> cls=p.getClass();
Person p2=(Person)cls.newInstance();
//或
Class<?> cls=Person.Class();
Person p=(Person)cls.newInstance();

//反射获取类的属性的值
Field getField = cls.getDeclaredField(fieldName);//传入属性名
Object getValue =getField.get(newclass);//传入实例值
//静态属性不用借助实例 
Field getField = cls.getDeclaredField(fieldName);
Object getValue =getField.get(null);

反射在插件化、热修复、Retrofit等等几乎所有的常见框架中均有使用。

最后

此面试题会持续更新,请大家多多关注!!!!
有需要此面试题的朋友可以扫描下方二维码免费领取!!!
同时扫描下方二维码还可以进群享受ChatGPT机器人的服务哦!!!

猜你喜欢

转载自blog.csdn.net/datian1234/article/details/132070028
今日推荐