欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android实习面面试题+答案

程序员文章站 2022-05-09 20:37:27
题 二面: application里面创建子线程处理耗时任务能不能代替service里面处理耗时任务 子线程里面能不能创建两个looper 快速排序(口述)和排序的复杂...

二面:

application里面创建子线程处理耗时任务能不能代替service里面处理耗时任务

子线程里面能不能创建两个looper

快速排序(口述)和排序的复杂度

prim算法

如何证明贪心算法

双亲委派模型

权限关键字的含义,private除了set,get方法访问,还有什么方法

java中的四种引用

内存泄露和内存溢出的区别

java注解的实现

解答

application里面创建子线程处理耗时任务能不能代替service里面处理耗时任务
题目很有误导性。service也是运行在主线程中的,处理耗时任务依然要开启子线程。所以问题就变成了这样:application容器可以取代service容器吗先不讨论这个,先讨论activity容器和service容器的区别。前者如果是后台的容易被杀。application在app的生命周期内,都不会被杀。但是也不意味着可以取代。serivce是依附于进程的,如果它不依附于app进程,而且他所在的进程不被杀,那么他的生命周期可以比application更长。
子线程里面能不能创建两个looper
当然不行。你在Looper.myLooper()的时候会进行一个创建。然后存放在ThreadLocal里。他首先会进行一个threadLocal.get()的判断,如果不为空,会提示你只能创建一个。
手撸一个快排和计算他的复杂度
快排就是通过比较著名的挖坑填数法来理解的。(下面的快排代码新手可能得理解好一会了)
void quick_sort(int[] a, int start, int end) {
int base = a[start];
int s = start;
int e = end;
while(s < e) {
//从右向左搜,搜到比keng小的数
while(s < e && base < a[e]) {
e--;
if(s < e) {//之所以还要再比一次,不放到循环里比,是为了不想每次循环都做一次运算
a[s++] = a[e];//坑就是哨兵处
}
while(s < e && base > a[s]) {
s++;
if(s < e) {
a[e--] = a[s];
}
}
a[s] = base;//最后初始坑放入最后生成的坑,此时s==e
//递归
quick_sort(int[] a, start, i - 1);
quick_sork(int[] a, i + 1, end);
}
时间复杂度:因为这个是递归的情形,所以最好情况是55分,一次递归会比较n次,深度这样算:n n/2...1
经过k次,1变为n,2^k=n,k=log2n,所以深度是lgn,总复杂度是nlgn
最坏情况是已经排好序的数组,会比n-1次,n-2次,。。。1次,总和是n^2/2
平均情况挺难算的,但是思路也要了解:C(n)=n-1+1/n (C(0)+C(n-1)..)n次的和。第一层是n-1,后面的层数是取一个平均值,这点很容易理解。计算就比较坑了,网上也没有讲解,最后渐进于2nlnn
prim算法和贪心算法的证明
这两题,我选择不做,因为,没有意义。已经属于偏难怪的范畴了。要是安卓里的偏难怪题我还可以接受
类加载器+双亲委派模型
类加载器:在类加载的时候,需要通过类的全限定名->获取定义这个类的二进制流。
这个二进制流可以从class获取,可以从jar、war获取,可以从网络获取,可以由jsp文件生成。。。
类加载器+和类本身共同确定一个类,如果不是这个类加载器加载的,那么就不是同一个类。所以加载一个类如下:ClassLoaderTest.class.getClassLoader().loadClass("com.jvm.classloading.ClassLoaderTest").newInstance();
先获取这个类的类加载器,再去加载这个类,再去newInstance创建实例。
类加载器种类:从JVM角度,有两种类加载器:1.启动类加载器2.所有其他的类加载器
开发者角度1.启动类加载器,负责加载jar包等类库2.标准扩展类加载器:它负责将Java_Home /lib/ext或者由系统变量 java.ext.dir指定位置中的类库加载到内存中3.应用程序类加载器:将系统类路径(CLASSPATH)中指定的类库加载到内存中4.自定义类加载器
他们之间的层次关系就是:双亲委派模型,除了启动类加载器,其他的都应该有父加载器。
所以当一个加载器接到任务,是一层层向上抛任务的。父类能解决最好,不能解决还是他自己处理。
还有就是找父类的时候,找不到,一般就指定启动类加载器作为父类。
就这么简单,不过得好好理解,好好记忆。
private的属性,除了set和get,还能怎么访问
太简单了,反射呗。
Class.getDeclaredFields和Class.getDeclaredMethod。
前者是获取所有属性,后者是获取所有方法。
简单写一下吧。
比如Book对象,你想要拿他的一个private的bookName字段。
Field field = book.getClass().getDeclaredFields("bookName");
field.setAccessible(true)。
String bookName = field.get(book).toString();
就好了。注意下那个setAccessible方法,他就是让private的子段,变得可访问。
但是Class.getDeclaredFields拿不到继承的,Class.getField好像可以拿到继承的,但是不能拿到私有的,保护的。
内存泄漏和内存溢出的区别
我觉得内存泄漏你得从垃圾回收机制出发,好好讲讲。还是拿Handler的内存泄漏打比方。Looper,message,message.target=Handler,Activity。依然是可达的,故而不可释放。
注解的实现
我个人感觉这个东西很好用,也用它封装了很多控件。但是我对他的应用还很粗浅--就是简单的指明是运行时注解,指明你要从哪里获取(类上还是方法上还是字段上。。。)然后根据取得的值,进行处理。这是一种很好的封装方式。理解这点,估计暂时够用了。哦,对了,本质还是反射。Class.getAnnotion仍然是在程序运行时,获知了类中的一切,只不过我们获知的东西有点特殊,是依附于某个东西的(类上还是方法上还是字段上。。。)。