字节跳动Android面试题目与答案(2020)

目录

  • 一面
    • Java部分
      • Java集合
        • Hashmap
      • 多线程相关
        • 线程池
        • wait和sleep的区别
        • notify和notifyall的区别?为什么?
        • synchornized作用在静态方法和普通方法的区别,class和this的区别?
        • synchornized的monitor原理?
        • valitile有什么作用?是怎么实现的?
      • 内存模型
        • Java内存模型简单介绍下?堆区域都保存什么?栈区域都保存什么?方法区都保存什么?
        • 简述GC回收机制?什么适合做引用链的根结点?(常量和栈中内容)
      • 内部类
        • 静态内部类和非静态内部类区别?
      • 引用
        • 强引用 软引用 弱引用 虚引用
    • 网络协议
      • TCP和UDP
      • HTTPS
    • Android部分
      • Android动画
        • Android中提供的三种动画,有什么区别?
      • 异步操作
        • android中的异步操作
        • intentservice和service
        • handlerthread和thread
        • looper原理
      • 持久化
        • 文件存储形式?ContentProvider何时创建?SP线程安全吗?
    • 算法部分
  • 二面
    • 算法
    • 你是怎么理解内部类的?
    • 你是怎么理解注解的?
    • 你是如何理解Service的?和线程的区别?
    • 你对View事件分发是如何理解的?
    • 简述你对HTTP协议的理解?
    • 简述你对HyBrid的理解?
    • 简述你对px,dp,dip的认识?
  • 总结
  • 附加题目

一面

Java部分

Java集合

Hashmap

Hashmap和Linkedhashmap
hashmap的index算法
Hashmap的扩容?可以不是2倍吗?为什么?
Hashmap的put都做了什么
Linkedhashmap是如何保证插入有序的?如何保证数组的内容和链的内容都有序?

这部分问的很详细,面试之前最好看一遍源码,可以参考如下博客:
HashMap? ConcurrentHashMap? 相信看完这篇没人能难住你!

多线程相关

线程池

四种线程池和创建线程池的必要参数
什么时候创建非核心线程
核心线程会被回收么
非核心线程什么时候会被回收

这部分问的也比较细,主要理解四种线程池的特点,非核心线程和核心线程的区别,可以参考刘望舒的《Android进阶之光》,里面有非常详细的描述。

wait和sleep的区别

先来看一下线程状态图
字节跳动Android面试题目与答案(2020)_第1张图片
sleep
1、让当前线程休眠指定时间,进入sleeping状态
休眠时间的准确性依赖于系统时钟和CPU调度机制。
2、不释放已获取的锁资源,如果sleep方法在同步上下文中调用,那么其他线程是无法进入到当前同步块或者同步方法中的
3、可通过调用interrupt()方法来唤醒休眠线程。
4、sleep方法定义在java.lang.Thread中,作用于当前线程
5、sleep是静态方法

wait
1、让当前线程进入等待状态,当别的其他线程调用notify()或者notifyAll()方法时,当前线程进入就绪状态
2、wait方法必须在同步上下文中调用,例如:同步方法块或者同步方法中,这也就意味着如果你想要调用wait方法,前提是必须获取对象上的锁资源
3、当wait方法调用时,当前线程将会释放已获取的对象锁资源,并进入等待队列,其他线程就可以尝试获取对象上的锁资源
4、wait方法定义在Object类中,作用于对象本身;
4、wait是实例方法;

notify和notifyall的区别?为什么?

1)如果我使用notify(),将通知哪个线程?
无法保证,ThreadScheduler将从等待该监视器上的线程的池中选择一个随机线程。保证只有一个线程会被通知(随机性);
2) 我怎么知道有多少线程在等待,所以我可以使用notifyAll()?
它取决于程序逻辑,在编码时需要考虑一段代码是否可以由多个线程运行。理解线程间通信的一个很好的例子是在Java中实现生产者 - 消费者模式。
3) 如何调用notify()?
Wait()和notify()方法只能从synchronized方法或块中调用,需要在其他线程正在等待的对象上调用notify方法。
4) 什么是这些线程等待被通知等?
线程等待某些条件,例如在生产者 - 消费者问题中,如果共享队列已满,则生产者线程等待,如果共享队列为空,则生成者线程等待。由于多个线程正在使用共享资源,因此它们使用wait和notify方法相互通信。

锁池
  假设线程A已经拥有对象锁,线程B、C想要获取锁就会被阻塞,进入一个地方去等待锁的等待,这个地方就是该对象的锁池;
等待池
  假设线程A调用某个对象的wait方法,线程A就会释放该对象锁,同时线程A进入该对象的等待池中,进入等待池中的线程不会去竞争该对象的锁。

notify和notifyAll的区别
1、notify只会随机选取一个处于等待池中的线程进入锁池去竞争获取锁的机会;
2、notifyAll会让所有处于等待池的线程全部进入锁池去竞争获取锁的机会;

java.util.concurrent.locks下的Condition 他可以支持唤醒指定的线程

synchornized作用在静态方法和普通方法的区别,class和this的区别?

synchronized 关键字可以在多线程环境下用来作为线程安全的同步锁。
造成线程安全问题的主要诱因有两点,一是存在共享数据(也称临界资源),二是存在多条线程共同操作共享数据。
因此,引入了互斥锁的概念,即一个共享数据只能被一个线程访问,其他线程需要等待(阻塞),直至当前线程处理完毕释放该锁。
所以,synchronized方法就保证了同一时刻只有一个线程对方法或者代码块有共享数据的操作。而且,synchronized保证了一个线程对共享变量操作的变化被其他线程看到(可以替代volatile功能)。

Synchronized就是内置锁,是java语言特性提供的内置锁,其获得锁和释放锁是隐式的(进入代码块就是获得锁,走出代码就是释放锁)。
java.util.concurrent.locks 包中的锁是显示锁,需要进行lock和unlock。

分类
1、对象锁(对象锁是用于对象实例方法,或者一个对象实例上的)
2、类锁(类锁是用于类的静态方法或者一个类的class对象上的)
类的对象实例可以有很多个,但是每个类只有一个class对象,所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。但是有一点必须注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的。

用法
1、非静态方法的同步;(对象锁)
2、静态方法的同步;(类锁)
3、代码块;(this则是对象锁,A.class则是类锁)

对象锁
非静态方法使用 synchronized 修饰的写法,修饰实例方法时,锁定的是当前对象;
代码块使用 synchronized 修饰的写法,使用代码块,如果传入的参数是 this,那么锁定的也是当前的对象;
某个线程得到了对象锁之后,该对象的其他同步方法是锁定的,其他线程是无法访问的;
如果某个线程得到了对象锁,但是另一个线程还是可以访问没有进行同步的方法或者代码。进行了同步的方法(加锁方法)和没有进行同步的方法(普通方法)是互不影响的,一个线程进入了同步方法,得到了对象锁,其他线程还是可以访问那些没有同步的方法(普通方法)。当获取到与对象关联的内置锁时,并不能阻止其他线程访问该对象,当某个线程获得对象的锁之后,只能阻止其他线程获得同一个锁。

类锁
类锁需要 synchronized 来修饰静态 static 方法;
或者使用代码块,需引用当前的类;
由于静态方法是类所有对象共用的,所以进行同步后,该静态方法的锁也是所有对象唯一的,每次只能有一个线程来访问对象的该非静态同步方法;
类锁和对象锁是不一样的锁,是互相独立的

synchornized的monitor原理?

synchronized是可重入锁
当线程请求一个由其它线程持有的对象锁时,该线程会阻塞,而当线程请求由自己持有的对象锁时,如果该锁是重入锁,请求就会成功,否则阻塞;
特别注意另外一种情况,当子类继承父类时,子类也是可以通过可重入锁调用父类的同步方法;
与多线程并发执行的线程安全不同,可重入强调对单个线程执行时重新进入同一个子程序仍然是安全的;

重入锁实现可重入性原理或机制是:每一个锁关联一个线程持有者和计数器,当计数器为 0 时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;当某一线程请求成功后,JVM会记下锁的持有线程,并且将计数器置为 1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为 0,则释放该锁。

valitile有什么作用?是怎么实现的?

valitile保障了有序性和可见性,不保证原子性
在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是 轻量级的synchronized (它比synchronized的 使用和执行成本会更低 ,因为它不会引起线程上下文的切换和调度),它在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。
有序性是指valitile禁止指令重排序;

共享变量:在多个线程之间能够被共享的变量被称为共享变量。共享变量包括所有的实例变量静态变量数组元素。他们都被存放在堆内存中,Volatile只作用于共享变量

valitile作用
1 保证变量在各个线程的可见性,意思就是说这个变量的值一修改,其他线程可以立即得知。而一个普通变量需要先写回主内存,然后其他线程去读取这个值。2:禁止指令重排序优化。然而它并不能保证原子性,以及运算的线程安全

valitile原理
使用Violatile修饰的变量在汇编阶段,会多出一条lock前缀指令,它在多核处理器下回引发两件事情:
1、将当前处理器缓存行的数据写回到系统内存;
2、这个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效;
通常处理器和内存之间都有几级缓存来提高处理速度,处理器先将内存中的数据读取到内部缓存后再进行操作,但是对于缓存写会内存的时机则无法得知,因此在一个处理器里修改的变量值,不一定能及时写回缓存,这种变量修改对其他处理器变得“不可见”了。
但是,使用Volatile修饰的变量,在写操作的时候,会强制将这个变量所在缓存行的数据写回到内存中,但即使写回到内存,其他处理器也有可能使用内部的缓存数据,从而导致变量不一致,所以,在多处理器下,为了保证各个处理器的缓存是一致的,就会实现缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期,如果过期,就会将该缓存行设置成无效状态,下次要使用就会重新从内存中读取。

内存模型

Java内存模型简单介绍下?堆区域都保存什么?栈区域都保存什么?方法区都保存什么?

深入理解Java内存模型
JVM内存模型

简述GC回收机制?什么适合做引用链的根结点?(常量和栈中内容)

GC垃圾回收机制详解

基本不做回收的区域
Java运行时内存区域中,程序计数器、虚拟机栈、本地方法栈这3个区域基本不会被GC。因为这3个区域随线程而生,随线程而亡,栈中栈帧分配对少内存在类结构确定下来的时候就已知了(大体编译期占用多少内存已知),因此这几个区域的内存分配和回收具备确定性。

回收区域
Java堆和方法区。这部分区域对象在运行时才知道要分配什么对象,分配多少对象,分配多大对象,因此这部分的分配和回收是动态的。

内部类

静态内部类和非静态内部类区别?

Java内部类详解

内部类
内部类就是定义在一个类的内部,包含内部类的类就称为外部类
第一,内部类可以访问其所在类的属性(包括所在类的私有属性),内部类创建自身对象需要先创建其所在类的对象
第二,可以定义内部接口,且可以定义另外一个内部类实现这个内部接口;
第三,可以在方法体内定义一个内部类,方法体内的内部类可以完成一个基于虚方法形式的回调操作;
第四,内部类不能定义static元素;(静态的内部类可以)
第五,内部类可以多嵌套;

static内部类是内部类中一个比较特殊的情况,Java文档中是这样描述static内部类的:一旦内部类使用static修饰,那么此时这个内部类就升级为顶级类。
也就是说,除了写在一个类的内部以外,static内部类具备所有外部类的特性;

static内部类不仅可以在内部定义static元素,而且在构建对象的时候也可以一次完成。从某种意义上说,static内部类已经不算是严格意义上的内部类了。

与static内部类不同,内部接口自动具备静态属性,也就是说,普通类是可以直接实现内部接口的;

引用

强引用 软引用 弱引用 虚引用

一,强引用
Java中默认声明的就是强引用,只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了;

二,软引用
软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。

三,弱引用
弱引用的引用强度比软引用要更弱一些,无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。

四,虚引用
虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,它随时可能会被回收,

网络协议

TCP和UDP

什么情况下用UDP?什么情况下用UDP?举个例子
TCP为什么比UDP效率低?(超时重传机制,,还有一个是啥?记不清了。。。)

HTTPS

简述HTTPS?
为什么第一步要是用非对称加密?
CA证书都包含哪些信息?
为什么HTTPS要是用对称加密技术?
说说你对session和cookie的理解?
session服务器端是怎么管理的?
multipleForm是什么?有什么作用?(上传文件同时附加信息,还有啥??)

Android部分

Android动画

Android中提供的三种动画,有什么区别?

异步操作

android中的异步操作

安卓异步任务处理

intentservice和service

handlerthread和thread

looper原理

threadlocal在looper中的作用
handler导致内存泄漏除了remove还怎么解决?

Android Handler总结一:Handler使用
Android Handler总结二:HandlerThread
Android Handler总结三:源码分析

持久化

文件存储形式?ContentProvider何时创建?SP线程安全吗?

android 五种数据存储 :SharePreferences、SQLite、Contert Provider、File、网络存储

Android系统提供了四种存储数据方式。分别为:SharePreference、SQLite、Content Provider和File。但由于Android系统中,数据基本是私有的,都是存放于”data/data”程序包名目录下,所以要实现数据共享,正确方式是使用Content Provider

SQLite:SQLite是一个轻量级的数据库,支持基本的SQL语法,是常被采用的一种数据存储方式。Android为此数据库提供了一个名为SQLiteDatabase的类,封装了一些操作数据库的api

SharedPreference: 除SQLite数据库外,另一种常用的数据存储方式,其本质就是一个xml文件,常用于存储较简单的参数设置。

File: 即常说的文件(I/O)存储方法,常用语存储大数量的数据,但是缺点是更新数据将是一件困难的事情。

ContentProvider: Android系统中能实现所有应用程序共享的一种数据存储方式,由于数据通常在各应用间的是互相私密的,所以此存储方式较少使用,但是其又是必不可少的一种存储方式。例如音频,视频,图片和通讯录,一般都可以采用此种方式进行存储。每个Content Provider都会对外提供一个公共的URI(包装成Uri对象),如果应用程序有数据需要共享时,就需要使用Content Provider为这些数据定义一个URI,然后其他的应用程序就通过Content Provider传入这个URI来对数据进行操作。

URI由3个部分组成:“content://”、数据的路径、标识ID(可选)。

Sp实现原理和如何实现线程安全

算法部分

1、环形打印二维数组
2、约瑟夫问题(两种实现方式,一种链表,一种数组)
3、两个栈实现队列的pop和push;
4、单链表的初始化,返回第一个节点;返回倒数第N个节点

二面

算法

实现链表数字的加法与输出

你是怎么理解内部类的?

手写如何创建非静态内部类对象的创建与静态内部类的创建

你是怎么理解注解的?

Java注解总结

Java注解精讲

你是如何理解Service的?和线程的区别?

IntentService和Service的区别?线程是串行的还是并行的?
Service怎么启动?两种方式有什么区别?

Android组件之Service理解

你对View事件分发是如何理解的?

一个View消费了DOWN事件,后面的MOVE、UP事件还会拦截吗?
DOWN、UP事件详解

简述你对HTTP协议的理解?

HTTPS加密机制解析与总结

HTTPS协议格式是什么样的?
有哪些方法(GET,POST,PUT、DELETE…要全部说出来)?
不同方法中有什么区别?
都有哪些响应?

301和303的区别?
403和404的区别?
Http教程

简述你对HyBrid的理解?

JSBridge的原理?代码是怎么注入的?
回调和异步如何实现?
你怎么认识WebClient和WebChromeClient?

Android HyBrid开发实战

JSBridge实现原理
1、在Native端编写本地功能的Java类(如HostJsScope.java);
2、在初始化WebviewChromeClient时根据该类反射动态生成JS代码;
3、将动态生成的JS代码通过WebView.loadUrl触发的onProgressChanged方法注入到webview中,供前端可调用。注意这里注册的不是Java对象了,而是js对象,而且这个对象过滤掉了Object的公有方法,所以是安全的,同时是在onProgressChanged方法中将js代码注入,
经过我的测试,在WebviewChromeClient的这个回调中注入js代码可以长期保留,不会因跳转到下一个页面而无效。
4、在前端调用HostJsScope对应的接口,触发webview的onPrompt事件,进而调用本地Java方法,如果有返回值则调用JsCallback将数据返回前端;

Web中有些资源放在App资源目录下,如何实现?
web img加载Android本地图片

App的网络cookie和Web的Cookie如何同步?
Android H5 cookie同步

Android 中的cookie介绍

简述你对px,dp,dip的认识?

总结

宇宙条果然不是吹的,对技术的要求很高。
一面问的特别详细,问的时间特别长,主要是Java基本功的考察,问的也比较深入;
二面主要考察你对Android开发各方面的理解和总结,比较宽泛,尽量以点带面,展开来说;

关于算法,要求也比较高,一面二面都需要手写算法,而且定时,一般五分钟之内;这块也需要练下下。

附加题目

1、两个算法;
2、java四中修饰符;
3、二叉树、排序二叉树、平衡二叉树、红黑树;
4、hashmap原理,hashmap和hashtable的区别;
5、wait和sleep的区别;
6、valitle关键字作用;
7、双亲委派模型;
8、service两种启动模式的区别;bind方式一定会stopservice吗?先start后bind生命周期是什么样?

你可能感兴趣的:(#,Android总结与进阶)