首先说一下,今日头条的面试主要分为三轮到四轮,如果是旺季面三轮,首先是基础面试,基本面试一般10个题左右,最近面试了一下字节跳动的移动Android资深工程师,记录下博客。
现在网络疯传都2020年了,Android开发早凉了!是真的吗?我相信很多朋友对职业规划很迷茫!
推荐阅读:(2020年Android开发人员打破寒冬期的利器在哪里?是转行还是进阶?)
这篇文档会帮你在迷茫中指明方向!
第一面(面经)
1、请你编程实现单例模式,懒汉和饱汉写法?
2、请编程实现Java的生产者-消费者模型
3、HashMap的内部结构? 内部原理?
4、请简述Android事件传递机制, ACTION_CANCEL事件何时触发?
5、Android的进程间通信,Liunx操作系统的进程间通信。
6、JVM虚拟机内存结构,以及它们的作用。
7、简述Android的View绘制流程,Android的wrap_content是如何计算的?
8、有一个整形数组,包含正数和负数,然后要求把数组内的所有负数移至正数的左边,且保证相对位置不变,要求时间复杂度为O(n), 空间复杂度为O(1)。例如,{10, -2, 5, 8, -4, 2, -3, 7, 12, -88, -23, 35}变化后是{-2, -4,-3, -88, -23,5, 8 ,10, 2, 7, 12, 35}
第一面是北京的开发进行视频面试,有理论和编程题组成。用的是在线编程工具,如下图。
第一面(解析)
1、请你编程实现单例模式,懒汉和饱汉写法?
//饱汉写法public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
} //懒汉写法
private static final Singleton1 single = new Singleton1();
//静态工厂方法
public static Singleton1 getInstance() {
return single;
} 123456789101112131415161718
2、请编程实现Java的生产者-消费者模型
看到这个有点懵逼,要是大学毕业的时候写这个肯定没问题,这都工作多年,这也只能按照自己的思路写了。这里使用synchronized锁以及wait notify实现一个比较简单的。
import java.io.IOException;public class WaitAndNotify{
public static void main(String[] args) throws IOException
{
Person person = new Person(); new Thread(new Consumer("消费者一", person)).start(); new Thread(new Consumer("消费者二", person)).start(); new Thread(new Consumer("消费者三", person)).start(); new Thread(new Producer("生产者一", person)).start(); new Thread(new Producer("生产者一", person)).start(); new Thread(new Producer("生产者一", person)).start();
}
}
class Producer implements Runnable
{ private Person person; private String producerName; public Producer(String producerName, Person person)
{ this.producerName = producerName; this.person = person;
} @Override
public void run()
{ while (true)
{ try
{
person.produce();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable
{ private Person person; private String consumerName; public Consumer(String consumerName, Person person)
{ this.consumerName = consumerName; this.person = person;
} @Override
public void run()
{ try
{
person.consume();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
class Person
{ private int foodNum = 0; private Object synObj = new Object(); private final int MAX_NUM = 5; public void produce() throws InterruptedException
{ synchronized (synObj)
{ while (foodNum == 5)
{
System.out.println("box is full,size = " + foodNum);
synObj.wait();
}
foodNum++;
System.out.println("produce success foodNum = " + foodNum);
synObj.notifyAll();
}
} public void consume() throws InterruptedException
{ synchronized (synObj)
{ while (foodNum == 0)
{
System.out.println("box is empty,size = " + foodNum);
synObj.wait();
}
foodNum--;
System.out.println("consume success foodNum = " + foodNum);
synObj.notifyAll();
}
}
}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
3、HashMap的内部结构? 内部原理?
关于HashMap的问题,不再详述,这方面的资料也挺多,不多需要注意的是Java1.7和1.8版本HashMap内部结构的区别。
4、请简述Android事件传递机制, ACTION_CANCEL事件何时触发?
关于第一个问题,不做任何解释,书籍资料上都会介绍的
关于ACTION_CANCEL何时被触发?系统文档有这么一种使用场景:
在设计设置页面的滑动开关时,如果不监听ACTION_CANCEL,在滑动到中间时,如果你手指上下移动,就是移动到开关控件之外,则此时会触发ACTION_CANCEL,而不是ACTION_UP,造成开关的按钮停顿在中间位置。
意思是当滑动的时候就会触发,不知道大家搞没搞过微信的长按录音,有一种状态是“松开手指,取消发送”,这时候就会触发ACTION_CANCEL。
5、Android的进程间通信,Liunx操作系统的进程间通信。
关于这个问题也是被问的很多,此处也不做解释。
6、JVM虚拟机内存结构,以及它们的作用。
这个问题也比较基础,JVM的内存结构如下图所示
7、简述Android的View绘制流程,Android的wrap_content是如何计算的?
8、有一个整形数组,包含正数和负数,然后要求把数组内的所有负数移至正数的左边,且保证相对位置不变,要求时间复杂度为O(n), 空间复杂度为O(1)。例如,{10, -2, 5, 8, -4, 2, -3, 7, 12, -88, -23, 35}变化后是{-2, -4,-3, -88, -23,5, 8 ,10, 2, 7, 12, 35}
要实现上面的效果有两种方式:
-
**第一种:**两个变量,一个用来记录当前的遍历点,一个用来记录最左边的负数在数组中的索引值。然后遍历整个数组,遇到负数将其与负数后面的数进行交换,遍历结束,即可实现负数在左,正数在右。
-
**第二种:**两个变量记录左右节点,两边分别开始遍历。左边的节点遇到负值继续前进,遇到正值停止。右边的节点正好相反。然后将左右节点的只进行交换,然后再开始遍历直至左右节点相遇。这种方式的时间复杂度是O(n).空间复杂度为O(1)
//方法1 public void setParted(int[] a){
int temp=0;
int border=-1;for(int i=0;i<a.length;i++){ if(a[i]<0){ temp=a[i]; a[i]=a[border+1]; a[border+1]=temp; border++; } } for(int j=0;j<a.length;j++){ System.out.println(a[j]); } }//方法2public void setParted1(int[] a,int left,int right){
if(left>=right||left==a.length||right==0){
for(int i=0;i<a.length;i++){
System.out.println(a[i]);
}
return ;
}
while(a[left]<0){
left++;
}
while(a[right]>=0){
right--;
}
if(left>=right||left==a.length||right==0){
for(int i=0;i<a.length;i++){
System.out.println(a[i]);
}
return;
}
swap(a,left,right);
left++;
right--;
setParted1(a,left,right);
}
private void swap(int a[],int left,int right){
int temp=0;
temp=a[left];
a[left]=a[right];
a[right]=temp;
}
public static void main(String[] args) {
int a[]={1,2,-1,-5,-6,7,-7,-10};
new PartTest().setParted1(a,0,a.length-1);
} 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
显然,第二种实现的难点比较高,不过只要此种满足条件。
面试题和答案解析全部已经被我整理成PDF
近期需要面试的小伙伴建议阅读:(Android程序员如何在面试中更胜一筹?)
文章到此也就结束了,身为Android程序员的你在大厂面试中能否取得头筹?阅读的同时也不忘点赞哦!
欢迎在文章下方留言!