2023最新高频Android面试题总结(附答案)

一、抽象类与接口的区别?

1、抽象类可以提供成员方法的实现细节,而接口中只能存在 public 抽象方法;
2、抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的;
3、接口中不能含有构造器、静态代码块以及静态方法,而抽象类可以有构造器、静态代码块和静态方法;
4、一个类只能继承一个抽象类,而一个类却可以实现多个接口;
5、抽象类访问速度比接口速度要快,因为接口需要时间去寻找在类中具体实现的方法;
6、如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。
7、如果你往接口中添加方法,那么你必须改变实现该接口的类。
8、接口更多的为了约束类的行为,可用于解耦,而抽象类更加侧重于代码复用。

二、Java 中深拷贝与浅拷贝的区别?

1、浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,
此为浅拷贝。
2、深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。

三、谈谈Error和Exception的区别?

1、Exception是java程序运行中可预料的异常情况,咱们可以获取到这种异常,并且对这种异常进行业务外的处理。
2、Error是java程序运行中不可预料的异常情况,这种异常发生以后,会直接导致JVM不可处理或者不可恢复的情况。所以这
种异常不可能抓取到,比如OutOfMemoryError、NoClassDefFoundError等。

四、什么是反射机制?反射机制的应用场景有哪些?

Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。
应用场景:1. 逆向代码,例如反编译2. 与注解相结合的框架,如 Retrofit3. 单纯的反射机制应用框架,例如 EventBus(事件总线)4. 动态生成类框架 例如Gson

五、谈谈你对Java泛型中类型擦除的理解,并说说其局限性?

Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。局限性:如在代码中定义的List和List等类型,在编译后都会变成List。JVM看到的只是List,而由泛型附加的类型信息对JVM 来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转 换异常的情况。类型擦除也是Java的泛型实现方法与C++模版机制实现方式之间的重要区别。

六、说说你对Java注解的理解?

三种注解:source、class、runtime。分别在源码,编译时,运行时存活自定义的source注解,可以用来对一些方法或者参数进行约束,比如说指定线程,指定参数类型class注解是配合apt编写注解处理器, 对注解的类或者变量进行解析生成.class文件 辅助工作 比方说 arouter,在注解处理器中生成代码,帮你做路径和activity的路由表,butterknife的注解帮你做findviewbyid的工作,runtime注解 则是在runtime时还能存在的,通常配合反射机制,把注解标注的对象拿到进行操作,比方说 retrofit,通过反射机制拿到注解的,接口和接口中的方法,在通过动态代理生成接口的实现类。

七、谈一谈Java成员变量,局部变量和静态变量的创建和回收时机?

成员变量:生命周期伴随类对象,类对象回收时回收,存在堆里。
静态变量:不回收,在方法区随着类的加载而加载,随着类的消失而消失,由于类需要非常长时间的不使用,不利用,不关联,才有可能会被回收机制回收,所以静态成员变量的生命周期特别长,除非是共享数据,否则不建议使用静态;
局部变量:方法调用时创建 方法结束时被标记为可回收,存在栈里

八、请说说Java中String.length()的运作原理?

privatefinalcharvalue[];
public String(char value[]) {
this.value=Arrays.copyOf(value,value.length);
}
public int length()
{ return value.length;
}

九、扩展:内部类都有哪些?

有四种:静态内部类、非静态内部类、局部内部类、匿名内部类

十、多态概述

1.多态是继封装、继承之后,面向对象的第三大特性。

2.多态现实意义理解:
1)现实事物经常会体现出多种形态,如学生,学生是人的一种,则一个
具体的同学张三既是学生也是人,即出现两种形态。
2)Java作为面向对象的语言,同样可以描述一个事物的多种形态。如Student类继承了Person类,一个Student的对象便既是Student,又是Person。
3)多态体现为父类引用变量可以指向子类对象。
4)前提条件:必须有子父类关系。
5)定义格式:父类类型 变量名=new 子类类型();
6)理解:多态是同一个行为具有多个不同表现形式或形态的能力,多态就是同一个接口,使用不同的实例而执行不同操作。

十一、多态中成员的特点

1、多态成员变量:编译运行看左边

Fu f=new Zi();
System.out.println(f.num);//f是Fu中的值,只能取到父中的值

2、多态成员方法:编译看左边,运行看右边

System.out.println(f1.show());//f1的门面类型是Fu,但实际类型是Zi,
所以调用的是重写后的方法。

十二、instanceof关键字

作用:用来判断某个对象是否属于某种数据类型。

Fu f2=new Son();
if(f1 instanceof Zi){
System.out.println("f1是Zi的类型");
}
else{
System.out.println("f1是Son的类型");
}

十三、多态的转型

多态的转型分为向上转型和向下转型两种:
1、向上转型:多态本身就是向上转型过的过程
使用格式:父类类型 变量名=new 子类类型();
适用场景:当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作。

2、向下转型:一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用类型转为子类引用各类型
使用格式:子类类型 变量名=(子类类型) 父类类型的变量;
适用场景:当要使用子类特有功能时。

十四、 java中接口和继承的区别

实际概念区别:
区别1:不同的修饰符修饰(interface),(extends)

区别2:在面向对象编程中可以有多继承!但是只支持接口的多继承,不支持’继承’的多继承,而继承在java中具有单根性,子类只能继承一个父类

区别3:在接口中只能定义全局常量,和抽象方法,而在继承中可以定义属性方法,变量,常量等…

区别4:某个接口被类实现时,在类中一定要实现接口中的抽象方法而继承想调用那个方法就调用那个方法,毫无压力

十五、线程池的好处

1、线程池的重用:
线程的创建和销毁的开销是巨大的,而通过线程池的重用大大减少了这些不必要的开销,当然既然少了这么多消费内存的开销,其线程执行速度也是突飞猛进的提升。

2、控制线程池的并发数:
初学新手可能对并发这个词语比较陌生,特此我也是结合百度百科和必生所学得出最优解释,万万记着并发可跟并行不一样。

十六、List<String>能否转为List<Object>

Java的泛型是伪泛型,编译时会进行泛型擦除

因此List<Number>和 List<Integer> 最终的类型都被擦除了,无论是List<String> 还是 List<Object> 都是List类型。

既然存在泛型擦除,但是下面的代码无法通过编译检查:

List<String> strs = new ArrayList<Integer>();
List<Object> objects = strs;

编译器会帮我我们检查明显的代码问题,因此上述代码会报错,这是编译器的行为,但是如果我们将代码改为:

List<String> strs = (List)new ArrayList<Integer>();
List<Object> objects = (List)strs;

注意,每条语句我们增加了强转声明。此时编译器能够成功完成编译。因此List<String>其实能够强转为List<Object>。但是存在隐患:

List<String> strs = (List)new ArrayList<Integer>();
List<Object> objects = (List)strs;
objects.add(123);
String str =  strs.get(0);

上述代码使用objects(List<Object> )向集合中增加整型数据:123。然后通过 strs获取数据时,因为其类型为List<String>,但是真实数据类型为整型。此时就会发生运行时异常:

Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String

十七、注解是什么?有哪些使用场景?

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 注解是元数据的一种形式,提供有关于程序但不属于程序本身的数据。注解本身没有特殊意义,对它们注解的代码的操作没有直接影响。

按照**@Retention** 元注解定义的注解保留级,注解可以一般常见于以下场景使用:

SOURCE

RetentionPolicy.SOURCE ,作用于源码级别的注解,在类中使用SOURCE级别的注解,其编译之后的class中会被丢弃。可提供给Lint 检查、APT等场景使用。

Lint

在Android开发中,support-annotationsandroidx.annotation中均有提供@IntDef注解,此注解的定义如下:

@Retention(SOURCE)  //源码级别注解
@Target({ANNOTATION_TYPE})
public @interface IntDef {
    int[] value() default {};
   
    boolean flag() default false;

    boolean open() default false;
}

Java中Enum(枚举)的实质是特殊单例的静态成员变量,在运行期所有枚举类作为单例,全部加载到内存中。比常量多5到10倍的内存占用。

此注解的意义在于能够取代枚举,实现如方法入参限制。

如:我们定义方法test,此方法接收参数teacher需要在:LanceAlvin中选择一个。如果使用枚举能够实现为:

public enum Teacher{
    LANCE,ALVIN
}

public void test(Teacher teacher) {

}

而现在为了进行内存优化,我们现在不再使用枚举,则方法定义为:

public static final int LANCE = 1;
public static final int ALVIN = 2;

public void test(int teacher) {

}

然而此时,调用test方法由于采用基本数据类型int,将无法进行类型限定。此时使用@IntDef增加自定义注解:

public static final int LANCE = 1;
public static final int ALVIN = 2;

@IntDef(value = {LANCE, ALVIN}) //限定为LANCE,ALVIN
@Target(ElementType.PARAMETER)  //作用于参数的注解
@Retention(RetentionPolicy.SOURCE) //源码级别注解
public @interface Teacher {
}

public void test(@Teacher int teacher) {

}

此时,我们再去调用test方法,如果传递的参数不是LANCE或者ALVIN则会显示 Inspection 警告(编译不会报错)。

在这里插入图片描述

APT注解处理器

SOURCE另一种更常见的应用场景是结合APT使用。APT全称为:“Anotation Processor Tools”,意为注解处理器。顾名思义,其用于处理注解。编写好的Java源文件,需要经过javac的编译,翻译为虚拟机能够加载解析的字节码Class文件。注解处理器是 javac 自带的一个工具,用来在编译时期扫描处理注解信息。你可以为某些注解注册自己的注解处理器。 注册的注解处理器由javac调起,并将注解信息传递给注解处理器进行处理。

注解处理器是对注解应用最为广泛的场景。在Glide、EventBus3、Butterknifer、Tinker、ARouter等等常用框架中都有注解处理器的身影。但是你可能会发现,这些框架中对注解的定义并不是SOURCE级别,更多的是CLASS级别,其实:**CLASS包含了SOURCE,RUNTIME包含SOURCE、CLASS。**所以CLASS是包含了SOURCE的场景,RUNTIME则包含了所有保留级的注解使用场景。所以对于APT来说,不管使用何种保留时都可以。

CLASS

定义为CLASS的注解,会保留在class文件中,但是会被虚拟机忽略(即无法在运行期反射获取注解)。此时完全符合此种注解的应用场景为字节码操作。如:AspectJ、热修复Roubust等框架。

在Android开发中,保留在class,但是会在dex被抛弃

RUNTIME

注解保留至运行期,意味着我们能够在运行期间结合反射技术获取注解中的所有信息。如Retofit,借助反射获取获取用户定义在注解中的请求配置信息,基于获取的这些请求配置完成对Request请求的构建。

十八、Activity如何保存状态的?

1.你在工作中,留意过在Android中存在下列几种情况会使Activity的状态发生变化?

答:

  • 配置变更(如屏幕翻转)
  • 系统自动销毁Activity(当系统内存不足时)
  • 手动销毁Activity(如点击返回键或在概览界面销毁Activity)

用户对上述几种状态的变更有着不同的期望,对于前两项,用户期望应用重新回到前台时保持着之前的状态,如果用户在屏幕翻转之前正在向输入框中输入数据,在屏幕翻转之后不希望已经输入的数据被删除,用户同样期望在切换到QQ回复好友消息后,即使之前的应用被系统销毁,但当用户重新返回应用后输入框中的文本依然存在。当用户手动销毁应用之后,用户期望下一次重新打开时应用以空白状态进行显示。

但是问题来了,针对上述三种情况,系统默认会销毁Activity从而小村存储在Activity实例中的所有界面状态。当然对于第三种情况着正是用户期望的,但我们需要通过一些方式来保存应用的某些状态以保证在发生配置变更或系统自动销毁Activity的时候恢复界面瞬态。

Android为我们提出了解决方案。我们可以通过使用ViewModel和onSaveInstanceState()保留页面瞬态。

ViewModel将数据保存在内存中,并与一个Actitvity相关联,在配置更改期间保存在内存中,系统会自动将ViewModel与发生配置更改后产生的新Actitivy实例相关联。

画草图:

在这里插入图片描述

onSaveInstanceState()回调在系统终止应用时被调用,我们可以在这个回调中保存页面瞬态。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KhHj1fxG-1684741434870)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230519213819512.png)]

除了使用onSaveInstanceState在系统销毁进程时保存数据,我们还可以使用SavedStateHandle对象保存数据,保存在SavedStateHandle中的数据会在进程被系统终止后继续保留。

ViewModel通过其构造函数接收SavedStateHandle对象,要设置ViewModel接收SavedStateHandle对象,需要向ViewModelProvider中传递SavedStateViewModelFactory对象,具体用法如下:

myViewModel = new ViewModelProvider(this, new SavedStateViewModelFactory(getApplication(), this))
                  .get(MyViewModel.class);

然后在自己实现的ViewModel的子类中添加构造方法:

public class MyViewModel extends ViewModel {
    private SavedStateHandle hanlder;

    public MyViewModel(SavedStateHandle hanlder) {
        this.hanlder = hanlder;
    }
}

十九、为什么 Android 要采用 Binder 作为 IPC 机制?

简单来说,Binder 是android系统工程师为android 定制的一个跨进程通信方法,当然它也不是android 系统原创的,是参考了OpenBinder的实现而引进到Google的。Binder是综合了android系统的特点,从性能,设计架构,安全性等几个方面的综合平衡而设计的,具体的关于Binder的实现细节,朋友们可以参考 上面的题目 《描述下Binder机制原理》进行系统学习。

应该从几个方面与传统IPC机制做对比。

  1. 性能方面
    • 拷贝数据需要花时间,Binder只需拷贝一次,共享内存无需拷贝,其他的需要拷贝两次。
    • 从速度上来说,Binder仅次于共享内存,优于Socket,消息队列,管道,信号,信号量等。
  2. 特点方面
    • Binder:基于C/S 架构,易用性高。
    • 共享内存:
      • 多个进程共享同一块内存区域,必然需要某种同步机制。
      • 使用麻烦,容易出现数据不同步,死锁等问题。
    • Socket:
      • socket作为一款通用接口,其传输效率低,开销大。
      • 主要用在跨网络的进程间通信和本机上进程间的低速通信。
  3. 安全性方面
    • Binder:(安全性高)
      • 为每个APP分配不同UID,通过UID鉴别进程身份。
      • 即支持实名Binder,又支持匿名Binder。
    • 传统IPC:(不安全)
      • 完全依赖上层协议,只能由用户在数据包中填入UID/PID。
      • 访问接入点是开放的,任何程序都可以与其建立连接。

通过上面几个比较,特别是安全性这块,所以最终Android选择使用Binder机制进行通信。

二十、Handler的Callback存在,但返回true,handleMessage是否会执行?

首先,如果Handler的Callback存在,若Callback返回true,handleMessage则不会执行;若Callback返回false,则handleMessage仍然会执行。Handler对于消息的处理都会在Handler#dispatchMessage中完成分发,具体细节分析如下代码所示:

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        // 1. 设置了Message.Callback(Runnable)
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            // 2. 设置了 Handler.Callback(Callback )
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        // 3. 未设置 Handler.Callback 或 返回 false
        handleMessage(msg);
    }
}
public interface Callback {
    public boolean handleMessage(Message msg);
}

我们一起来看一下 Callback的源码,Handler.Callback的定义如下:

public interface Callback {
    /**
     * @param msg A {@link android.os.Message Message} object
     * @return True if no further handling is desired
     */
	boolean handleMessage(@NonNull Message msg);
}

Handler.Callback#handleMessage在处理Message后需要返回boolean类型的结果,而此返回值如果为true,那么在Handler#dispatchMessage中会直接return:

if (mCallback.handleMessage(msg)) {
	return;
}

因此Handler#handleMessage则不会执行。

篇幅原因,暂时只放了部分面试题内容,具体已经整理成了PDF文档,有需要的点击下方二维码免费领取。

友情提示:所有的面试题目都不是一成不变的,面试题目只是给大家一个借鉴作用,最主要的是给自己增加知识的储备,有备无患。

希望正在准备面试的朋友们能顺顺利利找到自己心仪的工作!!!

图片

在这里插入图片描述

  • 9
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2023年的前端面试中,可能会涉及到以下几个高频面试题: 1. 浏览器兼容性问题及解决方案:面试官可能会询问你在开发过程中遇到的浏览器兼容性问题以及你是如何解决的。你可以提到一些常见的兼容性问题,比如不同浏览器对CSS属性的支持不一致或JavaScript API的兼容性问题。解决方案可以包括使用CSS前缀、Polyfill库或检测浏览器特性并提供不同的代码实现。 2. 前后端接口文档和接口测试:你可能会被问到在前端开发中如何与后端协作。你可以提到根据后端提供的接口文档进行开发,使用工具(比如Postman)测试接口的可用性和返回值是否符合预期。同时,你还可以提到与后端沟通以了解前端需要的参数和数据结构。 3. 跨域问题及解决方案:面试官可能会问到前端如何实现跨域。你可以解释浏览器的同源策略以及由此带来的限制。然后提到一些解决方案,如使用JSONP、CORS(跨源资源共享)、代理服务器或反向代理等。 综上所述,2023年前端面试可能涉及浏览器兼容性问题及解决方案、前后端接口文档和接口测试、跨域问题及解决方案等。记住在回答面试问题时,要清晰、简洁地说明问题和解决方案。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [2023高频前端面试题总结答案)](https://blog.csdn.net/weixin_45102366/article/details/125525247)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [2023高频前端面试题(含答案)](https://blog.csdn.net/weixin_44672169/article/details/116011608)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值