Android && Java面试题
1. 面向对象思想。
2. java的三大特性。
封装、继承、多态。
3. String Buffer和String Builder区别。
StringBuffer支持并发操作,线性安全的,适合多线程中使用。
StringBuilder不支持并发操作,线性不安全的,不适合多线程中使用,在单线程中的性能比 StringBuffer高。
4. HashMap与HashTable区别。
5. Service有几种启动方式,分别为哪几种?
service有两种启动方式,一种是通过 startService() 来启动的,另一种是通过 bindService() 来启动的。
第一种:startService() 来启动:
特点:
- 一旦服务开启跟开启者就没有任何关系;
- 开启者退出之后,服务还是可以在后台长期运行的。前提是没有调用 stopService(Intent);
- 开启者不能调用服务里面的方法。
生命周期:
2018053114134692.png如果服务已经开启,就不会重复的执行 onCreate() ,而是调用 onStart() 或 onStartCommand()。而服务停止的时候调用 onDestory() 。
第二种:bindService() 来启动:
特点:
- bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。
- 绑定者可以调用服务里面的方法。
生命周期:
20180531142740474.png绑定服务不会调用 onStart() 或 onStartCommand() 方法。
6. Android的生命周期。
一个最简单的完整的Activity生命周期会按照如下顺序回调:onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy
。
onStart,Activity被用户所见;
onResume,Activity可以响应用户交互;
在实际应用场景中,假设有A,B两个 Activity,A位于栈顶,此时用户操作,从A Activity跳转到B Activity。那么对AB来说,具体会回调哪些生命周期中的方法呢?回调方法的具体回调顺序又是怎么样的呢?
- 开始时,A被实例化,执行的回调有
A:onCreate -> A:onStart -> A:onResume
。 - 当用户点击A中按钮来到B时,假设B全部遮挡住了A,将依次执行
A:onPause -> B:onCreate -> B:onStart -> B:onResume -> A:onStop
。 - 此时如果点击Back键,将依次执行
B:onPause -> A:onRestart -> A:onStart -> A:onResume -> B:onStop -> B:onDestroy
。
7. 简述handler。
Handler的主要工作包含消息的发送与接收过程。消息的发送通过post和send的一系列方法来实现。当Handler发送了消息之后,MessageQueue里就插入了一条消息,然后MessageQueue就会返回这条消息给Looper,Looper接收到消息之后就开始处理了,最终消息由Looper交给Handler处理,即Handler的dispatchMessage方法会被调用,这时Handler就进入了处理消息的阶段,最后经过一系列的判断之后,就会调用handleMessage()方法了。
引入handler的原因:
- 主线程不能进行耗时操作
- 子线程不能更新UI
- 所以可以借助Handler通信来完成线程间的通信
工作原理:
20160721221140979.pngMessage:发给线程处理的一个任务。
MessageQueue:存放Message的队列,保存在线程里。
Looper:循环器,不断的从MessageQueue中获取Message对象。
8. Android数据库。
SQLiteOpenHelper是一个抽象的帮助类,用于管理数据库的创建及版本维护操作。这个类会自动帮助我们在需要时打开数据库,在不存在时创建数据库,在必要时更新数据库。
- onCreate():会在数据库不存在,第一次创建时调用,所以数据库中的初始化操作,如创建表等操作需要在该方法中完成。
- onUpgrade():新的版本号比原来有提升时,调用,用以完成数据库的升级操作,如新版本的app中,需要添加一张表,或者修改某个表,就需要在新版本的app创建SQLiteOpenHelper对象时,向其构造函数传入一个更大的版本号,这个版本号会被newVersion接收。
- getReadaleDatabase():创建或打开一个数据库,返回代表该数据库的只读的SQLiteDatabase对象
- getWritableDatabase():创建或打开一个数据库,返回代表该数据库的可读可写的SQLiteDatabase对象
常用方法:
9. 说说常用的几种设计模式。
单例模式
观察者模式
工厂模式
10. 排序
快速排序
该方法的基本思想是:
- 先从数列中取出一个数作为基准数。
- 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
- 再对左右区间重复第二步,直到各区间只有一个数。
以一个数组作为示例,取区间第一个数为基准数。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
34 | 21 | 3 | 45 | 6 | 78 | 26 | 52 |
初始时,i = 0; j = 7; X = a[i] =34
由于已将a[0]中的数保存到X中,(理解成在数组a[0]上挖了个坑),可以将其它数据填充到这来。
从j开始向前找一个比X小或等于X的数。当j=6,符合条件,将a[6]挖出再填到上一个坑a[0]中。a[0]=a[6]; i++; 这样一个坑a[0]就被搞定了,但又形成了一个新坑a[6],怎么办?简单,再找数字来填a[6]这个坑。这次从i开始向后找一个大于X的数,当i=3,符合条件,将a[3]挖出再填到上一个坑中a[6]=a[3]; j--;
数组变为:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
26 |
21 | 3 | 45 | 6 | 78 | 45 |
52 |
i = 3,j = 6,X = 34,再重复上面的步骤,先从后向前找,再从前向后找。
从j开始向前找,当j=4,符合条件,将a[4]挖出填到上一个坑中,a[3] = a[4]; i++;
从i开始向后找,当i=4时,由于i==j退出。
此时,i = j = 4,而a[4]刚好又是上次挖的坑,因此将X填入a[4]。
数组变为:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
26 |
21 | 3 | 6 |
34 | 78 | 45 |
52 |
可以看出a[4]前面的数字都小于它,a[4]后面的数字都大于它。因此再对a[0…3]和a[5…7]这二个子区间重复上述步骤就可以了。
// 快速排序
public void quickSort(int s[], int l, int r){
if (l < r) {
int i = l, j = r, x = s[l];
while (i < j) {
while(i < j && s[j] >= x) // 从右向左找第一个小于x的数
j--;
if(i < j) s[i++] = s[j];
while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
i++;
if(i < j) s[j--] = s[i];
}
s[i] = x;
quick_sort(s, l, i - 1); // 递归调用
quick_sort(s, i + 1, r);
}
}
11. 递归
- 递归是常用的编程技术,其基本思想就是“自己调用自己”。
- 递归是一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法; 递归函数就是直接或间接调用自身的函数,也就是自身调用自己。
- 算1+2+3+...+n求和。
public static int sum(int n){
if (n > 0) {
return n + sum(n-1);
}else {
return 0;
}
}
- 递归阶乘n! = n * (n-1) * (n-2) * ...* 1(n>0)。
public static int recursionMulity(int n){
if(n == 1){
return 1;
}
return n * recursionMulity(n-1);
}
12. 数组去重怎么实现?
=======================================
React Native面试题
1.react native生命周期。
生命周期大致分为三个阶段:
第一阶段:是组件第一次绘制阶段,如图中的上面虚线框内,在这里完成了组件的加载和初始化;constructor() => componentWillMount() => render() => componentDidMount()
第二阶段:是组件在运行和交互阶段,如图中左下角虚线框,这个阶段组件可以处理用户交互,或者接收事件更新界面;若props改变:componentWillReceiveProps() => shouldComponentUpdate() => componentWillUpdate() => render() => componentDidUpdate()
;state改变:shouldComponentUpdate() => componentWillUpdate() => render() => componentDidUpdate()
;
第三阶段:是组件卸载消亡的阶段,如图中右下角的虚线框中,这里做一些组件的清理工作。componentWillUnmount()
2. 简述redux。
3.RN中如何调用原生界面?
4.简述react-thunk原理。
redux-thunk 是一个比较流行的 redux 异步 action 中间件,比如 action 中有setTimeout 或者通过 fetch 通用远程API 这些场景,那么久应该使用 redux-thunk 了。redux-thunk 帮助你统一了异步和同步 action 的调用方式,把异步过程放在 action 级别解决,对 component 没有影响。
源码
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
改造后的dispatch入参接受的数据类型:
1、非function,不处理,将action 传给下一个中间件
2、function类型的action, 自动触发函数,并且将dispatch传入
5.简述ES5和ES6的区别?
6. js数组中怎么判断对象?
7.js中数组去重。
思路:双层循环,外层循环元素,内层循环时比较值,如果有相同的值则跳过,不相同则push进数组。
Array.prototype.distinct = function() {
let arr = this;
let result = [],
i,
j,
len = arr.length;
for(i = 0; i < len; i++){
for(j = i + 1; j < len; j++){
if(arr[i] === arr[j]){
j = ++i;
}
}
result.push(arr[i]);
}
return result;
}
let array = [1,2,3,4,4,1,1,2,1,1,1];
array.distinct(); // 返回[3,4,2,1]
8.简述Promise的原理,什么时候使用Promise?
Promise的优势在于,可以在then方法中继续写Promise对象并返回,然后继续调用then来进行回调操作,避免了层层嵌套的回调函数。
使用js写队列
bufferKnife原理
简述箭头函数,怎么使用?
http在iso的哪一层?
http与https区别?
什么是无状态组件和状态组件?
react native 与原生怎么通信?
父组件与子组件怎么通信?
同一个父组件下的两个子组件怎么通信?
进程与线程的区别。
进程间怎么通信?
简述队列和栈。
数组和链表的区别?
surfaceView和View的区别?
FlatList和ListView的区别?
React Native数据持久化。
简述AsynStorage原理。
网友评论