每一次面试前的准备都是一次对过往知识的回顾和总结...
1.for循环的执行顺序:
猎豹移动的一道Android笔试题,考察的就是for循环的执行顺序
public class ForLoop {
private static boolean foo(char c) {
System.out.println(c);
return true;
}
public static void main(String[] args) {
int i = 0;
for (foo('A'); foo('B') && i < 2; foo('C')) {
i++;
foo('D');
}
}
}
输出结果是:ABDCBDCB
for (表达式1; 表达式2; 表达式4) {
表达式3;
}
for循环的执行顺序:第一次循环,即初始化循环,执行表达式1、表达式2、表达式3(前提表达式2满足)、表达式4;第N>=2次循环,执行表达式2、表达式3(前提表达式2满足)、表达式4。
2.final、finally、finalize的区别:
a.final修饰数据是常量,但必须被初始化(定义时、代码块或构造方法时静态和非静态的区别),默认值不属于初始化;final修饰方法不能被子类重写;final修饰类不能被继承;
b.finally只能用在try/catch语句中,表示发生异常后最终总是被执行,即使return、continue、break也不能影响finally语句块的执行,例如:
private static ReturnException testReturn() {
try {
return new ReturnException();
} catch (Exception e) {
System.out.println("程序捕获了异常");
} finally {
System.out.println("finally类最终会执行");
}
return null;
}
private static class ReturnException {
public ReturnException() {
System.out.println("执行了return语句");
}
}
输出:
执行了return语句
finally类最终会执行
编译器在编译return new IOException()时会分为两个步骤,new IOException()在finally之前执行,return在finally之后执行,但catch语句不会被执行;
c.finalize用于垃圾回收器在决定回收对象时,会首先调用它的finallize()方法,在该方法中可以释放系统资源,如关闭输入输出流等;但是在《Java编程思想》这本书中并没有释放系统资源的相关描述,书上说垃圾回收只与内存有关,此方法应该用在“特殊”分配内存的释放上,如JNI为C++分配的内存,实际中输入输出流的关闭也是在try/catch的finally代码块中完成,所以该方法一般不常用。
3.生成长度为100,元素的范围是1~100的随机数组:
这道算法题在实际中的用途是音乐的随机播放,可以用经典的洗牌算法——Fisher–Yates shuffle费雪耶茨洗牌算法:
public static void shuffle(int[] data) {
int shuffle_key;
int temp;
Random rand = new Random();
int length = data.length;
for (int i = length - 1; i > 0; i--) {
shuffle_key = rand.nextInt(i + 1);
temp = data[i];
data[i] = data[shuffle_key];
data[shuffle_key] = temp;
}
}
基本思路是从1到i(1<=i<=n)个数字中依次随机抽取一个数字,并放到一个新序列的尾端(该算法通过互换数字实现),逐渐(i--)形成一个新的序列。计算一下概率:如果某个元素被放入第i个位置,就必须是在前i-1次选取中都没有选到它,并且第 i次恰好选中它,其概率是1/n,理论上可以达到等概率随机分布。
4.简述Android IPC(进程间通信)的机制:
Android程序主要是由Activity和Service组成的,这些Activity和Serivice可能运行在同一个进程中,也可能运行在不同的进程中,运行在不同进程的Activity和Service采用了Binder机制实现进程间通信(其实在同一进程中也可以采用Binder机制,不知道为什么,以后再研究)。当在Activity中bindService的时候,Service会返回一个包含了Service业务调用的 Binder对象,通过这个Binder对象,Activity就可以获取Service提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。
5.字符串中将连续出现的字符按出现次数从大到小的顺序排序,例如aaabbbbcca则输出bbbb、aaa、cc、a:
基本思路:首先找到连续出现的字符存到List中,然后再排序。
String s = "aaabbbbcccaab";
List<String> result = new ArrayList<String>();
for (int i = 0, j = i + 1, l = s.length(); i < l; i = j) {
char temp = s.charAt(i);
for (; j < l; j++) {
if (temp != s.charAt(j)) {
result.add(s.substring(i, j));
break;
}
}
// 边界
if (j == l) {
result.add(s.substring(i, j));
}
}
// 直接插入排序
int len = result.size();
for (int i = 1; i < len; i++) {
for (int j = i; j > 0 && result.get(j - 1).length() < result.get(j).length(); j--) {
String t = result.get(j);
result.set(j, result.get(j - 1));
result.set(j - 1, t);
}
}
输出:[bbbb, aaa, ccc, aa, b]
6.对Java中synchronized关键字的理解:
非static的synchronized,无论是synchronized方法还是synchronized代码块,都是对对象上锁(对象锁),多个线程不能同时执行所有synchronized方法或代码块,没有获得锁的线程会阻塞,等待当前线程执行完毕,但可以同时执行其它非synchronized方法;
static的synchronized或synchronized(类.class)是对类上锁(类锁),相当于对代码上锁,多个线程不能同时执行该类的所有static synchronized方法,跟这个类的对象没有关系。
7.sleep 、wait、notify、notifyAll等方法说明:
sleep是Thread类的方法,会使当前线程休眠一段时间后继续执行,Thread.sleep不会导致锁行为的改变,如果当前线程拥有锁,那么Thread.sleep不会让线程释放锁。wait是Object类的方法,在线程中调用对象的wait方法,会使当前线程停止运行,并释放它所拥有的锁,进入等待状态,当在其它线程中调用该对象的notify或notifyAll方法时,如果该线程可以获得锁则继续执行,否则继续等待。
notify只唤醒一个等待当前对象锁的线程,notifyAll唤醒所有等待当前对象锁的线程。