时光如白驹过隙,忽然而已。2020年金三银四随着疫情的影响现在变成金五银六了,本人三年Android程序🐒一枚,面试了一段时间找到了一份工作,有人说三年前的你决定了三年后的自己,希望接下来的三年我能够不再迷茫,三年后的自己能对现在的我说,感谢现在努力的你。。。
1.简介java类加载机制,什么是双亲委托机制以及原理
Java中的类加载是在JVM虚拟机中实现的,JVM是Java能实现跨平台重要原因,Android中的热修复技术中的原理其实也是利用Java类加载原理,说清楚双亲委托机制其实也就回答的差不多了, 三言两语说不清,附上链接
答:https://blog.csdn.net/u014307117/article/details/47307225
2.Java中的内存回收机制
Java中的内存回收机制也就是常说的GC回收,首先要知道Java虚拟机运行时的内存分配,Java虚拟机运行时内存分为6个区域:程序计数器,Java虚拟机栈,本地方法栈,堆,方法区,运行时常量池。另外要知道对象创建的具体过程,也就是内存分配,先有分配才有回收。一.回收首先要确定哪些对象需要回收,有两种算法:可达性分析法,引用计数法 二.垃圾收集的算法:标记-清除算法(Mark-Sweep),复制算法,标记-整理算法(Mark-Compact),分代收集算法
答:https://www.jianshu.com/p/a9ff882337d4
3.Socket网络通信协议
Socket即套接字,是应用层 与 TCP/IP 协议族通信的中间软件抽象层,表现为一个封装了 TCP / IP协议族 的编程接口(API),首先分析一下计算机网络,分为五层 应用层 运输层 网络层 数据链路层 物理层 ,然后回答一下TCP协议的三次握手以及四次挥手,以及Soctet与Http的区别,最后说一下Socket的使用
答:https://juejin.im/entry/5a9581c75188257a5d2b6184
4.String、StringBuffer、StringBuilder区别(也算Java基础中被常问的一题)
1、相同点:都是final类,不允许被继承,主要是从性能和安全性上考虑的,因为这几个类都是经常被使用着,且考虑到防止其中的参数修改影响到其他的应用
2、三者在执行速度上:StringBuilder > StringBuffer > String (由于String是常量,不可改变,拼接时会重新创建新的对象回收旧的对象)。
3、StringBuffer是线程安全的,StringBuilder是线程不安全的。(由于StringBuffer有缓冲区且很多方法都带有synchronized关键字)
5.什么是匿名内部类(百度面试官问的,我TM居然没回答出来,Java白学了)
匿名内部类说白了就是没有名字的内部类,一般用于只需要使用一次的类,例如Android中常用的View.setOnClickListener就使用了匿名内部类
6.App包体积优化方案有哪些
1.业务方面:①移除一些已经不在使用的功能 2.技术方面:②精简语言配置去掉多语言支持,③精简支持的CPU架构目前大部分手机都支持arm-v7a所以可以考虑只保留这一种架构,④只保留一套设计图只保留一套设计图比如xxhdpi,如果某些地方适配不好单独添加设计图片 3.使用工具:①proguard代码混淆 混淆不光可以防止反编译还能去掉无用代码减少代码体积,②lint工具 保证项目的各个module的build.gradle中有以下代码
lintOptions {
abortOnError false
}
然后在项目根目录里执行
path/to/your/gradle lint
执行结束后,会生成lint报告,有xml和html两种格式,如果未使用资源过多,html中不会展示所有的未使用资源,所以建议用浏览器打开xml格式的报告,通过全局搜索UnusedResource定位未使用资源,删除这些资源时,要反复确认,因为lint不能发现通过getIdentifier动态引用的资源。
③shrinkResources 设置为 false 移除无用资源 ④资源混淆工具 腾讯的AndResGuard和字节跳动的AabResGuard,要正确配置否则会引起崩溃 ⑤Matrix-Apk-Checker Apk-Checker同lint一样,也能够检查未使用的资源,它直接处理apk包,但比lint更好的一点是,能够检测文件名不同而实际内容相同的图片,这是通过文件的md5比较实现的 ⑥滴滴Booster Booster 提供了性能检测、多线程优化、资源索引内联、资源去冗余、资源压缩、系统 Bug 修复等一系列功能模块比较好用 4.其他 ①将项目中的png图片使用tinypng进行压缩②将项目中的图片通过AndroidStudio工具转成webp格式③一些可以用代码实现,也可以用图片实现时,需要做一下权衡。比如可以通过drawable实现图片的方向切换④尽量少使用gif图⑤尽量避免使用Lottie,它会在asset中引入json文件
答:https://www.jianshu.com/p/c76a032b0f4c
7. 实现排序的算法(Sorting algorithm)有哪些,手写一下冒泡排序和快速排序
排序算法:冒泡算法、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序、基数排序
常见的排序算法(图文详解,下面的文字看不懂可以看一下)
①冒泡排序:从第一个数开始,相邻元素两两对比,小的数放前面。(每循环一次,最后一个数都会被确定下来,为每轮的最大数)
②选择排序:从第一个数开始,循环一圈找最小的数交换位置。(每循环一圈,第一个数都会被确定下来,为每轮最小的值)
③插入排序:从第二个数开始,跟前一个数比较,若比前一个数小,则交换位置,接着跟前一个数比较,直到比前一个数大为止。(从第一张开始整理扑克牌,小的往前插)(可能会出现一个数从最后比较到最前面,比较费时)
④希尔排序:希尔排序属于插入类排序,是将整个有序序列分割成若干个小的子序列分别进行插入排序。
排序过程:先取一个正整数d1<n,把所有序号相隔d1的数组元素放一组,组内进行直接插入排序,然后取d2<d1,重复上述分组和排序操作,直至d1=1,即所有记录放进一个组中排序为止。(将每间隔一定步距的数取出来进行比较,比如gap=5,就是把第1个、第6个、第11个…数取出来进行插入排序)
优点:当n值很大时,数据项每一趟排序需要移动的个数很少,但数据项的距离很长;当n值减小时,每一趟需要移动的数据增多,此时已经接近于它们排序后的最终位置。
希尔分析:
希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比o(n^2)好一些。
⑤归并排序 归并排序有两种实现方法:自上而下的递归;自下而上的迭代。下面讲递归法:
将原数组用二分法一直分到两个数为一组,然后通过比较将较小的数放到前面(通过一个中间数组排序);然后一层层向上排序。
(就是两个数比较进行排序,然后两组(四个数)进行比较排序,然后两组(八个数)进行比较排序…)
⑥快速排序 先找到一个基准点(一般指数组的中部),然后数组被该基准点分为两部分,依次与该基准点数据比较,如果比它小,放左边;反之,放右边。 左右分别用一个空数组去存储比较后的数据。最后递归执行上述操作,直到数组长度<=1。
特点:快速,常用。缺点是需要另外声明两个数组,浪费了内存空间资源。
//冒泡排序算法
public class DemoSort {
public static void main(String[] args) {
int[] numbers=new int[]{1,5,8,2,3,9,4};
for(int i=0;i<numbers.length-1;i++){
for(int j=0;j<numbers.length-1-i;j++){
if(numbers[j]>numbers[j+1]){
int temp=numbers[j];
numbers[j]=numbers[j+1];
numbers[j+1]=temp;
}
}
}
System.out.println("从小到大排序后的结果是:");
for(int i=0;i<numbers.length;i++)
System.out.print(numbers[i]+" ");
}
}
//快速排序算法
public class QuickSort {
public static void quickSort(int[] arr,int low,int high){
int i,j,temp,t;
if(low>high){
return;
}
i=low;
j=high;
//temp就是基准位
temp = arr[low];
while (i<j) {
//先看右边,依次往左递减
while (temp<=arr[j]&&i<j) {
j--;
}
//再看左边,依次往右递增
while (temp>=arr[i]&&i<j) {
i++;
}
//如果满足条件则交换
if (i<j) {
t = arr[j];
arr[j] = arr[i];
arr[i] = t;
}
}
//最后将基准为与i和j相等位置的数字交换
arr[low] = arr[i];
arr[i] = temp;
//递归调用左半数组
quickSort(arr, low, j-1);
//递归调用右半数组
quickSort(arr, j+1, high);
}
public static void main(String[] args){
int[] arr = {10,7,2,4,7,62,3,4,2,1,8,9,19};
quickSort(arr, 0, arr.length-1);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
8. == 和 equals 以及 hashCode的区别
== 是运算符,用来比较两个值、两个对象的内存地址是否相等;
equals是Object类的方法,默认情况下比较两个对象是否是同一个对象,内部实现是通过 “==”来实现的,如果想比较两个对象的其他内容,则可以通过重写equals方法。
hashCoed也是Object类里面的方法,返回值是一个对象的哈希码,同一个对象哈希码一定相等,但不同对象哈希码也有可能相等。
①、如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。
②、如果两个对象不equals,他们的hashcode有可能相等。
③、如果两个对象hashcode相等,他们不一定equals。
④、如果两个对象hashcode不相等,他们一定不equals。
9.MVC MVP MVVM 模式的演变过程以及有哪些区别(这个问题被问了三遍至少)
简单介绍可以看这篇文章 下面分析一下在这几种模式在Android中的应用情况以及优缺点
MVC(View Model Controller): View 层实际上目前在Android中就是XML或者自定义控件,Model和Controller 一般都是在Activity或Fragment中,模块划分不是特别明显约束性没有后端的Spring全家桶MVC模式那么强,所以就造成了一旦逻辑复杂点Activity或Fragment中几千行很常见。
MVP(View Model Presenter) : 这种模式目前应用的比较广泛 View层通常指 Activity或Fragment ,Presenter层做相应的数据的处理,Model用来请求接口获取数据传递给Presenter层 ,主要注意就是Activity的生命周期要通知到Presenter做相应的请求或者取消请求等操作。问题也很明显就是因View和Presenter的交互会过于频繁,耦合度高,所以一旦View变了就要创建一个Presenter,会创建很多类。
MVVM(View Model ViewModel): 目前Google推出了JetPack 组件,其中有个ViewModel 配合 dataBinding可以很好的实现MVVM (最好配合kotlin使用,酸爽)优点:利用观察者模式和数据绑定,减少写回调接口的过程,代码和逻辑和更简洁清晰,耦合度低 缺点:随着后期功能不断增加,viewmodel中的代码量会越来越多
简单的使用方法可以参考这篇文章:https://blog.csdn.net/wjj1996825/article/details/87784331
10.RxJava2是如何切换线程的,它的原理是怎样的(一嗨租车)
//rxjava切换线程代码
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
subscribeOn 用于指定上游线程,observeOn 用于指定下游线程,多次用 subscribeOn 指定上游线程只有第一次有效,多次用 observeOn 指定下次线程,每次都有效。
至于原理可以参考下面这两篇文章: Rxjava是如何实现线程切换的(上), Rxjava是如何实现线程切换的(下) 我看了很久才理解,主要还是要自己去阅读源码分析,看别人分析源码和自己看源码的感觉是不一样的。
先写这么多吧,后面还有不少面试题,在后面的文章里面总结吧,水平有限,如果写的有误,欢迎指出,我会及时修改。如果觉得这篇文章对你有用,欢迎点赞 收藏 😀