|
```
以上代码主要测试js与java相互调用,而由于按键这种系统事件被webview截获掉,有如下两种方式进行处理
1、把方向键的流程改成:先传给webcore,假如没处理,再在webview里面处理,这个需要修改webview.java代码
2、直接应用搞定,java捕获按键,然后调js函数,上面代码就是使用这种方法。
测试结果如下: 点击buttons按钮:
I/A ( 4990): Callfunction
I/A ( 4990): getSize
I/A ( 4990): getObject
I/A ( 4990): GetList:test
I/A ( 4990): getObject
I/A ( 4990): GetList:test
I/A ( 4990): getObject
I/A ( 4990): GetList:test
I/A ( 4990): getObject
I/A ( 4990): GetList:test
I/A ( 4990): getObject
I/A ( 4990): GetList:test
you press KEY_RIGHT
I/AA ( 4990): keyCode=22
I/A ( 4990): GetList:22
you press KEY_UP
I/AA ( 4990): keyCode=19
I/A ( 4990): GetList:19
you press KEY_DOWN
I/AA ( 4990): keyCode=20
I/A ( 4990): GetList:20
you press KEY_LEFT
I/AA ( 4990): keyCode=21
I/A ( 4990): GetList:21
这里为何使用这种方式,是因为对于上下左右及确定这种功能键被webview截取掉了,无法传递到webcore中,而只能重载OnKeyDown/OnKeyUp方法,再由js调用java方法来获取得。
对于数字键的处理可以直接在js中进行处理:
logcat中会有明显的打印,对于这些键没有截掉,所以可以直接获取得到:
D/webcore ( 4990): proc key: code=12
D/webcore ( 4990): proc key: nativeKey return false
D/webcore ( 4990): proc key: nativeKey return true
js代码可以如此编写:
```
```
39.Service和Activity在同一个线程吗
默认情况同一线程 main主线程 ui线程40.ViewStub的应用
在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局。那么最通常的想法就是把可能用到的View都写在上面,先把它们的可见性都设为View.GONE,然后在代码中动态的更改它的可见性。这样的做法的优点是逻辑简单而且控制起来比较灵活。但是它的缺点就是,耗费资源。虽然把View的初始可见View.GONE但是在Inflate布局的时候View仍然会被Inflate,也就是说仍然会创建对象,会被实例化,会被设置属性。也就是说,会耗费内存等资源。
推荐的做法是使用android.view.ViewStub,ViewStub是一个轻量级的View,它一个看不见的,不占布局位置,占用资源非常小的控件。可以为ViewStub指定一个布局,在Inflate布局的时候,只有ViewStub会被初始化,然后当ViewStub被设置为可见的时候,或是调用了ViewStub.inflate()的时候,ViewStub所向的布局就会被Inflate和实例化,然后ViewStub的布局属性都会传给它所指向的布局。这样,就可以使用ViewStub来方便的在运行时,要还是不要显示某个布局。
但ViewStub也不是万能的,下面总结下ViewStub能做的事儿和什么时候该用ViewStub,什么时候该用可见性的控制。
首先来说说ViewStub的一些特点:
1. ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了。
2. ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,当然也可以把View写在某个布局文件中。
基于以上的特点,那么可以考虑使用ViewStub的情况有:
1. 在程序的运行期间,某个布局在Inflate后,就不会有变化,除非重新启动。
因为ViewStub只能Inflate一次,之后会被置空,所以无法指望后面接着使用ViewStub来控制布局。所以当需要在运行时不止一次的显示和隐藏某个布局,那么ViewStub是做不到的。这时就只能使用View的可见性来控制了。
2. 想要控制显示与隐藏的是一个布局文件,而非某个View。
因为设置给ViewStub的只能是某个布局文件的Id,所以无法让它来控制某个View。
所以,如果想要控制某个View(如Button或TextView)的显示与隐藏,或者想要在运行时不断的显示与隐藏某个布局或View,只能使用View的可见性来控制。
下面来看一个实例
在这个例子中,要显示二种不同的布局,一个是用TextView显示一段文字,另一个则是用ImageView显示一个图片。这二个是在onCreate()时决定是显示哪一个,这里就是应用ViewStub的最佳地点。
先来看看布局,一个是主布局,里面只定义二个ViewStub,一个用来控制TextView一个用来控制ImageView,另外就是一个是为显示文字的做的TextView布局,一个是为ImageView而做的布局:
```xml
```
为TextView的布局:
```xml
```
为ImageView的布局:
```
```
下面来看代码,决定来显示哪一个,只需要找到相应的ViewStub然后调用其infalte()就可以获得相应想要的布局:
```java
package com.effective;
import android.app.Activity;
import android.os.Bundle;
import android.view.ViewStub;
import android.widget.ImageView;
import android.widget.TextView;
public class ViewStubDemoActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewstub_demo_activity);
if ((((int) (Math.random() * 100)) & 0x01) == 0) {
// to show text
// all you have to do is inflate the ViewStub for textview
ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_text);
stub.inflate();
TextView text = (TextView) findViewById(R.id.viewstub_demo_textview);
text.setText("The tree of liberty must be refreshed from time to time" +
" with the blood of patroits and tyrants! Freedom is nothing but " +
"a chance to be better!");
} else {
// to show image
// all you have to do is inflate the ViewStub for imageview
ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_image);
stub.inflate();
ImageView image = (ImageView) findViewById(R.id.viewstub_demo_imageview);
image.setImageResource(R.drawable.happy_running_dog);
}
}
}
```
运行结果:
使用的时候的注意事项:
1. 某些布局属性要加在ViewStub而不是实际的布局上面,才会起作用,比如上面用的android:layout_margin*系列属性,如果加在TextView上面,则不会起作用,需要放在它的ViewStub上面才会起作用。而ViewStub的属性在inflate()后会都传给相应的布局。
41.android开发中怎么去调试bug
逻辑错误
1.断点 debug
2. logcat ,
界面布局,显示 hierarchyviewer.bat42.书写出android工程的目录结构以及相关作用
下面是HelloAndroid项目在eclipse中的目录层次结构:
由上图可以看出项目的根目录下共有九个文件(夹),下面就这九个文件(夹)进行详解:
1.1src文件夹和assets文件夹:
每个Android程序都包含资源目录(src)和资产目录(assets),资源和资产听起来感觉没有多大差别,但在存储外部内容时用资源(src)比较多,其中它们的区别在于存放在资源(src)下的内容可以通过应用程序的R类进行访问,而存放在资产(assets)下的内容会保持原始文件的格式,如果需要访问,则必须使用AssetManager以字节流的方式来读取,用起来非常的不方便。为了方便使用,通常文件和数据都会保存在资源(src)目录下
1.2res(Resource)目录:资源目录
可以存放一些图标,界面文件和应用中用到的文字信息,下图为res目录截图:
1.2.1 drawable-*dpi文件夹:将图标按分辨率的高低放入不同的目录,其中draeable-hdpi用来存放高分辨率的图标,drawable-mdpi用来存放中等分辨率的图标,drawable-ldpi用来存放低分辨率的图标
1.2.2 values文件夹:用来存放文字的信息
(1)strings.xml:用来定义字符串和数值
Hello World, Hello 3G
Android1.1
哥想你了
按钮1
按钮1
每个string标签生命了一个字符串,name属性指定它的引用值
(2)为什么要把这些出现的文字单独放在strings.xml文件中?
答案:一是为了国际化,如果需要将文件中的文字换成别的国家的语言,就可以只需要替换掉一个strings.xml文件就可以了
二是为了减少应用的体积,例如,我们要在应用中使用“哥想你了”这句话1000次,如果我们没有将“哥想你了”定义在strings.xml文件中,而是直接在应用中使用时写上这几个字,那么我们就会在应用中写4000个字。4000个字和4个字占用的内存可是有很大差距的啊,况且手机的内存本来就小,所以应该是能省就省
(3)另外还有arrays.xml,color.xml等定义数组,颜色的,都最好用单独的一个xml文档
1.2.3 layout文件:用来存放界面信息
本例中的布局文件是自动生成的“main.xml”
元素:线性布局的意思,在该元素下的所有子元素都会根据他的”orientation”属性来决定是按行还是按列或者按逐个显示进行布局的
元素:是一种显示控件,他的”text”属性指定了在这个元素上显示的内容
1.3 gen目录:gen目录下只有一个自动生成的“R.java”文件
```java
/*AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated bythe
* aapt tool from the resource data itfound. It
* should not be modified by hand.
*/
packagecn.csdn.android.demo;
public final class R {
public static final class attr {
}
public static final class drawable {
public static final int ic_launcher=0x7f020000;
}
public static final class id {
public static final int button1=0x7f050000;
public static final int radioButton1=0x7f050001;
public static final int toggleButton1=0x7f050002;
}
public static final class layout {
public static final int main=0x7f030000;
}
public static final class string {
public static final int app_name=0x7f040001;
public static final int hello=0x7f040000;
public static final int start=0x7f040004;
public static final int startButton=0x7f040003;
public static final int test=0x7f040002;
}
}
```
R.java文件:默认有attr,drawable,layout,string这四个静态内部类,每个静态内部类对应一中资源,如layout静态内部类对应layout中的界面文件,string静态内部类对应string内部的string标签。如果在layout中在增加一个界面文件或者在string内增加一个string标签,R.java会自动在其对应的内部类增加所增加的内容。
R.java除了自动标识资源的索引功能外,还有另一个功能,就是当res文件中的某个资源在应用中没有被用到,在这个应用被编译时,系统不会把对应的资源编译到应用中的APR包中。
1.4 AndroidManifest.xml 功能清单文件
每个应用程序都会有一个AndroidManifest在它的根目录里面。这个清单为Android系统提供了这个应用的基本信息,系统在运行之前必须知道这些信息,另外,如果我们使用系统自带的服务,如拨号服务,应用安装服务等,都必须在AndroidManifest.xml文件中声明权限
AndroidManifest.xml的功能:
命名应用程序的Java应用包,这个包名用来唯一标识应用程序;
描述应用程序的组件,对实现每个组件和公布其功能的类进行命名,这些声明使得Android系统了解这些组件以及它们在什么条件下可以被启动
决定哪个组件运行在哪个进程里面
声明应用程序必须具备的权限,用以访问受保护的API,以及和其他进程的交互
声明应用程序其他的必备权限,用以组件之间的交互
列举application所需要链接的库
以HelloAndroid项目的功能清单为例子进行讲解:
```xml
```
1.4.1 元素
```xml
```
元素是AndroidManifest.xml的根元素,”xmlns:android”是指该文件的命名空间,“package”属性是Android应用所在的包,“android:versionCode”指定应用的版本号,如果应用不断升级,则需要修改这个值,”android:versionName”是版本的名称,这个可以根据自己的喜爱改变
1.4.2 元素
```xml
```
元素是一个很重要的元素,开发组件都会在此下定义
元素的”icon”属性是用来设定应用的图标,其中“@drawable/ic_launcher”的意思是:在R.java文件中的drawable静态内部类下的icon,如下图所示
元素的“label”属性用来设定应用的名称,其中“@string/app_name”和上述的一样,也是R.java文件中的string静态内部类下的app_name
1.4.3 元素
```xml
```
元素的作用是注册一个activity信息,当我们在创建“HelloAndroid”这个项目时,指定了“Created Activity”属性为“HelloActivity”,然后ADT在生成项目时帮我们自动创建了一个Activity,就是“HelloActivity.java”;
元素的“name“属性指定的是Activity的类名,其中“.HelloActivity”中的“.”指的是元素中的“package”属性中指定的当前包,所以“.HelloActivity”就相当于“cn.csdn.android.demo.HelloActivity.java”,如果Activity在应用的包中可以不写“.”,但是为了避免出错,还是写上这个点把
1.4.4元素
如果直接翻译的话是“意图过滤器”,组件通过告诉它们所具备的功能,就是能响应意图类型,在intent中设置action, data, categroy之后在对应的intentfilter中设置相同的属性即可通过过滤被activity调用
1.5应用要求运行的最低Android版本
1.6 存放Android自身的jar包 43.ddms 和traceview的区别.
daivilk debug manager system
1.在应用的主activity的onCreate方法中加入Debug.startMethodTracing("要生成的traceview文件的名字");
2.同样在主activity的onStop方法中加入Debug.stopMethodTracing();
3.同时要在AndroidManifest.xml文件中配置权限
3.重新编译,安装,启动服务,测试完成取对应的traceview文件(adb pull /sdcard/xxxx.trace)。
4.直接在命令行输入traceview xxxxtrace,弹出traceview窗口,分析对应的应用即可。
traceview 分析程序执行时间和效率
KPI : key performance information : 关键性能指标:
splash界面不能超过5秒
从splash 界面加载mainactivity 不能超过0.7秒 44.谈谈NDK
NDK全称:Native Development Kit。
1、NDK是一系列工具的集合。
* NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。[1]
* NDK集成了交叉编译器,并提供了相应的mk文件隔离平台、CPU、API等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。
* NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。
2、NDK提供了一份稳定、功能有限的API头文件声明。
Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。
45.请介绍下Android的数据存储方式。
一.SharedPreferences方式
二sdcard
三内部存储
四SqliteDatabase
五. 网络存储方式46.谈谈推送,优缺点以及实现原理
本文主旨在于,对目前Android平台上最主流的几种消息推送方案进行分析和对比,比较客观地反映出这些推送方案的优缺点,帮助大家选择最合适的实施方案。
方案1、使用GCM服务(Google Cloud Messaging)
简介:Google推出的云消息服务,即第二代的C2DM。
优点:Google提供的服务、原生、简单,无需实现和部署服务端。
缺点:Android版本限制(必须大于2.2版本),该服务在国内不够稳定、需要用户绑定Google帐号,受限于Google。
方案2、使用XMPP协议(Openfire + Spark + Smack)
简介:基于XML协议的通讯协议,前身是Jabber,目前已由IETF国际标准化组织完成了标准化工作。
优点:协议成熟、强大、可扩展性强、目前主要应用于许多聊天系统中,且已有开源的Java版的开发实例androidpn。
缺点:协议较复杂、冗余(基于XML)、费流量、费电,部署硬件成本高。
方案3、使用MQTT协议(更多信息见:http://mqtt.org/)
简介:轻量级的、基于代理的“发布/订阅”模式的消息传输协议。
优点:协议简洁、小巧、可扩展性强、省流量、省电,目前已经应用到企业领域(参考:http://mqtt.org/software),且已有C++版的服务端组件rsmb。
缺点:不够成熟、实现较复杂、服务端组件rsmb不开源,部署硬件成本较高。
方案4、使用HTTP轮循方式
简介:定时向HTTP服务端接口(Web Service API)获取最新消息。
优点:实现简单、可控性强,部署硬件成本低。
缺点:实时性差。
对各个方案的优缺点的研究和对比,推荐使用MQTT协议的方案进行实现,主要原因是:MQTT最快速,也最省流量(固定头长度仅为2字节),且极易扩展,适合二次开发。接下来,我们就来分析使用MQTT方案进行Android消息的原理和方法,并架设自己的推送服务。
1、推送原理分析
实际上,其他推送系统(包括GCM、XMPP方案)的原理都与此类似。
2、推送服务端准备
a> 下载&解压rsmb安装包(下载地址:http://www.alphaworks.ibm.com/tech/rsmb)
b> 进入对应的目录,比如32位的Linux系统则应该进入linux_ia32目录。
c> 编辑配置文件broker_1883.cfg,配置如下:
[html] view plaincopy
port 1883
max_inflight_messages 10
max_queued_messages 1000
d> 运行./broker broker_1883.cfg,显示如下:
20120823 110454.039 CWNAN9999I Really Small Message Broker
20120823 110454.039 CWNAN9997I Licensed Materials - Property of IBM
20120823 110454.039 CWNAN9996I Copyright IBM Corp. 2007, 2010 All Rights Reserved
20120823 110454.039 CWNAN9995I US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
20120823 110454.039 CWNAN0049I Configuration file name is broker_1883.cfg
20120823 110454.040 CWNAN0053I Version 1.2.0, Aug 18 2010 17:03:35
20120823 110454.040 CWNAN0054I Features included: bridge
20120823 110454.040 CWNAN9993I Author: Ian Craggs (icraggs@uk.ibm.com)
20120823 110454.040 CWNAN0014I MQTT protocol starting, listening on port 1883
... ...
这样,推送服务的服务端就已经准备好了,监听1883端口。
3、推送客户端准备
a> 下载&解压AndroidPushNotificationsDemo项目(下载地址:https://github.com/tokudu/AndroidPushNotificationsDemo)
b> 将该项目导入Eclipse中(File -> Export -> Existing Projects into Workspace)
c> 修改PushService.java中的MQTT_HOST常量为推送服务端的IP地址。
d> 启动Android模拟器,并安装该项目。
注意:在新版本的Android SDK中可能会遇到以下错误。
... ...
08-23 02:28:44.184: W/dalvikvm(282): VFY: unable to find class referenced in signature (Lcom/ibm/mqtt/MqttPersistence;)
08-23 02:28:44.194: I/dalvikvm(282): Failed resolving Lcom/tokudu/demo/PushService$MQTTConnection; interface 35 'Lcom/ibm/mqtt/MqttSimpleCallback;'
08-23 02:28:44.194: W/dalvikvm(282): Link of class 'Lcom/tokudu/demo/PushService$MQTTConnection;' failed
08-23 02:28:44.194: E/dalvikvm(282): Could not find class 'com.tokudu.demo.PushService$MQTTConnection', referenced from method com.tokudu.demo.PushService.connect
08-23 02:28:44.194: W/dalvikvm(282): VFY: unable to resolve new-instance 42 (Lcom/tokudu/demo/PushService$MQTTConnection;) in Lcom/tokudu/demo/PushService;
... ...
08-23 02:28:44.404: E/AndroidRuntime(282): java.lang.VerifyError: com.tokudu.demo.PushService
08-23 02:28:44.404: E/AndroidRuntime(282): at com.tokudu.demo.PushActivity$1.onClick(PushActivity.java:32)
08-23 02:28:44.404: E/AndroidRuntime(282): at android.view.View.performClick(View.java:2408)
08-23 02:28:44.404: E/AndroidRuntime(282): at android.view.View$PerformClick.run(View.java:8816)
08-23 02:28:44.404: E/AndroidRuntime(282): at android.os.Handler.handleCallback(Handler.java:587)
08-23 02:28:44.404: E/AndroidRuntime(282): at android.os.Handler.dispatchMessage(Handler.java:92)
08-23 02:28:44.404: E/AndroidRuntime(282): at android.os.Looper.loop(Looper.java:123)
08-23 02:28:44.404: E/AndroidRuntime(282): at android.app.ActivityThread.main(ActivityThread.java:4627)
08-23 02:28:44.404: E/AndroidRuntime(282): at java.lang.reflect.Method.invokeNative(Native Method)
08-23 02:28:44.404: E/AndroidRuntime(282): at java.lang.reflect.Method.invoke(Method.java:521)
08-23 02:28:44.404: E/AndroidRuntime(282): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
08-23 02:28:44.404: E/AndroidRuntime(282): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
08-23 02:28:44.404: E/AndroidRuntime(282): at dalvik.system.NativeStart.main(Native Method)
... ...
原因是发布的时候没有加入wmqtt.jar包,解决办法如下:
1> 在项目根目录下创建libs目录,并把wmqtt.jar包移入该目录。
2> 重新配置项目的Java Build Path(右键菜单中的Properties选项中)。
3> 重新打包发布即可。
运行效果如下:
点击“Start Push Service”按钮即可开启推送服务。这时我们可以看到rsmb的服务日志中打出以下提示:
20120823 113742.297 CWNAN0033I Connection attempt to listener 1883 received from client tokudu/9774d56d682e549c on address 192.168.28.39:3345
其中的“9774d56d682e549c”就是对应的客户端ID号。
4、发送服务准备
a> 下载&解压PHP版的发送服务端代码send_mqtt.zip(下载地址:http://download.csdn.net/detail/shagoo/4520102)
b> 修改etc/config.php中推送服务端的IP地址和端口号,即MQTT_SERVER_HOST和MQTT_SERVER_POST常量。
c> 打开对应的URL地址,就可以看到发送服务的界面,实际上就是向对应的推送客户端推送消息。47.谈谈数据加密
数据加密又称密码学,它是一门历史悠久的技术,指通过加密算法和加密密钥将明文转变为密文,而解密则是通过解密算法和解密密钥将密文恢复为明文。数据加密目前仍是计算机系统对信息进行保护的一种最可靠的办法。它利用密码技术对信息进行加密,实现信息隐蔽,从而起到保护信息的安全的作用。用自己的话来说就是,只有双方才知道的协议。
数据加密 - 密码算法分类
1按发展进程分密码的发展:古典密码,对称密钥 密码公开密钥密码.
2按加密模式分对称算法:序列密码和分组密码.
经典密码 代替密码: 简单代替多名或同音代替多表代替多字母或多码代替换位密码: •对称加密算法 DES AES •非对称公钥算法 RSA 背包密码McEliece密码Rabin 椭圆曲线EIGamal D_H 48.解决问题和思考问题的方式
首先查看官方提供的API,通过自己对功能的理解,然后通过网络的途径,下载demo可以选择 github ,查找问题可以选择 stackover flow,然后可以问身边的朋友。49.列举7到12个设计模式 以及它们的应用场景
设计模式,提供了很多软件工程问题所需处理的解决方案。
根据模式的目的可分为3类: 1.创建型模式:与对象的创建有关。 2.结构性模式:处理类与对象的组合。 3.行为性模式:对类或对象怎样交互和怎样 分配职责进行描述。
面向对象设计的2个基本原则: 1.针对接口编程,而不是针对实现编程。 2.优先使用对象组合,而不是类继承。
面向对象设计的5个设计原则: 1.单一职责原则(SRP) 2.开放封闭原则(OCP) 3.Liskov替换原则(LSP) 4.依赖倒置原则(DIP) 5.接口隔离原则(ISP)
23中设计模式: 1.创建型模式: (1).工厂方法模式 (2).抽象工厂模式 (3).创建者模式 (4).原型模式 (5).单例模式 2.结构型模式: (6).适配器模式 (7).桥模式 (8).组合模式 (9).装饰模式 (10).外观模式 (11).享元模式 (12).代理模式 3.行为型模式 (13).解释器模式 (14).模板方法模式 (15).职责链模式 (16).命令模式 (17).迭代器模式 (18).中介者模式 (19).备忘录模式 (20).观察者模式 (21).状态模式 (22).策略模式 (23).访问者模式 除此之外,后来人发现很多新的模式,如空模式等。
下面列举几个常见的问题导致重新设计,可能需要设计模式来分析解决: 1.通过显示的指定一个类来创建对象 2.对特殊操作的依赖 3.对硬件和软件平台的依赖 4.对对象表示或实现的依赖 5.算法依赖 6.紧耦合 7.通过生产子类来扩展功能 8.不能方便的对类进行修改
软件的设计臭味: 1.僵化性 2.脆弱性 3.顽固性 4.粘滞性 5.不必要的复杂性 6.不必要的重复 7.晦涩性 ... ... 总而言之,一句话,面向对象特性+原则+模式,折腾来折腾去就是这么个回事。
设计模式(Design Patterns)
——可复用面向对象软件的基础
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。本章系Java之美[从菜鸟到高手演变]系列之设计模式,我们会以理论与实践相结合的方式来进行本章的学习,希望广大程序爱好者,学好设计模式,做一个优秀的软件工程师!
在阅读过程中有任何问题,请及时联系:egg。
邮箱:xtfggef@gmail.com 微博:http://weibo.com/xtfggef
如有转载,请说明出处:http://blog.csdn.net/zhangerqing
企业级项目实战(带源码)地址:http://zz563143188.iteye.com/blog/1825168
23种模式java实现源码及收集五年的开发资料下载地址: http://pan.baidu.com/share/home?uk=4076915866&view=share
一、设计模式的分类
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下:
二、设计模式的六大原则
1、开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
5、迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。
三、Java的23中设计模式
从这一块开始,我们详细介绍Java中23种设计模式的概念,应用场景等情况,并结合他们的特点及设计模式的原则进行分析。
1、工厂方法模式(Factory Method)
工厂方法模式分为三种:
11、普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。首先看下关系图:
举例如下:(我们举一个发送邮件和短信的例子)
首先,创建二者的共同接口:
```java
public interface Sender {
public void Send();
}
其次,创建实现类:
```java
public class MailSender implements Sender {
@Override
public void Send() {
System.out.println("this is mailsender!");
}
}
```
```java
public class SmsSender implements Sender {
@Override
public void Send() {
System.out.println("this is sms sender!");
}
}
```
最后,建工厂类:
```java
public class SendFactory {
public Sender produce(String type) {
if ("mail".equals(type)) {
return new MailSender();
} else if ("sms".equals(type)) {
return new SmsSender();
} else {
System.out.println("请输入正确的类型!");
return null;
}
}
}
```
我们来测试下:
public class FactoryTest {
public static void main(String[] args) {
SendFactory factory = new SendFactory();
Sender sender = factory.produce("sms");
sender.Send();
}
}
```
输出:this is sms sender!
22、多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。关系图:
将上面的代码做下修改,改动下SendFactory类就行,如下:
```java
public class SendFactory {
public Sender produceMail(){
return new MailSender();
}
public Sender produceSms(){
return new SmsSender();
}
}
```
测试类如下:
```java
public class FactoryTest {
public static void main(String[] args) {
SendFactory factory = new SendFactory();
Sender sender = factory.produceMail();
sender.Send();
}
}
```
输出:this is mailsender!
33、静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
```java
public class SendFactory {
public static Sender produceMail(){
return new MailSender();
}
public static Sender produceSms(){
return new SmsSender();
}
}
```
```java
public class FactoryTest {
public static void main(String[] args) {
Sender sender = SendFactory.produceMail();
sender.Send();
}
}
```
输出:this is mailsender!
总体来说,工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。
2、抽象工厂模式(Abstract Factory)
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。因为抽象工厂不太好理解,我们先看看图,然后就和代码,就比较容易理解。
请看例子:
```java
public interface Sender {
public void Send();
}
两个实现类:
```java
public class MailSender implements Sender {
@Override
public void Send() {
System.out.println("this is mailsender!");
}
}
```
```java
public class SmsSender implements Sender {
@Override
public void Send() {
System.out.println("this is sms sender!");
}
}
```
两个工厂类:
```java
public class SendMailFactory implements Provider {
@Override
public Sender produce(){
return new MailSender();
}
}
```
```java
public class SendSmsFactory implements Provider{
@Override
public Sender produce() {
return new SmsSender();
}
}
```
在提供一个接口:
```java
public interface Provider {
public Sender produce();
}
```
测试类:
```java
public class Test {
public static void main(String[] args) {
Provider provider = new SendMailFactory();
Sender sender = provider.produce();
sender.Send();
}
}
```
其实这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好!
3、单例模式(Singleton)
单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:
1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。
首先我们写一个简单的单例类:
```java
public class Singleton {
/* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
private static Singleton instance = null;
/* 私有构造方法,防止被实例化 */
private Singleton() {
}
/* 静态工程方法,创建实例 */
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
/* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
public Object readResolve() {
return instance;
}
}
```
这个类可以满足基本要求,但是,像这样毫无线程安全保护的类,如果我们把它放入多线程的环境下,肯定就会出现问题了,如何解决?我们首先会想到对getInstance方法加synchronized关键字,如下:
```java
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
```
但是,synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了,所以,这个地方需要改进。我们改成下面这个:
```java
public static Singleton getInstance() {
if (instance == null) {
synchronized (instance) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
```
似乎解决了之前提到的问题,将synchronized关键字加在了内部,也就是说当调用的时候是不需要加锁的,只有在instance为null,并创建对象的时候才需要加锁,性能有一定的提升。但是,这样的情况,还是有可能有问题的,看下面的情况:在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了,我们以A、B两个线程为例:
a>A、B线程同时进入了第一个if判断
b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();
c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。
d>B进入synchronized块,由于instance此时不是null,因此它马上离开了synchronized块并将结果返回给调用该方法的程序。
e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。
所以程序还是有可能发生错误,其实程序在运行过程是很复杂的,从这点我们就可以看出,尤其是在写多线程环境下的程序更有难度,有挑战性。我们对该程序做进一步优化:
```java
private static class SingletonFactory{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonFactory.instance;
}
```
实际情况是,单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。这样我们暂时总结一个完美的单例模式:
```java
public class Singleton {
/* 私有构造方法,防止被实例化 */
private Singleton() {
}
/* 此处使用一个内部类来维护单例 */
private static class SingletonFactory {
private static Singleton instance = new Singleton();
}
/* 获取实例 */
public static Singleton getInstance() {
return SingletonFactory.instance;
}
/* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
public Object readResolve() {
return getInstance();
}
}
```
其实说它完美,也不一定,如果在构造函数中抛出异常,实例将永远得不到创建,也会出错。所以说,十分完美的东西是没有的,我们只能根据实际情况,选择最适合自己应用场景的实现方法。也有人这样实现:因为我们只需要在创建类的时候进行同步,所以只要将创建和getInstance()分开,单独为创建加synchronized关键字,也是可以的:
```java
public class SingletonTest {
private static SingletonTest instance = null;
private SingletonTest() {
}
private static synchronized void syncInit() {
if (instance == null) {
instance = new SingletonTest();
}
}
public static SingletonTest getInstance() {
if (instance == null) {
syncInit();
}
return instance;
}
}
```
考虑性能的话,整个程序只需创建一次实例,所以性能也不会有什么影响。
补充:采用"影子实例"的办法为单例对象的属性同步更新
```java
public class SingletonTest {
private static SingletonTest instance = null;
private Vector properties = null;
public Vector getProperties() {
return properties;
}
private SingletonTest() {
}
private static synchronized void syncInit() {
if (instance == null) {
instance = new SingletonTest();
}
}
public static SingletonTest getInstance() {
if (instance == null) {
syncInit();
}
return instance;
}
public void updateProperties() {
SingletonTest shadow = new SingletonTest();
properties = shadow.getProperties();
}
}
```
通过单例模式的学习告诉我们:
1、单例模式理解起来简单,但是具体实现起来还是有一定的难度。
2、synchronized关键字锁定的是对象,在用的时候,一定要在恰当的地方使用(注意需要使用锁的对象和过程,可能有的时候并不是整个对象及整个过程都需要锁)。
到这儿,单例模式基本已经讲完了,结尾处,笔者突然想到另一个问题,就是采用类的静态方法,实现单例模式的效果,也是可行的,此处二者有什么不同?
首先,静态类不能实现接口。(从类的角度说是可以的,但是那样就破坏了静态了。因为接口中不允许有static修饰的方法,所以即使实现了也是非静态的)
其次,单例可以被延迟初始化,静态类一般在第一次加载是初始化。之所以延迟加载,是因为有些类比较庞大,所以延迟加载有助于提升性能。
再次,单例类可以被继承,他的方法可以被覆写。但是静态类内部方法都是static,无法被覆写。
最后一点,单例类比较灵活,毕竟从实现上只是一个普通的Java类,只要满足单例的基本需求,你可以在里面随心所欲的实现一些其它功能,但是静态类不行。从上面这些概括中,基本可以看出二者的区别,但是,从另一方面讲,我们上面最后实现的那个单例模式,内部就是用一个静态类来实现的,所以,二者有很大的关联,只是我们考虑问题的层面不同罢了。两种思想的结合,才能造就出完美的解决方案,就像HashMap采用数组+链表来实现一样,其实生活中很多事情都是这样,单用不同的方法来处理问题,总是有优点也有缺点,最完美的方法是,结合各个方法的优点,才能最好的解决问题!
4、建造者模式(Builder)
工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。我们看一下代码:
还和前面一样,一个Sender接口,两个实现类MailSender和SmsSender。最后,建造者类如下:
```java
public class Builder {
private List list = new ArrayList();
public void produceMailSender(int count){
for(int i=0; i children = new Vector();
public TreeNode(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public TreeNode getParent() {
return parent;
}
public void setParent(TreeNode parent) {
this.parent = parent;
}
//添加孩子节点
public void add(TreeNode node){
children.add(node);
}
//删除孩子节点
public void remove(TreeNode node){
children.remove(node);
}
//取得孩子节点
public Enumeration getChildren(){
return children.elements();
}
}
```
```java
public class Tree {
TreeNode root = null;
public Tree(String name) {
root = new TreeNode(name);
}
public static void main(String[] args) {
Tree tree = new Tree("A");
TreeNode nodeB = new TreeNode("B");
TreeNode nodeC = new TreeNode("C");
nodeB.add(nodeC);
tree.root.add(nodeB);
System.out.println("build the tree finished!");
}
}
```
使用场景:将多个对象组合在一起进行操作,常用于表示树形结构中,例如二叉树,数等。
12、享元模式(Flyweight)
享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。
FlyWeightFactory负责创建和管理享元单元,当一个客户端请求时,工厂需要检查当前对象池中是否有符合条件的对象,如果有,就返回已经存在的对象,如果没有,则创建一个新对象,FlyWeight是超类。一提到共享池,我们很容易联想到Java里面的JDBC连接池,想想每个连接的特点,我们不难总结出:适用于作共享的一些个对象,他们有一些共有的属性,就拿数据库连接池来说,url、driverClassName、username、password及dbname,这些属性对于每个连接来说都是一样的,所以就适合用享元模式来处理,建一个工厂类,将上述类似属性作为内部数据,其它的作为外部数据,在方法调用时,当做参数传进来,这样就节省了空间,减少了实例的数量。
看个例子:
看下数据库连接池的代码:
```java
public class ConnectionPool {
private Vector pool;
/*公有属性*/
private String url = "jdbc:mysql://localhost:3306/test";
private String username = "root";
private String password = "root";
private String driverClassName = "com.mysql.jdbc.Driver";
private int poolSize = 100;
private static ConnectionPool instance = null;
Connection conn = null;
/*构造方法,做一些初始化工作*/
private ConnectionPool() {
pool = new Vector(poolSize);
for (int i = 0; i < poolSize; i++) {
try {
Class.forName(driverClassName);
conn = DriverManager.getConnection(url, username, password);
pool.add(conn);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/* 返回连接到连接池 */
public synchronized void release() {
pool.add(conn);
}
/* 返回连接池中的一个数据库连接 */
public synchronized Connection getConnection() {
if (pool.size() > 0) {
Connection conn = pool.get(0);
pool.remove(conn);
return conn;
} else {
return null;
}
}
}
```
通过连接池的管理,实现了数据库连接的共享,不需要每一次都重新创建连接,节省了数据库重新创建的开销,提升了系统的性能!本章讲解了7种结构型模式,因为篇幅的问题,剩下的11种行为型模式,
本章是关于设计模式的最后一讲,会讲到第三种设计模式——行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。这段时间一直在写关于设计模式的东西,终于写到一半了,写博文是个很费时间的东西,因为我得为读者负责,不论是图还是代码还是表述,都希望能尽量写清楚,以便读者理解,我想不论是我还是读者,都希望看到高质量的博文出来,从我本人出发,我会一直坚持下去,不断更新,源源动力来自于读者朋友们的不断支持,我会尽自己的努力,写好每一篇文章!希望大家能不断给出意见和建议,共同打造完美的博文!
先来张图,看看这11中模式的关系:
第一类:通过父类与子类的关系进行实现。第二类:两个类之间。第三类:类的状态。第四类:通过中间类
13、策略模式(strategy)
策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数,关系图如下:
图中ICalculator提供同意的方法, AbstractCalculator是辅助类,提供辅助方法,接下来,依次实现下每个类:
首先统一接口:
```java
public interface ICalculator {
public int calculate(String exp);
}
```
辅助类:
```java
public abstract class AbstractCalculator {
public int[] split(String exp,String opt){
String array[] = exp.split(opt);
int arrayInt[] = new int[2];
arrayInt[0] = Integer.parseInt(array[0]);
arrayInt[1] = Integer.parseInt(array[1]);
return arrayInt;
}
}
```
三个实现类:
```java
public class Plus extends AbstractCalculator implements ICalculator {
@Override
public int calculate(String exp) {
int arrayInt[] = split(exp,"\\+");
return arrayInt[0]+arrayInt[1];
}
}
```java
public class Minus extends AbstractCalculator implements ICalculator {
@Override
public int calculate(String exp) {
int arrayInt[] = split(exp,"-");
return arrayInt[0]-arrayInt[1];
}
}
```
```java
public class Multiply extends AbstractCalculator implements ICalculator {
@Override
public int calculate(String exp) {
int arrayInt[] = split(exp,"\\*");
return arrayInt[0]*arrayInt[1];
}
}
```
简单的测试类:
```java
public class StrategyTest {
public static void main(String[] args) {
String exp = "2+8";
ICalculator cal = new Plus();
int result = cal.calculate(exp);
System.out.println(result);
}
}
```
输出:10
策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可。
14、模板方法模式(Template Method)
解释一下模板方法模式,就是指:一个抽象类中,有一个主方法,再定义1...n个方法,可以是抽象的,也可以是实际的方法,定义一个类,继承该抽象类,重写抽象方法,通过调用抽象类,实现对子类的调用,先看个关系图:
就是在AbstractCalculator类中定义一个主方法calculate,calculate()调用spilt()等,Plus和Minus分别继承AbstractCalculator类,通过对AbstractCalculator的调用实现对子类的调用,看下面的例子:
```java
public abstract class AbstractCalculator {
/*主方法,实现对本类其它方法的调用*/
public final int calculate(String exp,String opt){
int array[] = split(exp,opt);
return calculate(array[0],array[1]);
}
/*被子类重写的方法*/
abstract public int calculate(int num1,int num2);
public int[] split(String exp,String opt){
String array[] = exp.split(opt);
int arrayInt[] = new int[2];
arrayInt[0] = Integer.parseInt(array[0]);
arrayInt[1] = Integer.parseInt(array[1]);
return arrayInt;
}
}
```
```java
public class Plus extends AbstractCalculator {
@Override
public int calculate(int num1,int num2) {
return num1 + num2;
}
}
```
测试类:
```java
public class StrategyTest {
public static void main(String[] args) {
String exp = "8+8";
AbstractCalculator cal = new Plus();
int result = cal.calculate(exp, "\\+");
System.out.println(result);
}
}
```
我跟踪下这个小程序的执行过程:首先将exp和"\\+"做参数,调用AbstractCalculator类里的calculate(String,String)方法,在calculate(String,String)里调用同类的split(),之后再调用calculate(int ,int)方法,从这个方法进入到子类中,执行完return num1 + num2后,将值返回到AbstractCalculator类,赋给result,打印出来。正好验证了我们开头的思路。
15、观察者模式(Observer)
包括这个模式在内的接下来的四个模式,都是类和类之间的关系,不涉及到继承,学的时候应该 记得归纳,记得本文最开始的那个图。观察者模式很好理解,类似于邮件订阅和RSS订阅,当我们浏览一些博客或wiki时,经常会看到RSS图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。先来看看关系图:
我解释下这些类的作用:MySubject类就是我们的主对象,Observer1和Observer2是依赖于MySubject的对象,当MySubject变化时,Observer1和Observer2必然变化。AbstractSubject类中定义着需要监控的对象列表,可以对其进行修改:增加或删除被监控对象,且当MySubject变化时,负责通知在列表内存在的对象。我们看实现代码:
一个Observer接口:
```java
public interface Observer {
public void update();
}
```
两个实现类:
```java
public class Observer1 implements Observer {
@Override
public void update() {
System.out.println("observer1 has received!");
}
}
```
```java
public class Observer2 implements Observer {
@Override
public void update() {
System.out.println("observer2 has received!");
}
}
```
Subject接口及实现类:
```java
public interface Subject {
/*增加观察者*/
public void add(Observer observer);
/*删除观察者*/
public void del(Observer observer);
/*通知所有的观察者*/
public void notifyObservers();
/*自身的操作*/
public void operation();
}
```
```java
public abstract class AbstractSubject implements Subject {
private Vector vector = new Vector();
@Override
public void add(Observer observer) {
vector.add(observer);
}
@Override
public void del(Observer observer) {
vector.remove(observer);
}
@Override
public void notifyObservers() {
Enumeration enumo = vector.elements();
while(enumo.hasMoreElements()){
enumo.nextElement().update();
}
}
}
```
```java
public class MySubject extends AbstractSubject {
@Override
public void operation() {
System.out.println("update self!");
notifyObservers();
}
}
```
测试类:
```java
public class ObserverTest {
public static void main(String[] args) {
Subject sub = new MySubject();
sub.add(new Observer1());
sub.add(new Observer2());
sub.operation();
}
}
```
输出:
update self! observer1 has received! observer2 has received!
这些东西,其实不难,只是有些抽象,不太容易整体理解,建议读者:根据关系图,新建项目,自己写代码(或者参考我的代码),按照总体思路走一遍,这样才能体会它的思想,理解起来容易!
16、迭代子模式(Iterator)
顾名思义,迭代器模式就是顺序访问聚集中的对象,一般来说,集合中非常常见,如果对集合类比较熟悉的话,理解本模式会十分轻松。这句话包含两层意思:一是需要遍历的对象,即聚集对象,二是迭代器对象,用于对聚集对象进行遍历访问。我们看下关系图:
这个思路和我们常用的一模一样,MyCollection中定义了集合的一些操作,MyIterator中定义了一系列迭代操作,且持有Collection实例,我们来看看实现代码:
两个接口:
```java
public interface Collection {
public Iterator iterator();
/*取得集合元素*/
public Object get(int i);
/*取得集合大小*/
public int size();
}
```
```java
public interface Iterator {
//前移
public Object previous();
//后移
public Object next();
public boolean hasNext();
//取得第一个元素
public Object first();
}
```
两个实现:
```java
public class MyCollection implements Collection {
public String string[] = {"A","B","C","D","E"};
@Override
public Iterator iterator() {
return new MyIterator(this);
}
@Override
public Object get(int i) {
return string[i];
}
@Override
public int size() {
return string.length;
}
}
```
```java
public class MyIterator implements Iterator {
private Collection collection;
private int pos = -1;
public MyIterator(Collection collection){
this.collection = collection;
}
@Override
public Object previous() {
if(pos > 0){
pos--;
}
return collection.get(pos);
}
@Override
public Object next() {
if(pos
也有人说面试看脸,估计是的,这跟相亲一样一样的,你情我愿。
总之面试是一种技术活,又是体力活,并且还是一场心理战。虽然我上面提供的题目是去两年前的面试题,但是有80%的接近腾讯2.3和阿里的p6程师的面试题。对一些小的公司估计你会了笔试题目和一面的技术点,估计你已经被offer了,稍微的二线公司,只要会了一面和二面的部分问题,只要说出理论,不要到细节,那么你已经有了被录取的可能,总之能力和薪水成正比的。但是前提你要准备,至少两个月是合理的。
最后切记,大公司不要学历造假,不然你无法入职的,现在很多公司都在offer前进行背调,这样会影响你以后去该公司的就入职机会,小公司当然你可以玩点技巧,但最重要的还是你必须自我努力,自己有能力才是关键,是金子去哪里都会发光。
如果你没被录上,也不要来喷我,如果你被录上了,那么恭喜你。不管怎样都是命。

================================================
FILE: docs/android/Android-Interview/经验分享/README.md
================================================
## 经验之谈
- [一个程序员的血泪史](一个程序员的血泪史.md)
- [我为什么离开锤子科技?](我为什么离开锤子科技?.md)
- [扫清Android面试障碍](扫清Android面试障碍.md)
- [史上最全 Android 面试资料集合](史上最全 Android 面试资料集合)
- [2016年4月某公司面试题及面试流程](2016年4月某公司面试题及面试流程.md)
- [2017届实习生招聘面经](2017届实习生招聘面经.md)
- [国内一线互联网公司内部面试题库](国内一线互联网公司内部面试题库.md)
- [互联网公司面试经验总结](互联网公司面试经验总结.md)
- [一个五年Android开发者百度、阿里、聚美、映客的面试心经](一个五年Android开发者百度、阿里、聚美、映客的面试心经.md)
- [腾讯公司程序员面试题及答案详解](腾讯公司程序员面试题及答案详解.md)
- [面试心得与总结:BAT、网易、蘑菇街 ](面试心得与总结:BAT、网易、蘑菇街 .md)
- [阿里+百度+CVTE面经合集](阿里+百度+CVTE面经合集.md)
- [技术硬碰硬—阳哥带你玩转上海Android招聘市场](技术硬碰硬—阳哥带你玩转上海Android招聘市场.md)
================================================
FILE: docs/android/Android-Interview/经验分享/一个五年Android开发者百度、阿里、聚美、映客的面试心经.md
================================================
### 花絮
本文为完整版,加了一些彩蛋哦!文末有面试和必备的技能点总结。
> 也许会有人感叹某些人的运气比较好,但是他们不曾知道对方吃过多少苦,受过多少委屈。某些时候就是需要我们用心去发现突破点,然后顺势而上,抓住机遇,那么你将会走向另外一条大道,成就另外一个全新的自我。
先简单说说我最近的面试经历吧。面试的公司很多,其中有让我心血沸腾的经历,也有让我感到失望到无助的经历,我将这些体会都记录下来,细想之后很值得,面了这么多公司,要是最后什么也没有留下来,那就太浪费了。至少对于我来说有些东西在整理总结之后才能得到一个肯定的答案。希望这些能对即将换工作或者打算看看机会的你有一些帮助。
> 下文真的很长,你可以把这篇文章当做看小说一样,快速浏览一下,但是希望你能将文中提到的那些技能掌握。那也就不枉费我花了一两天时间专门整理这些。我的这些经验仅供参考,希望你能做的比我好,同时希望你在以后的面试中能轻松应对。
### 为何离职?
先从我的换工作的动机开始说吧。
公司裁员的时候老大说:『你就留下好好干吧,以后不管公司怎么分股票、期权,肯定少不了你』。我非常信任我的老大,跟着老大一起工作,感觉是一种享受。
但是没想到裁员后,公司内部大动荡,主业务线从客户端A 业务线转移到另外的B 业务线上。我主要负责A客户端的架构,这下可真闲下来了。B 业务线那边的业务量还是很忙的,没时间配合我做一些架构上的事情。于是我每天就看看资料,补充点能量。
呆了几天后,就后悔当初没有拿 N+1 走,有一种被老大忽悠的感觉。 因为公司接下来的操作让我很是不爽,先是晚上打车不能超过30,然后福利大减,瞬间没有工作的心情了。再过了一两周后公司宣布新一轮融资成功,可惜只融到了 2千多万美元(按照预期应会更高),然后接着招新人。
我特么无语了,站在公司的角度是没有任何问题的,可以节省开销,也可以容纳新鲜血液。但是我作为一个老员工,心寒,走的员工都拿到了 N+1,我们这些老员工什么也没有得到,反而福利大减,伤人啊! 现在即使我想走,什么也得不到,一种莫名的恼火涌上心头(只怪本人经历尚浅,看不清一些大的趋势,还是老鸟们聪明,拿钱走人,然后换一个新工作,好不自在啊)。
不过理智分析一些这样确实有好处,可以给自己留很多的时间来选择更好的公司。就如此刻的我一样,在公司悠闲的上着班,骑驴找马,遇到合适的,可以立刻走。其实细想一下,如果我当时拿了 N+1 走了后,可能会迫切的需要一份合适的工作,然后迅速入职。至于新公司怎么样,还真不敢确定。
已经动了想走的心,意味着再也不可能在这里很安分的待下去了。
### 面试分级
于是我决定开始投递简历(世界那么大,我想去外面的世界看看)。这次看机会与往常不同,我决定好好准备一番,然后开始投递简历,主要渠道是 “X钩”,辅助渠道是猎头。
这次看机会我将所有公司分为三类:
1. A类: BAT公司,非常靠谱,各项待遇都是很优厚的
2. B类:一些知名的互联网公司(基本都在C轮以上),基本很靠谱,该有的都少不了
3. C类:就是那些正在招聘的公司,没啥名气,虽然钱多但是事也多。靠不靠谱真还不知道,只能碰运气
### 基础知识不可少
以前我基本都是直接去面试,总以为Android工作好几年了,出去面试基本没啥问题,因此带着那份傲娇的自信 总是碰壁,尤其遇到很多基础性的问题,一时真不知道怎么回答?还有一些问题之前都记得很准确,但是在面试官问的时候,就一个大写的懵逼表情。
在我出去面试之前,我已经把 《大话数据结构》 基本看完了(想想我之前的生活,每天早上七点多起床,然后看几页,洗漱完就去公司)。虽然没怎么记住,但是遇到这些相关问题,还是能很容易回答出来的。因为有了以前的教训,而且这次我也是很认真的准备了好久(可以说蓄谋已久啦,我心里其实很明白互联网公司可能存在很多风险,尤其是没有盈利的公司,唯有技术这东西必须牢牢掌握住,才能立于不败之地),因此我准备把Java基础巩固下,但是手头没啥合适的书籍和资料。
还好民间有很多厉害的开发者,他们不以盈利为目的,只为完成某种需求,开发一款 app,然后发布到应用市场,给需要的人。于是我就找到一个 “Java面试训练” 的App,下载量还可以,就安装到手机上,开启刷题模式,应该刷了10来天吧(都是在上班,下班时间看一点,虽然时间比较零散,但是这样记得最深刻)。在之后的面试中,基本很少遇见一些奇葩的java基础。
> 这里不得不提一件事,那就是从 app 崛起的那一刻起,就有很多的 中间商,一个小作坊的屋子里有很多电脑或者不知名的设备,屋子里慢慢的数据线,犹如蜘蛛网一样连接着很多设备,做着一些神秘的事情。不用我说你们应该也知道他们做着一些很肮脏的事情,我就不细说干什么了,简单举个例子:这群人的老大看中某个市场上某款游戏非常火爆,或者 app 特别的火,于是通过反编译等技术修改这些 app,然后重新打包上线到一些不是很知名的app 渠道或者小型应用时长,还有一些论坛,一旦有用户下载,就会在 app中弹出广告,在游戏中做各种充值操作,甚至在你无意间点到一个按钮就会自动扣除你的话费。这是前几年干的事情,新闻中也纰漏了很多,这里只能说监管不力。
>
> 但是随后各个公司都意识到这样的安全问题于是有了 app加固的技术,无法修改 app,即便修改了,但是也运行不起来,所以一定要注重安全性问题。
### 刚踏入架构师之路的经历
这次我给自己的规划是做一个架构师,但是我深知架构师可不是闹着玩的,必须要有很强的一面,因此我在简历里面写的只是“架构师方向”。我在K公司 做得是架构师方向,因此我觉得有必要朝着这个方向发力,虽然现在不是很厉害,但是坚持一两年后,即使不是非常厉害,但是也距离非常厉害很近(这里使用了《孙子兵法》的一句:“求其上,得其中;求其中,得其下,求其下,必败。” )。
这个想法来源于在K 公司我第一任leader曾经跟我说过的话:『对于新东西,如果你觉得掌握了,但是不应用到项目里面来,是没有什么意义的,时间长了还是会忘记的。』我很庆幸我有一个好老大(我是属于双领导型的,K 公司 A项目的负责人是我的leader,但是我的直接汇报对象是 K 公司的副技术总监,下文就成为老大),用他的话来说就是经常踢着我的屁股走。
当我在网上了解到很多实用的新技术时,跟他随意吐露一句话,他就能非常用心的倾听我的想法,并鼓励我将这些东西带入到项目中来。从那以后我就开始看很多新技术,感觉合适的会引进到我们的项目中。从之后的证明中来看,是非常有价值的。
曾经遇到的情况是这样的:当我刚进入K公司后,打杂一个多月,就被关到了 小黑屋(呜呜呜,好可怕的小黑屋,996的制度)。然后才开始正常的架构师之路,第一步就是统一开发环境,在我来公司后,我发现公司的android同事用的开发工具种类真是繁多啊,神马 Eclipse、IntelliJ IDEA、Android Studio、Windows、Ubuntu、Mac。刚进公司的时候我曾经用鄙夷的眼神看过那些 Eclipse 的童鞋,真是无力吐槽了。于是我给 老大说:『咱们的开发环境最好统一起来,现在各式各样的工具,弄个东西真费劲。』于是老大二话不说,就在群里跟大家吼,都务必切换到 Android Studio(以下简称 AS),由我来监督并执行。于是我拿着鸡毛当令箭,给大伙把地址什么的都找好,发到群里去,让他们自己下载(后期我们就搭建了 ftp服务器将这些常用的工具都放在里面,省的再去下载了)。 翻墙工具我使用 goagent(不怎么稳定),给其他人分享也太费劲了,因此让他们自己搞定。老大自己有一个 VPS,于是给大伙共享后,环境基本就统一了。
> 期间有一个小插曲:
> 一个年龄 比我大的同事在用 Eclipse,在我推广我的 AS 时,他说比较忙,没时间弄。我就急了,因为我刚到公司不久,老大分配给我的任务,推行不下去,这可不行啊,没说几句吵起来了。最后我也知道不能太着急,但是已经吵了,关系肯定不咋样,老大当时开会去了,我知道自己太心虚了,因此主动给老大承认错误,说我和那谁谁吵架了,因为他不用AS。最后在老大的劝说下,这个人就勉强切换到 AS了。
> 其实这个人就是我之后的新Leader,每每想到这里我就全身发冷汗,Leader要虐你,你还能有好活路么?还好这个Leader人比较好,人也比较大气会处事,不怎么跟我计较。我已经对着佛祖忏悔了N多次。
### 第一天面试
我用 “X钩” 开始捡一些不怎么有名的C 类公司投递,很快就收到了很多的 面试邀请。
##### 首次面试——国外输入法
记得当时去的第一家公司是做国外做输入法的,做的还不错。从外面能看见一栋略微有点老的大厦,办公环境很一般。
进去后很巧的是遇见了一个熟人,第一位面试官竟然认识我之前在X游的一个同事,然后我们就聊开了,他也没怎么难为我,就问了我几个很简单的问题,例如:handler的原理,多线程。我按照记忆中的样子说给他听,然后就第一关就轻松过了。
等了一会,另外一个面试官进来了,问了一长串问题,基本就是 Android的相关的基础,然后第二个又轻松过了。
等到第三关的时候,一个年龄稍微大的人进来了,很容易能看出,这个人应是该技术团队的负责人,问了一些工作经历后,然后问了一个最让我印象深刻的问题是:『你了解过Android上的黑科技么?比如Android 5.0 之上有一个辅助功能,如果用户开启后,就能像豌豆荚那样自动安装app,等同于拥有了root权限,但是手机重启后,这个就自动关闭了,有没有办法可以自动打开呢?』据他了解,有很多不知名的小App 都实现了,但是很多大公司都没用。 我想好好一会,说可能这些app 被厂商列入了白名单,因此重启手机后还能自动打开那个辅助功能。我实在想不出如何能实现这样的效果。最后他告诉我,其实他们也是分析了好久,才发现,那些小App, 都是开启了一个进程(或者是service,具体记不清了,有兴趣的童鞋可以试试)来守护,因此能够开启。这么一说,我也瞬间明白了。
但同时我提到这样做会可能会导致耗电量增加啊,对方的一句话把我真雷住了。“那能费多少电。。。” ,我瞬间无语了。但是他们可能因为某些需求必须如此做,因此要实现这样的功能,相对于电量来说应该也能接受,不至于比什么都玩不了的强,体验也确实提升了很多。不用用户每次去开启那个开关,虽然有点风险,但是相对于Android上的风险来说,确实低很多。
等第三轮面试完成后,然后Hr 小妹妹带我到一个很大的会议室,见到一个很年轻的人,听Hr说,这个人应是CEO之类的,反正职称很高。他就问了些职业规划,平时有什么兴趣爱好,以后有什么打算,薪资要多少?我说到公司后可以先接触一些业务层面的东西,然后慢慢再走架构路线,之后可以负责主要核心模块。平时就看看书,参加沙龙活动,没事打打游戏。他也简单回答我一些问题。之后就是让我先走,等通知。
傻傻的我还就这样高兴的走了,因为我总体感觉还是很棒的,毕竟连过4轮哈。从最后的结果中能明白,其实应该是要的薪资太高了。为什么这么说呢?因为一般情况下,最后一轮就是简单看看你这个人怎么样,技术关肯定没问题,否则前三关就 pass 了。可能对方觉得你要的薪资和你的实力不符合,也可能他们想再对比看看,选择一个更合适的人选。
##### 58到家
从上一家公司面过后,我就紧接着去第二家公司 58到家,在大屯路东地铁站附近。到了后刚好12点,电话联系后,他们说班车司机都午休去了,要等到2点才能过去(58到家面试需要从地铁站做班车过去,路程还算能接受的)。然后我就吃了点饭,在附近网吧 撸一局,看时间点差不多了,我就去那块坐车了,差不多走了5分钟做就到了。
北苑路北美国际商务中心,这块有很多公司,什么珍爱网之类的都在那附近。
第一轮面试我的是一个小伙,问了一些基本的Android基础,然后问了一下 android的绘图原理,我说: onMeasure, onLayout, onDraw。 然后他说每一个什么作用? 那个onMeasuer主要做什么的?并举了一个例子:一个自定义的滚动View A里面如何放另外一个滚动的View B?我说把 View B将 onMeasure 里面的高设置成最大,这样就能解决冲突问题。最后他简单说了一些 onMeasure 里面的几个参数,我对此加深了解了。
第一关也就这样过去了,等到第二关的时候看起来一个挺帅气的男人带着一个很显眼的婚戒跟我说一些项目流程上的东西,因为我在K 公司这块跟老大接触的比较多,因此一般问题难不住我,轻松就过了。
等到第三关的时候,问我一些工作经历,然后问问职业发展规划,平时的兴趣爱好,以及你觉得得你和其他人有什么优势。我挺好奇的,为什么最后的这些面试官都要问类似的问题,之后从一个关系还不错的猎头那里了解到,其实他们也就是了解下以后的动向,以及看看这个人的人品。关于优势我是这么说的:我说到公司后可以先接触一些业务层面的东西,然后慢慢再走架构路线,之后可以负责主要核心模块。其实和上面的回答一样,这基本就是所说的套路。他们可以用套路,我们为何不可呢? 嘿嘿,别学我,自己根据实际情况来。
本以为就结束了,没想到他们说 CTO不在,可能还有复试,先让HR大美女跟我谈谈。HR慢条斯理的跟我说了一些待遇什么的,了解了下我的状况,问我要多少。我基本和上一个公司说的一个样。
之后再来复试的时候,这个大美女HR给我了一些建议,说这个CTO是阿里出来的,喜欢会说话的人,想到什么就说什么,别紧张。在这面的时候,我就很放松,该怎么说就怎说,他也问了一些职业发展规划,以及我的经历,基本10来分钟就结束。我只想说大美女 HR 真真是体贴入微,感觉很 Nice, 这轮基本也顺利过了。之后这个HR直接说我被评为T5,但是以后可以继续努力,我也欣然接受了。不管怎么样,反正拿到offer再说,之后慢慢对比。
##### 楚楚街
说起这第三家 楚楚街 我就一肚子火,也不是说第三家不好,只是在去的路上让我备受折磨。从大屯路东 到 知春路,坐地铁应该几十分钟就到了。当时已经快四点了,5点面试,然后我就打算坐车去(不想再挤地铁了,想轻轻松松的过去),特么的为了省那几块钱,我选择拼车,在路上本以为只需要最多一个小时就到,没想到花了我1个半小时(只能感叹北京的车真多,路上堵的不行不行的)。哎,到他们公司的时候都快6点了,还好我提前在电话里和HR说过,他们说6点也是可以的。于是第三个面试就开始了。
首先过来第一位面试官,看样子应该是 Android 技术 leader,开始问了我一些基础的面试题,比如:View 的事件分发机制,View的绘图,ListView 的实现原理(这个应该是几年前面试的时候经常问题,没想到现在也能遇见)。聊了好一会,然后他拿出他们的客户端给我演示了一个页面,说这个界面比较卡顿,让我分析下原因。我看过后,提出了几个有效的检测卡顿的方案,他们的这个界面主要是Listview 的 item 里面包含了一个 viewpager,然后 viewpager 的 item 里面有一个大view, 上面有N 多图片 + 动画效果,因此实现起来很麻烦,最后导致性能卡顿(不得不说产品同学,你的想象力真丰富啊,有没有考虑过研发同学的心情)。然后,他感觉得到了共鸣,因此接下来说话就比较放松了,他说和我年龄差不多,感觉我还是很厉害的(我不禁惶恐不安,我感觉还行,但是应该不是他说的很厉害,可能只是工作时间长了,该积累下来的东西大部分都有了),互留了微信,方便以后的交流(事实是没有啥交流的,只是当你面试通过后,可以有一个拉你入伙的渠道,嘿嘿,不晓得对不)。
第二个进来的面试官长得挺帅气的,手上戴着戒指(之所以提到这个,是因为在我在我的印象中这个最亮眼,很多次在和他交流的过程中,我都比较紧张,我就盯着这块看用来放松,说真的如果看着对方的眼睛,双方可能都不会自在,当然除非你很有自信的时候是可以的)。开始简单问了下工作经历,然后就开始聊技术,第一个就是问我知道不知道 二分法,我当时楞了一下,猛然间反应不过来,最后专门确认问了下是不是 二分查找。然后我说在一个数组里面每次查找的时候从中间点开始对比,大于就右边找,小于就左边找,顺带提了一句这要在一个顺序的数组里面。然后面试官就说,二分查找还得每次先排一次序?我当时说是的,结果就感觉很2,可能没理解清楚面试官表达的是什么或者说我的表达有问题,其实我想说最开始的数组就是一个有序数组,但是面试官可能误解了我的意思,以为每次查到后,都要先排一次序(只能说悲催啊)。
这个问题过了后就再问了我一个问题:『你来说说 Java 的内存管理。』这个问题在一两年前上就栽过跟头,所以当时专门看过相关文章。但是当我回答的时候,由于长时间没怎么看过了,记忆有点松动,大体的说出来了,但是不够准确(回去后就好好补充了下,在之后的面试过程中遇到的概率还是非常大的,尤其在第二面的时候)。然后他问我要多少薪资,我当时说 XX,然后他就问我是不是可以低一些呢?我开始说可以低一点,但是当他问低多少的时候,我心想上面两个公司的 offer 基本感觉到手了,这个可以适当的要高点,能给就来,给不了那就算了(我事后想想才明白,这种2B 的想法绝对不能有,要时刻保持低调,把握住任何一次机会)。最后他说,我得对得起兄弟们(怎么说呢?估计是刚回答的时候不是特别的满意,还有感觉我要的太高了),你这个薪资我没法跟上面谈。然后可想而知,当然肯定没有结果了。
因此奉劝各位,要时刻保持低调,谦虚谨慎,莫要装B,否则肯定遭雷劈,我这就是一个活生生的例子。
### 第二轮B 类公司面试:
面试有很多,说起来可能会长篇大论,以下就总结性的说说,不再说明具体细节,只说我们之后在面试的时候应该注意的地方,以及他们对应聘者的要求。
##### 映客 && 蘑菇街
映客直播在望京soho,很高大上的地方,t1,t2,t3分别对应从低到高的大楼。到公司后,感觉还可以,第一个面我的人是一个技术,基本就问到一些Android 的面试题,没有任何悬念就过了,第二面的时候,感觉那个人还是比较随和的,问了 Java 内存管理的东西,以及一些其他的问题,最后还都聊得挺开心,第三面的时候直接就是 HR谈薪资,很容易就过了。
在望京 soho 还去过 蘑菇街,里面的人技术比较好,我当时过去的时候已经6点了。那个面试官就跟我聊人生理想,提到一些 Android系统原理性的东西,但是感觉回答的不是很好。面试官感觉还是很不错的,然后给我说你以后要多看看例如 handler 原理,windowManager 的东西,并且从源码上去分析,网络上的理论知识还是要结合实践的,真是受教了。这部分我有点弱,虽然知道原理,但是看过源码的东西还是很少的,以后需要注重补充。他说他才是高级,我要应聘的这个 架构师肯定是不行的,问我是否愿意做其他的,我当然表示愿意了,现在要综合提升能力,才能往更高层走。
最后的最后,他很搞笑的跟我说:『我这人真不骗人』。我还纳闷啥意思,最后他说:『今天已经很晚了,第二轮的面试官不在,我明天给你向上反馈下(从之后的一个同事的口中才明白,一般说第二轮的面试官不在,基本就是说你没戏,很委婉的一种说法而已)』。
结束后我看了一下表,我晕,一面就面试我了一个半小时,真特么无语了。不过收获还是很大的,知道自己的不足后,就知道需要补充哪些东西了。
##### 乐视
去了一趟姚家园的乐视,只能说看着挺风光的,但是进去后,特么的真虐人。
电梯分区,还只能在一边的乘坐,很不赶巧的是我去的时间刚好是10点,对于他们公司来说这就是高峰期,电梯根本排不上队,而且乱糟糟的(之前在X游的时候,大家都是排队的,这边没有,可能地方太小了,排不开吧)。电梯上不去了,看来只能跟一些人爬楼梯,一直爬到9层,感觉都喘不过气了。
上去后一个很美的 HR(长腿姐)带我找面试官,然后表示没有会议室,原来的会议室都变成工位了,所以让我先在一个小角落呆着(保洁阿姨的专属位置),过了好一会面试官姗姗来迟,也是一些非常基础性的东西,最主要的是他们提到了推送,怎么实现,已经存活情况说了一些。
第二个面试官也是特么来得晚,等了 N 久,闲的无聊就和保洁阿姨聊天,顺带看看他们的办公环境,只能说真心挤得慌。第二位面试官来了后就看看我的经历,因为第一轮的技术面都过了,因此简单聊了下,就说说他们的发展前景,要做海外产品。听我的兴致勃勃,很开心,然后让我等会。
他们基本都去吃饭了,留下了我在那里干等,然后来了一个HR 的小妹妹,跟我谈薪资以及经历,貌似对我一两年换工作有很大意见,哥就好好给她普及了一番互联网界的基础知识。没想到就在快要搞定的时候,这个小妹妹的老大过来了,然后就看见一个身材超棒,腿很长的漂亮姐姐 HR(长腿姐),坐在我的对面(小妹妹示意我这是她的老大)。瞬间不爽了,都马上谈完了,结果换人再来,真无语了。只能将刚刚的辉煌时刻再来装 B一次,然后谈薪资神马的,给的也不是很多,我要 XX,她说那么多,只能给我薪资范围最低的一个档次。好吧,就接着吧,然后非要我先填写一份背景调查表,如果没有问题后,才给我发 offer,我看到美女拿着那份很大的 纸张,瞬间无语了。
我当时就不怎么开心,然后长腿姐毕竟老练的很问到:『说你是不是有事?』。我说是的,待会1点还有其他地方的面试,然后她说:『那你先回去吧,这个表格发你邮箱,你写好后发给我。』然后长腿姐就送我出去,我又特么的一路爬楼梯下去(9层啊),电梯等了 N 久都下不去。
### 接下来说说几个有意思的公司
##### 新浪
新浪位于理想国际大厦,记得几年前去新浪面试的时候,傻傻的都没准备就去了,结果第一关就挂了。
这次是下午去,外面还飘着毛毛细雨。去了后竟然特么的让我做面试题,哥已经不做面试题很多年。但是想起了之前的经历,还是老老实实写写,据我估计面试的哥们应该会问上面的东西。还好这次做了万全的准备,刷了 N 多面试题,补充了基础的数据结构理论知识。写起来如行云流水,嗖嗖嗖的没几分钟就完了。
第一个面试的哥们看看卷子,没啥意见,然后问最后一道纠错编程题有没有什么问题,我虽然指出了几个错误,但是感觉他还不是特别满意。因此我仔细看了下,原来是一个静态变量引用了 Activity 的上下文,然后指出,他再问了一些偏底层的东西以及性能优化的地方,轻轻松松就过了。
等到第二面的时候,这个人一看就是技术大牛,问了很多 Java 层面的东西,多态,抽象类,多线程,内存管理等等。我感觉回答的不是太好,多态那有点问题,其他的应该还可以。
然后就进入了第三面,第三面的面试官应该是部门负责人,问了工作经历上的事情以及兴趣爱好,之后的发展方向,想做什么层面的。最后很不幸的是在等待第四面的时候,最开始给我题的美眉告诉我时间很晚了,让我先回去,之后等消息。
至少这次来比第一次高级了很多,不至于第一轮就被刷下去。最后分析了下原因,还是薪资要的太高了,尤其是这类公司。
##### 滴滴
滴滴位于西二旗,应该有两个办公地点,其实我一直很想去滴滴,福利待遇很不错。一年前去过一次,很可惜在第一轮的时候,因为在某些适配方面回答的不是太好,因此失去了机会。
这次已经准备很多了,进来后还是在去年的位置上坐下等面试官。说实话感觉滴滴成长的很快,办公环境都变的更漂亮了,哈哈哈。
这个面试官一看就是一个技术宅,开始对我各种炮轰。面试题一个接一个的,在我连续回答十来个题后,看见他还在问,记得在提及到 volatile 的作用的时候,我就开始不爽了,这个东西记得之前在源码里面见过,但是具体的一时说不上来,看着他那样子,埋头在纸上给我出题,我就不怎么配合了。面试了那么多家,就你问了 N 多问题,还有完没完了(其实这也算是抗压的一种面试方式)?我直接说不知道,然后他再问了几个基础性的东西,我想都不想直接说不知道,他貌似已经看出来我已经很不爽了,然后说,那你说说你项目中有没有比较 NB 或者比较有亮点的地方。我的回答直接是:没有。然后他也就不怎么问了,说那先这样。我说:好,就这样,我先走了。 然后潇洒的离开滴滴。
现在想想真特么的很2B,应该低调低调再低调。也可能是那天下午太累了,上午面试了两家,而且已经拿到两家的 offer 了,还都不错,在这特么憋屈,才表现的如此差劲。其实对于问题,知道的话就好好说,不知道的话,可以说说思路和想法,然后说说以后会怎么做,利用迂回包抄策略去应答,准没错。至少给面试官知道你还是可以动脑子的人。
在此我真心后悔当时的冲动,向滴滴那位面试官表示歉意。其实不用那样的,我们只需在面试的时候尽力表现自我就可以,以后切莫带着情绪去看待或者回答问题。
对于人生中的很多问题也是这样的,这次栽倒坑里去了(用我老大的话来说,你不在这里踩坑,总有一天也会在另外一个地方踩到,到时候的损失就不可估计,趁着年轻多多历练自己),总结之后才能更近一步。
##### 百度外卖
百度外卖现在已经不属于百度了,而是单独分出来。
我的一个同事去了百度外卖,我感觉他的能力和我差不多,我就让他推荐了。
去后,上了一个很长的台阶(感觉很庄重的样子),要刷卡才能进去。等了好长时间,面试官把我领到楼下的公共办公桌,就是那种中间空地,周围都是楼层,能看见其他人在楼层间走动。一个年龄见长的面试官,开始感觉挺随和的,然后说跟我聊聊 Android 基础。
第一个问就是:『咱们先来谈谈 Android 的四大组件。』我彻底懵逼了,尼玛,跟我谈四大组件,有意思么? 没想到一直到最后都跟我谈这些,一个接一个的问。说到广播那块,关于一个 app 被杀掉进程后,是否还能收到广播的问题纠结了好久。
然后让我画我之前设计的架构图,我就随便画了画,但是没想到这个看起来很好的面试官让我大跌眼镜,他用鄙夷的笑容告诉我:『你这也太初级了。』我当时心里有几万只草泥马在崩腾,你都30+了,就不知道鼓励新人啊,我都说过我刚做架构的时间不长,而且鄙视我,有本事你也弄一个架构给我看看啊,一点不尊重我们年轻一辈的劳动成果。也许就怪我当时我真就按照他说的草草画几笔吧,没怎么认真对待。我去其他公司面试的时候,虽然这个图不怎么样,但是至少能解决 某些领域的问题,其他面试官都很谦虚。这个百度外卖的面试官,真不是我喜欢的领导,如果以后真让他来带我,那就真完蛋了,很多时候我们都是因为某些人扼杀了我们最初美好的萌芽,而从此失去了创新的意识。
很庆幸的是我在 K 公司的时候,老大一直鼓励我创新,遇到想做的就去做,所以一路下来,虽然很累,但是干的很开心。
所以每当有人问当初为什么选择K 公司的时候,我都会自豪的说:『我的老大很不错,我在那里很很舒服,很开心』。记得在我离开的时候老大给我最后劝告就是:『你要时刻反思自己此刻是不是已经被别人洗脑了。』
### 第三轮:
##### 1.百度
百度位于海淀区上地十街附近,有很多大厦。 我去的是一个做国外工具的部门,去了后,被百度的环境和氛围震惊到了,在一个很大的技术园区,有网易,百度,腾讯公司,对面还有一个大楼正在修建,估计会是另外一个互联网公司的场地。
进入大厦里面后,由于还没来得及吃饭,边吃手里的饼,边浏览下百度的外围办公区。进入百度的大楼后,两个入口都设有刷卡机。
在空闲区等了好一会,然后一个人带我进入大厦。在进去之前,到前台那块面试官输入自己的邮箱账号,然后让我填写其他登记信息,我印象最深的是显示器上边贴着一个纸条,说:请离开的时候在此登记,否则会进入百度的黑名单(意思就这样,具体记不清了)。当时震惊了半天,没想到竟然这个严格。
和面试官进入大楼里面后,只记得的印象是:很整洁,高大。出楼梯后,脚踩着厚厚的地毯,稍微走快点,都感觉很松弛,脚下如踩棉花一样。
为什么有地毯,而不是地板砖————到了夏天很多漂亮的长腿美女穿着高跟鞋踩在地板砖上是一个怎么样的体验呢?噔噔噔……
我在等候区等到第一个面试官,然后我们简单聊了下 Android技术,其中有两点有必要提下:
- 其中一点是:说说 View 的事件分发机制。然后我就说了好多,从 WindowManager->window->Decorview->子 view。最后我说当所有的 view 都不处理事件,事件会最后会传递到 Activity 的 onTouchEvent 上。然后面试官立刻说:『哈?你这是颠覆我的三观啊?』 然后我意识到可能有问题,但是记得 《Android 艺术开发探索》上确实写过到 Activity,但是不是到 onTouchEvent还真没底。面试官很自信的样子,让我颤抖了。但是随着我的坚信,面试官说:『不行,我不能冤枉你是不!』立刻在手边的 MBP 上看了一下,自言自语感叹道:『还真有啊!』 我顿时无语了。
- 另外一点是:问我 Service 上能不能弹出对话框。对于这个问题,我印象最深刻了,记得一年前的时候,在另外一个公司就因为这个问题让我尴尬万分,回去后专门对这块进行补充。我的回答是可以的,但是面试官面带差异的表情告诉我这是不行的,Dialog 必须要依附于 Window 才能显示出来。然后我的解释会让面试官郁闷一会:我说这个是可以弹出的,我之前也专门试过,不过他弹出是有条件的。 条件是:
- 必须在 Manifest 里面注册系统权限
- 在显示 dialog 的时候必须要加一个 flag.
我的理由是:系统对话框可以在低电量的时候弹出对话框,我们同样也可以采用该方式来实现。
面试官语塞,然后给我说 Dialog 是必须要依附在 Window 上,Toast 其实也是一个 Window。我听着这些话,就想起以前看过的一篇文章上也确实是这么说的。估计该面试官回去要好好补充下一些知识了哦。 然后该面试官让我不能用 Arraylist,用数组 写一个队列。这块刚好我在之前项目中特意用了一下,写的时候,主要有三个方法: put(), get(),peek(). 然后考虑下队列的特性,一端进入,一端出去。我当时遇到了盲点,没怎么写完,最后给面试官说了下思路,大体是对的。但是关于选择位置那块没怎么想好。不过这不阻碍我进入第二轮。
第二轮面试的时候,面试官带了很多纸张,我瞬间压力山大,知道不太妙。不出所料,这个面试官,从动画实现原理,到 handler 实现原理,一步步深入各种原理,当我感觉回答的不错的时候,然后他就顺着我的问题继续深入。我只能说我尽力了,有些东西,平时开发的时候真心不注意,但是就因为没有留意,所以就没法继续回答他的问题。
面试官把我带出大厦的那一刻,我心情很不好,很可惜没进入百度,之后应该需要准备很多东西。我要说,我还会再来的,哈哈哈! 最后也归还身上的一个牌子到前台后,省的被拉入到黑名单(好吓人的样子)。
以后有时间多看看原理性的东西,最好整理一个自己的博客,写上自己的一些看法和感悟,这样记得最深刻,即使几年后也不会遗忘,只是看看别人总结的东西,真的就不怎么记得住。
关于博客可以使用 Hexo, 我的博客也是如此,可以整理一些自己的东西与心得。
### 2.阿里
这次去的是一个阿里的高德部门,在望京 Soho 附近的 首开广场。去了以后首先找厕所,你们知道么?厕所竟然从大厦楼层的的一个角转了一大半圈才找到,回来后进入找不到前台了…… 瞬间无语了。问了好一个美女才回到前台,然后接待我的 HR美女貌似等得不太耐烦了(宝宝心里苦,厕所好远,都找不到回来的路了)。在一个小型会议室等待面试官,看了下布置氛围和环境,感觉太棒了,很多东西都体贴入微。
> 回顾上次阿里的悲痛遭遇
> 其实这是我第二次来这边面试了,上一次过来的时候,是刚过完年。提到这里我就苦不堪言,为何如此说呢?当时是2016年2月15日,因为我参加好朋友的婚礼(不得不说,我这个年纪的人都开始结婚了,这次回去有4个好朋友都结婚,可想而知,一场完了以后还有另一场,虽然累,但是值得)推迟了好几天才回北京,在参加同学婚礼的时候接收到阿里高德部门的面试邀请。回到北京的当天是12点多,然后回家,一个关系非常好的朋友说今天她们要宴请公司的人吃饭,因为她们结婚了,让我帮忙弄个 MTV。我想这是朋友的终身大事,因此必须要好好干。
> 我下午4点是阿里高德的面试,因此时间很紧促。我凭借我大学的技能在两个小时内搞定这个 MTV,总体来说还不错,就迅速发给朋友,弄完已经3点了,然后打车立刻去首开广场。
> 高德的面试是4点钟,匆匆赶到后,就等待面试官。面试很不理想,因为什么都没有准备,而且心力憔悴。面试官问的是一些基础的 Java 问题,很可惜我没怎么回答好。于是就深深的浪费了一次机会,之后和朋友提起此事,无比后悔,当时其实是可以和 HR 电话再约一个时间的。
> 这次对我的打击很大很大,因为这是我这么多年第一次面试 BAT 的职位,一上来就受挫,很不是滋味。**我在这里失利后我就各种准备资料,增强自己的能力,面试前必须要刷题,虽然简单,但是不失为一种方法,虽然不一定有用,但是会加深印象,尤其是去 BAT 这些公司,一定要准备好,否则就别浪费机会,这就是我的教训和经验。**
> 为了6月份的这次面试策划了很久。以前对什么可能都不是很上心,但是这个事件深深的刺激我了。
第一个面试官来了后问了一些基本问题,很顺利就进入到第二轮面试。
第二轮也基本是技术面试,问了一些 Android 基础和 Java 基础以及内存管理。
第三轮的面试官应是部门负责人,看起来很好说话的,问了一些经历和基本情况后,问我薪资要多少以及之后的发展方向。我说要 XX,之后希望在架构方面发展,但是也可以从业务开始。貌似这里回答的不怎么好。然后让我留了他的联系方式,我知道很有戏哦。
因为我在进入 K 公司的时候也是这样的,老大感觉我很不错,于是留了微信后,我基本就顺利入职。
回去后的一两天还是很焦虑的,但是我知道大公司都是有流程的,因此我告诉自己不要焦急。过了一两天后他主动加我微信,然后问了些基本情况后,就说他要做最后的总结,让我等着,最迟一周后就有消息。我感觉希望超大的,开心了好久,本以为就可以这样过去。但是一周时间过去了,没人通知我,我开始焦急了,于是我开始主动和他说话,反思自己是否有什么地方做的不好。
经过很多面试后我总结出了结论就是要薪资太高了,于是我在微信里面给他说,只要能过去,薪资低点也是可以的。但是问了他好几次,他都没有回话,看着微信消息记录,都是我发给他,而他没有回复,已经过去好多天了,我知道没希望了,他说不管怎么样都会给我回复的,但是我真绝望了。
就像相亲一样,遇到一个不错的美女,开始都一起聊得很不错,她开始加你好友,并且和你说看好你,不管能不能做女朋友,她之后一定会回复,但是苦苦等待一段时间后,不管你怎么给她说话,但是她就是不理你。可能她真的忙,但是也不可能连续一两天都这么忙吧。于是你知道没结果,因为无言等同于没有希望。为了避免一些幻想的存在,你会将她删除掉,不想留下任何关于他的信息。
同样我也是把这个阿里高德的老大的联系方式删掉,微信也删掉。在我失去希望的时候,过了几天看见他要主动加我,但是我想可能只是安慰的话语,最多告诉我,我不适合他们的职位,因此我为了避免尴尬,直接删除那个加我好友的请求(如果说真的合适的话,应该会很重视你的,不可能好几天都回复,怎么有一种备胎的感觉,呜呜呜,我不想被发好人卡,宁愿做高傲的兔子,也不想做纸老虎,虽然尽管只是纸老虎,但是也会拥有属于它的一片森林)。
于是阿里的这次机会就失去了。
总结后的结论就是:去大公司要的薪资不要太高,否则对方只能感谢你的到来,因为比你优秀的人太多了。
### 聚美优品
聚美优品 位于东四十条地铁站附近。路过一个竹亭子后,进入大厦里面需要用身份证在前台那块登记后给我一个纸条,上面写着我的身份证信息,然后在门禁卡附近刷二维码进入(真担心个人信息泄露哦,当然一般情况下没人会关注你是谁的,千万别干坏事哦,会被查出来的,哈哈哈)。
推荐我去聚美优品的同事接我上去后,带我到前台填写基本信息。我只写了最基本的信息,然后她说,你就写这么点啊。我说,其实这些信息够用了,写那么多没用,还会暴露你的个人信息。面试成功后,如果有需要可以写详细些,但是一般去面试最好别写身份证信息。工作经历基本也只是最近两个,之前的就不用写了,写那么多没什么用,简历中都会有的。
记得刚工作那会,傻傻的全写了,真耽误了不少时间。过了一会,她把我交给 漂亮的HR 温柔姐,然后就先忙去了。温柔姐告诉我一般情况下有两轮基本就过了,先让架构师老大直接面我,让我先等候。
过了一会温柔姐不好意思的跟我说架构老大先让一个技术面我,问我是否有意见,我当然没意见了,这是很标准的面试流程(如果你有意见,建议还是别说太多的话,基本都这样的,要淡定)。
一面技术给我一种很成熟的感觉,开始问了我一些基础技术问题,外加 Java 内存管理知识。后给我出了一道算法题,说有一个数组最多存储6个数,如果有普通用户的话,存储四个 vip的客户,另外两个是普通用户(留出一定的空间给普通用户),让考虑全面点(一般都是结合实际场景,让你写出一个算法,要具备的能力就是抽象,处理问题的思路与细节,还有最基本的编码功底)。
然后我就考虑各种情况,第一种是非空情况,然后下面就是几个大的 if else, 至少四个条件,基本涵盖了全部情况,然后每个条件里面写上对应的存储数据的过程。由于我的四个大条件都把距离占的差不多了,在写里面细节的时候,用中文描述。过了一会他回来后,看了下说:『你这个还有中文啊!』 我尴尬的笑着说:『我先写条件的,最后发现没有空位了,只能用文字代替了,你看我正在另外一个纸上写全部的完整算法。』指了指纸上刚写一小半的代码。他也会心一笑,并指出算法上应该改进的地方,基本 ok 啦。
然后等第二轮的面试,看起来更成熟,但是说话有一种很亲近的感觉。问了基本情况,然后拿出他们的 app 让我看看首页的实现效果,说说怎么实现的。对于这种情况,基本就是考察你的抽象能力,以及分析问题的能力。我先说出使用 ListView 的 header,footview,然后使用 ListView 的 type 来实现。然后简单说了一些性能优化的东西,该面试官提出我的做法可能会存在性能瓶颈。其实他说出这块是在指导我说这块会有问题,我当然明白他的意思,于是说这块采用 recyclerview + fresco 来实现,可以有效的改善问题(其实提到这些,就说明你看过很多新技术了,有时间最好还是要自己练练这些东西,毕竟孰能生巧)。
他也没深究,基本就感觉不错,开始谈了谈他们的目前状况,以及即将遇到的问题。他在只言片语中都把我当做内部人看,我也心里感觉很舒服。最后告诉我如果我愿意,他就向上报备了,意思是可以继续下一轮。当时他问到我的薪资的时候,因为之前已经说了 N 多次,有的成功,有的感觉很亏,于是这次我并没有说,只是笑笑,而对方说:『那就按照年薪算吧,你打算要多少呢?』我当时什么也没有多想,然后就说:『我希望在我现有的薪资基础上,能上涨15% - 20%。』他经过在手机上一阵比划后,告诉我可以达到我的预期效果。整个过程感觉很愉悦。
因为面过了一些,并有offer,但是还是想多看看,结果把自己搞的疲惫不堪。但是最后的最后,温柔姐给我打电话说面试通过。
### 最终结果
最终我辞职后在家休息几天,没事的时候去咖啡馆看看书,上上网,好好过几天轻松的日子,然后再说定去哪里工作。
### 总结:面试和必备的技能
这里只简单列举一些东西,可能不是特别全,但是却特别适用,也不一定按照下面的流程,有可能是穿插的,也有可能都有,根据公司的规模以及面试官的心情而定(哈哈哈 ,你们就自求多福吧)。建议大家还是要将下面的东西全部掌握,没事写写代码,练练手,在项目中能用到的地方一定要用,有可能会遇到很多坑,一定要自己想办法填坑,之后回忆起这段经历,肯定可以敢理直气壮的跟别人讨论。如果你说的头头是道,那么对方会先输一层,然后在心里对你佩服。
1. 一般情况下第一轮都是基础面试,需要扎实的基础
- 最常用的Android 基础知识
- Java 基础知识
- 了解一些 常用东西的原理,例如:handler, thread 等
- 项目中的技术点
2. 第二轮的时候需要了解更深层次的东西
- Android 事件分发机制原理
- Android 绘图机制原理
- WindowManager 的相关知识
- 进程间传输方式
- Java 内存管理机制
- 一些常用的 list,map 原理,以及子类之间的差别
3. 能进入第三轮基本没什么问题,但是要注意以下问题
- 该轮一般是 老大或者部门负责人,问的问题一般都看 深度与广度
- 当问及薪水的时候,要说一个合适的,小公司随意,大公司一定要慎重,当心里没底的时候,可以告诉对方,让对方给一个合理的薪资。一般都是在原工资基础之上增长,听猎头说一般涨幅都在15%-30%,超 NB 的可以要30%及以上,如果感觉自己还不错的,挺厉害的,建议最高20%,一般人就定在15% 左右最靠谱。公司内部一般有一套机制,根据公司情况而定。
- 我们的面试原则就是拿到合理薪资,得到 offer
- 个人发展情况,这个问题很难回答,如果和公司方向不符合,极有可能和公司无缘。建议多试探性的问问公司缺少什么,你能否给予公司对应的东西。当然对于有自我追求的人,那可以放心大胆的提。我的方向就是架构师,哈哈哈,挺极端的,别学我哦。我感觉选择都是双向的,因此我知道自己需要的是什么。
- 你最擅长什么UI 还是其他什么?这个问题更不好回答。你要说你擅长 UI,是不是意味着你其他能力就不行?虽然我不知道面试官的用意,但是我能感觉到,这个问题不是那么好回答,我会回答说自己都行,来什么业务接什么需求。可能回答不太好,总之和公司的职位吻合就行,这样总不至于出错吧。
如果你有面试的疑问或者困惑,可以加我的微信公众账号:[mianshishuo](http://7xlcno.com1.z0.glb.clouddn.com/weixingdky005_mianshishuo.jpg), 可以扫描下方二维码,一起来吐槽面试中的感受。我将不定期分享最新的 Android 面试题与面试经验。也可以将你们的面试经验与问题发给我一同讨论,非常感谢。
================================================
FILE: docs/android/Android-Interview/经验分享/一个程序员的血泪史.md
================================================
我的第一份工作,是某某电力.
求职过程很有意思:有一天辅导员有家国企严招聘,说都去看看;结果去了发现只有几个人在,一位大姐说:人都到齐了吗?那就开始吧.我介绍一下我们公司,你们愿意来的话,就填个表. 完全没有面试….就算是有了第一份工作.
毕业后就去报到了,结果报到时间还没到…玩了几个月才又去.简单地培训了两个星期,做了一个安全生产知识的考试,就给所有人买了火车票,送到了四川一个偏僻的小山沟里.那里有一家火力发电场正在修建.
初到这里,什么也没有.有一片正在修建的房子,刚盖好框架,封了顶,地面都还没有平整,这就是我们的宿舍.每人发了几百块钱,说,开车带你们去镇上买点生活用品吧(工地上有不少的大小货车).然后生活就这样开始了.
规定的上班时间是8点到5点;天气非常热,经常只能在屋子里猫着.还好我们不需要天天下工地.有一段时间比较无聊,每天打游戏,但是没有网,只能打单机版的大菠萝.有的日子也经常需要加班赶进度,因为进入梅雨季度了施工就会受影响;但是我们这些质检岗位是帮不上忙的,我们的日子,是负责编质检报表,厚厚的报告拿过来手写上质检记录,反正师傅让这么填的,天知道有没有真正的检查过….
工地上,一般是不允许夫妻同行的,整个工地上几乎全是一水的大老爷们.下了班,业余生活就基本可以用吃喝嫖赌来概括.当然,我们刚毕业的学生,也就只能参于一下吃,每天轮流着去小镇上少得可怜的几家餐馆去吃.
老师傅们,除了吃喝,还赌.有时候通霄地打麻将.旷工就旷工呗,反正也不会怎么样.辛苦钱,还算可观,加上各种补贴,安全奖金啊,其实不算少.那两个月七七八八加起来是3500一个月,但是在这山里,基本没地儿花.当然,后来因为每天轮流请客大吃大喝,花光了.
当然,还有嫖.谁谁谁去嫖了,基本不是新闻.没办法,没别的娱乐….
到这里一个星期的时候,有天在外面吃完晚饭,有位师傅说,你们要不要我带你们去找个小姐?几个刚毕业的孩子吓尿了.
打那后,我就决定要辞职.我觉得要不了几年,我就会成为这样一个人.
于是,在工地上又呆了两个月,辞职了.
在家玩了一段时间,春节过后,我带着仅剩的1000块钱来到了这个有着几千万人的大城市.(我打肿脸充胖子,给了家里一点钱…)
不再是电焊质检工程师,我的新职业是PHP工程师,月薪2500.买了火车票,还剩下700块.住在一个380一个月的地下室.然后中午在公司吃,早晚都吃那种北京的一块钱的大饼,当时感叹,北方的大饼真大啊….
来了没多久,老板说要招人,一直没招着.我想起有一个兄弟,因为没有拿到毕业证,还呆在学校旁边,没有正经找工作,好像呆在一个什么地方打杂,一个月500.我说,把他招过来吧.然后就是哥俩一起住地下室.
公司很小,偶尔会晚一点发工资.有一天,有个人离职,走的时候对老板哭着说,我500块的时候就跟着你干 ,干了3年,没要求地啥,你给我什么? 那之后不久,我也换了一家公司.
这次换了之后,看起来公司会靠谱一点,因为有某知名网站的CTO坐阵.但是那时候显示鉴别水平太低了…这段时间里其实一直被教育,你的努力,老板看得见.但是事实是,老板看见了,就只会开心一下而已,又能怎么样呢….我从来没想过为自己争取点什么.
新的公司,老板同时还有房地产业务和广告公司业务.租的地方很宽敞的样子,搞了个神秘气派的会议室,三天两头拉着据说是政府高官来开会,老板也总是一幅指点江山的样子,说是在通州弄了片地搞开发,但从没见过有啥进展.广告公司呢,好奇葩,是个清华美女负责的,是老板的…小三.
广告公司在18楼,有几个设计师,我认识一个,高高瘦瘦的男孩,我悄悄打听了一下,他的月薪是….1400!
后来的离开也有戏剧性,有一天快下班时候,来了几个警察,有几个律师来了.原来是有老板们的分歧,都说公司是自己的,要我把服务器代码复制出来交出来,要是交给另一方的话,要告我侵占公司财产….
得,我写个代码还要写进监狱啊,那我辞职还不好吗…..
我又失业了.
这次,我一定要找个更靠谱的人介绍个工作.
所以,我找了一个我认识的某知名博客网站的php开发经理介绍,当时他刚刚要离开,去南京创办一家在线旅游网站(没几年就美股上市了)
大牛介绍的工作,从名字上绝对靠谱,是某某电视台的网络中心.在农村小镇,你要说你是这电视台来的啊,镇长马上得来请你吃饭.
面试过程也简单:你是介绍过来的呀,那不用面了.你期望月薪多少?8000?好吧,没问题,现在还在职吗?不在职?那你下周一就来吧.
入职是在月底了,没过几天,有个妹子拿了个表过来登记身份证号,然后两天后就发了5000块钱现金.我心想,这国家单位就是不一样啊….我才上了几天班,就发钱了… 没几个月我就知道,这是劳务费.我们根本不属于编制人员.编制,是在这个单位的生命线.有编制,你就不用干活,有活让外包做就行了.几乎每周都有各种公司来讲方案,而编制类的老大们就只是做决定,买哪个系统. 这里做点事很难.会议很多,效率很低,很讲究级别.有个会议,一个总监没空去,叫一个下属去代开.进门就被轰了出来:你什么级别啊,这是你能来的会吗?
当时是离奥运还有一年四个月,我们的工作就是上线一个相关的站点,要在离奥运一年前上线.还好时间快到的时候,上线了.
接下来的几个月,一直没有发工资,连劳动合同也没有,当然,这之前两家也都没有.期间问了几次,但没答复.有次问急了,就安排去一个考试,还是北京人事局组织的,我没考不过,因为考的是政治和英语.没有英语专八和考研辅导是没指望的.
我和那个登记身份证的妹子熟了起来.我问她,你发工资了吗?她说,这几个月还没有呢,我算实习.我大学在比利时上的,这边不认.所以我只能在这实习,好把档案挂这.我说,那一个月多少钱?200. 我目瞪口呆.依你开的车,200就够养一天吧? 妹子说,我来上班是为了有点事情做,也不是为了钱.
好吧,你家住王府井,你开A6上班,我可不是,我老家房子都摇摇欲坠随时要塌了,我上班做事就是为了钱.
我打电话给当时负责的大部分的老大,我诚恳地希望能结一部分钱.他在电话里说,你不是在找人打听吗?听说你不是要走吗?你牛B你就走啊? 我录了音,但后几年之后觉得已经没什么必要了.丑陋的人到处有,犯不着揭开那些不痛快的记忆.
我决定去申请劳动仲裁. 我问那位大哥,你介绍我过去,我去申请劳动仲裁,会对你有什么不好的影响吗? 他说,你放心去吧,干活拿钱,天经地义.
其实,我也没啥选择,人总得吃饭.要不然我怎么办,兜里没钱了,难道滚回老家去种地吗?
2007年,我在劳动局大厅犹豫了5分钟,在想,要不要问问,我可不可以满足那个”农民工免仲裁费”的条件呢?
一个月后,开庭. 我见识了各种无赖的狡辩.比如说,现在说,他是实习生,实习生没有工资(已经毕业的就不再是实习生了),现在已经过了60天的诉讼时限了(完幸书记官看了一下日历,我提交材料的时候刚好是第60天).
我已经忘了是当庭宣布了结果还是后来通知了. 只记得,是电视台的法务通知我去找财务领钱.去的时候各种忐忑,心想平时找各位头们可是千辛万苦, 这次能顺利吗?
还好,财务已经等在那里,数完钱,签字走人. 回来后,法务打电话给我,很生气,不想见你. 我心里想,我已经不生气了,我再也不想和贵台有任何交集.
这次之后,我终于换到了一家靠谱的外企,虽然没几年他也从中国互联网中出局了.
记我那些可怕的职业经历.
原文链接:http://blogread.cn/it/article/7712?f=wb
================================================
FILE: docs/android/Android-Interview/经验分享/互联网公司面试经验总结.md
================================================
这是一位攻城狮面试了近十家互联网公司总结下来的经验之谈:
我现在主要的方向是Java服务端开发,把遇到的问题和大家分享一下,也谈谈关于技术人员如何有方向的提高自己,做到有的放矢。
面试遇到的问题
## 1. 百度
百度最近真是炙手可热,贴吧事件刚结束,医疗竞价排名又闹得沸沸扬扬,一些论坛上连带程序员都开始招黑了,友谊的小船可是说翻就翻。
说回面试,百度面了两次,分别是百度糯米和金融事业部,百度目前只有这两个部门的招聘岗位和我比较匹配。面试都在西二旗的百度新总部,园区还在施工,离地铁也比较远,需要打车过去。
面试官自带电脑,整个面试过程都在记录,首先详细询问了最近一份工作项目的架构和工作内容,面试主要围绕工作中用到的组件和中间件技术来扩展,考察掌握程度。
> MySQL InnoDB存储的文件结构
>
> 索引树是如何维护的?
>
> 数据库自增主键可能的问题
>
> Redis的并发竞争问题如何解决了解Redis事务的CAS操作吗
>
> **分析线程池的实现原理和线程的调度过程**
>
> 动态代理的几种方式
>
> Spring AOP与IOC的实现
>
> 为什么CGlib方式可以对接口实现代理?
>
> RMI与代理模式
>
> Dubbo的底层实现原理和机制
>
> 描述一个服务从发布到被消费的详细过程
>
> **算法方面考察了一个简单的数组就地去重问题,用丢弃数组尾部元素的方式实现**
百度金融的面试安排在了周六,最近应该在各种扩张,各个招聘网站随处可见招聘启事。一面面试官很赞,态度认真,有些问题没有思路会给你提示,交流的不错,二面被告知缺少金融支付背景,不过作为一名工作不到两年的新人,我觉得被Pass主要原因应该是工作经验比较少,教育背景也不太亮眼。
> **分布式系统怎么做服务治理**
>
> 接口的幂等性的概念
>
> Maven出现版本冲突如何解决
>
> JVM垃圾回收机制,何时触发MinorGC等操作
>
> 新生代和老生代的内存回收策略
>
> Eden和Survivor的比例分配等
>
> Synchronized和Lock的区别
两次面试,感觉百度的流程比较严格,面试官挺不错的,简单可信赖,虽然工作中一般都用谷歌。
**这是一个段子:**
有次面百度,我提到了一个比赛,面试官很感兴趣,想搜一下,于是先用百度搜了一下关键字,首屏没有找到,面试官面不改色,熟练的打开了谷歌输入关键字,发现第一个就是官方网站。

## 2. 阿里巴巴
在内推网上收到了阿里菜鸟和阿里云安全部门的面试,后来参加了阿里云的面试。阿里的面试安排的很快,这次止步二面,两轮面试都是电面。听朋友说阿里五轮面试,四轮技术一轮HR,技术面试是部门的几个同事交叉面试,也有了了解。
一面总体上还是围绕项目架构、Java基础、JVM、并发编程、数据库操作、中间件技术和Dubbo服务治理框架等展开,
可能因为是云安全部门,有一半时间在考察JVM,还提问了一些编译优化的知识,一面结束后很快安排了二面,相对一面,二面的问题更深入,问题比较刨根问底,更加注重对一些技术细节的理解和把握。
比如数据库操作,面试官会详细的问你数据库插入和删除一条数据的过程在底层是如何执行的,项目里配置了读写分离,也会比较深入的就实现方法和底层逻辑展开讨论。
> JVM内存分代
>
> Java 8的内存分代改进
>
> 深入分析了Classloader,双亲委派机制
>
> JVM的编译优化
>
> 对Java内存模型的理解,以及其在并发中的应用
>
> 指令重排序,内存栅栏等
>
> HashMap的并发问题
>
> 了解LinkedHashMap的应用吗
>
> 在工作中遇到过哪些设计模式,是如何应用的
阿里的岗位大都在杭州,面试结束特意关注了一下那边的生活成本,目前杭州房子均价不到两万,相比浙江一些县市的房价都破两万,杭州的房价应该比较正常。如果拿到阿里和网易等几家互联网公司的高薪,买房和生活的确比北京要轻松很多,果断决定再沉淀一段时间,两年后P7再战。

## 3. 优酷土豆
优酷的面试都是二对一,每轮面试两个面试官,一面比较顺利,主要是Java基础,Spring原理,Java NIO,并发和集合框架等,可能是因为视频网站,优酷考察网络原理的知识多,比如TCP/IP协议、长连接与短连接等。
一面提到了自己可能会在下半年学习大数据与机器学习相关的知识,二面就在这上面栽了跟头,问了很多海量数据的问题。
> TCP/IP协议
>
> 长连接与短连接
>
> mapreduce过程
>
> 多路归并的时间复杂度
>
> 海量url去重类问题
>
> Java NIO使用
>
> 倒排索引的原理
>
> 对分词技术的了解
面试中给了一个具体场景,考察对MapReduce过程的理解,比如Map阶段和Reduce阶段是如何进行的等,Reduce阶段面试官希望分析给出一个多路归并的时间复杂度,用外排序的知识简单分析了一下,回答的不太好。回来以后搜索了胜者树和败者树的优化,发现这里面的内容还挺多,深刻体会到有些知识点如果平时掌握的不够全面深刻,很难信手拈来。

## 4. 搜狐新闻
搜狐最近应该是没有招聘计划,面试等待时间比较长。做了笔试题,一面是个和我年纪相仿的面试官,针对笔试和简历提问了一些基础问题,聊得挺投机,二面技术经理就比较偏架构和中间件的应用,提问了项目,主要考察了服务治理和消息队列等中间件使用的问题:
> 消息中间件如何解决消息丢失问题
>
> Dubbo的服务请求失败怎么处理
>
> 重连机制会不会造成错误
>
> 对分布式事务的理解
>
> 深入分析几个设计模式
面试最后提问了一个不定长字符串转为定长字符串的问题,刚刚面过优酷,这个简单的问题被我想复杂了,没有Get到面试官的点,考虑了唯一性、性能等,扯了一大堆。也提醒一下大家,面试过程中要保持清醒,不要有思维定式,除非是底层研发岗位,社招对算法的考察不会特别难,用正常的思路去解决就可以。

## 5. 58赶集
58总部在798附近,全天有班车可以过去。总体上,感觉面试官的问题非常接地气,三轮技术面,大部分是实际场景的算法和系统设计类问题:
> HTTP请求的报文格式Spring的事务实现原理
>
> 实际场景问题,大量用户数据如何在内存中排序和去重
>
> 缓存机器增删如何对系统影响最小,一致性哈希的实现
>
> Redis持久化的几种方式
>
> Redis的缓存失效策略
>
> 实际场景问题解决,典型的TOP K问题
>
> 实际场景问题,海量登录日志如何排序和处理SQL操作,主要是索引和聚合函数的应用
三面面试官提问了一些优点和缺点的自我评价类问题,简单交流以后对我给出了一些中肯的建议,非常感谢。

## 6. 国美在线
国美在线面试最开始是部门经理沟通,在知道我毕业不满两年以后,重新去做了一份笔试题,主要考察Java基础,数据库,设计模式以及数据结构,要求写出B-Tree的节点结构,算法题目是一道等概率抽奖的题目,用蓄水池抽样算法解决了。
> SQL语句编写
>
> MySQL的几种优化
>
> Spring行级锁
>
> Spring衍生的相关其他组件整理
>
> RMI的几种协议和实现框架
>
> BTree相关的操作
>
> 数据库锁表的相关处理
>
> 考察跳台阶问题
和面试官的交流比较轻松,面试官提示我要加强数据库操作的掌握,另外面试过程中询问了一些工作中用到框架和组件的版本等细节问题,平时没太关注,
后来思考了一下,对开源组件的应用,版本的管理很重要,不注意可能会发生一些诡异的问题。
## 7. 去哪儿网,口袋购物等公司
除了上面的公司,还参加过去哪儿网、口袋购物、链家等几家公司的面试。去哪儿网中规中矩,口袋购物的工作环境非常不错。链家网最近有新浪的鸟哥加入任技术总监,在IT圈子里挺火,面试了链家旗下的两个租房部门,技术氛围不错。
几家公司的模式和问题都类似,注重对基础和编程能力的考察,以及对分布式系统设计和架构的理解。值得一提的是一家创业公司的面试,过程十分简单粗暴。没有自我介绍,面试官看完简历就在白板上提了一个多线程调度问题,递过来MAC就开始敲代码。
写完以后我表示这题目意义不大,问了Redis,要求十五分钟实现一个LRUCache,再次现场写代码。写到一半面试官看没问题就打断了,问对公司有什么想了解的,等了一会让我回去了,就这么被Pass,创业公司效率果然高。

面试中要保持清醒,比如被问到十万个ip段查找这个问题,首先是一个典型的查找问题,明确了这个,就可以针对性的选择相关的算法实现,如二分查找、二叉查找树等。推荐画图表达的方式,做过的项目架构,各种框架和中间件的设计实现,通过画图的方式都可以很好的阐述,可以随身带着纸和笔,面试本来就是一次很好的学习过程,一些问题也可以记录下来。
一般来说,面试过程类似一个寻路算法,交流过程中如果提到了面试官感兴趣的某一点,就会就这个点展开,然后一直提出问题到你不能回答为止,或者你特别牛在这个领域直接秒杀面试官,这样一条路线走通,再换下一条路线。
攻城狮如何用正确的姿势提高技术水平

一般来说,主流互联网公司都在用的就是业内比较成熟和流行的技术,最简单的方式就是看招聘要求,虽然大部分公司的Job Description都有抄袭的嫌疑,但是多比较几个招聘,还是可以了解主流互联网公司的技术方向。下面是从从拉勾上找的几个招聘要求:
**百度核心业务部门:**

**阿里巴巴:**

**美团酒店事业部:**

既然是社招,工作经验是必须的,三年以上最好,上面的几个JD里也体现了。然后是技术方面,结合自己的体会,总结下面几点:
## 基础知识必须要扎实
语言基础,计算机基础,算法和基本的Linux运维等
针对Java语言,需要对集合类,并发包,IO/NIO,JVM,内存模型,泛型,异常,反射等都有比较深入的了解,最好是学习过部分源码。这些知识点都是相通的,在面试中也可以体现。
从源码的角度,可以深入到哈希表的实现,拉链法以外的哈希碰撞解决方法,如何平衡内部数组保证哈希表的性能不会下降等;
从线程安全的角度,可以扩展到HashTable、ConcurrentHashMap等其他的数据结构,可以比较两种不同的加锁方式,RetreenLock的实现和应用,继续深入可以考察Java内存模型,Volitale原语,内存栅栏等;横向扩展可以考察有序的Map结构如TreeMap、LinkedHashMap,继而考察红黑树,LRU缓存,HashMap的排序等知识。
Java方向的中高级职位,会比较重视对虚拟机的掌握,诸如类加载机制,内存模型等,这些在程序的优化和并发编程中都非常重要。
算法方面,基本的排序和查找算法,对递归,分治等思想的掌握。如果算法基础不太好,推荐《编程珠玑》等,每一章都很经典。
计算机基础方面,比如TCP/IP协议和操作系统的知识也是必备的,这些都是大学计算机专业的基础课,也是做开发基本的素养。
## 系统设计能力
设计模式,造轮子的能力,各种缓存和数据库应用,缓存,中间件技术,高并发和高可用的分布式系统设计等。
大型互联网公司每天要面对海量的请求,都会考察分布式系统的架构和设计,如何构建高并发高可用的系统。另外因为用户基数比较大,一个细微的优化可能会给带来很大的收益,所以对一些技术栈的掌握要求都比较深入。比如对MySQL数据库,需要知道相关的配置和优化,业务上来以后如何分库分表,如何合理的配置缓存,一个经验丰富的服务端开发人员,也应该是一个称职的DBA。
对常用的开发组件,比如中间件,RPC框架等都要有一定的了解,虽然工作中可能用不到我们自己造轮子,但是掌握原理才会得心应手。这部分知识主要靠工作积累,推荐《大型网站技术架构与Java中间件实践》,还有曾贤杰的《大型网站系统架构与实践》,里面对大型网站的演变,服务治理和中间件的使用做了很详细的阐述。
作为业务开发人员,有必要了解压力测试相关的指标,比如QPS,用户平均等待时间等,可以帮助你更好的了解自己的系统。
## 软性指标
快速学习,良好的沟通能力,以及对相关行业的了解。
公司招聘会比较看重一个人的学习能力,是不是值得培养,很多公司校招的毕业生薪资会倒挂工作多年的老员工,也是这样。像沟通习惯,逻辑分析能力,这些都属于软实力,短时间内很难提高,需要长期的养成和持续不断的投入。好多公司还会看重所在行业,虽然是做业务,但是对产品和行业的了解也很重要。比如互联网金融类公司的岗位,如果有过支付和银行相关的系统开发经验肯定会有加分,这点和每个人的长期规划有关。
有了方向,接下来就是如何提高,说一些自己的感想。
很多时候,除非你的工作内容就是要应对高并发,海量用户等场景,否则通过加班或者说重复性的工作,其实很难有提高。技术人员最直接的提高方式,还是需要跳出来,在工作以外审视自己,比如广泛的阅读技术书籍,多去论坛和各路牛人交流,了解主流互联网公司的技术栈,有针对性的去学习和了解。同时也可以适当的了解一些产品或者设计的知识,以点带面,复合人才肯定更受欢迎,对待面试,要像和妹子约会一样,表现自己平常的一面就可以了。
================================================
FILE: docs/android/Android-Interview/经验分享/互联网巨头BAT3内部员工的真实状况.md
================================================
【导读】在中国互联网竞争加剧,让巨头们对用户的竞争很激烈,对人才的竞争更激烈。中国4家市值超过100亿美元的互联网巨头公司BAT3,对待员工的方式,以及组织架构都各有不同,因此造成了各自风格鲜明的企业文化,究竟巨头内部员工生活工作状态如何,是什么原因造成这种情况的,值得我们实地考察一番。本文整理自“每日CEO说”。

阿里巴巴员工:我感觉我是在为自己做事,不是为公司
王小炜(虾米网创始人,原阿里巴巴员工):阿里巴巴有强大的HR体系,我目前我在国内看到效率最高的体系。整个HR体系几乎每一件具体的事情都有办法和具体落实的流程,具体到战略怎么制订,目标怎么样分解,考核的指标定的是不是准确等,这都是HR的事情。而对于人的方面所有的业务主管,基本上业绩只占到我们的50%,有30%是团队,还有20%是文化。
阿里巴巴是所有互联网巨头中最喜欢给员工灌输价值观、营造企业文化的公司。“江湖”传言阿里的人,工程师都被洗脑,很多猎头也表示阿里的人最难挖。马云一直强调要有自己的DNA,同时也强调value的重要性,同时有一句话让人关注,一万人的believe就是信仰。他能把自己的梦想和价值观源源不断地灌输给你,用其“扭曲磁场”使得你产生认同并与之共同努力。对于不懂技术的领导者而言,他不会跟你坐下来讨论技术问题或者产品问题,他更像是一种精神存在,一盏指明灯,告诉你要往哪里走。这样的文化收获了什么?某位阿里员工表示:“阿里巴巴也没有宗教式的崇拜,我们崇拜的是自己,崇拜自己的事业。”阿里员工难挖,很重要的一点是因为他们认为在阿里是在为自己做事情,当然,阿里巴巴工资高也是不争的事实。
百度员工:推崇狼性,公司内部压力太大
3B大战之后,百度在内部反思中提出要推广狼性文化,要求员工要以结果导向。百度一些老员工说,“在百度比较怕的是新人,老员工和新员工永远在一个起跑线上在竞争,论功劳,不论苦劳,优秀人才可以不拘一格地被提拔上去。对于新人而言,这是一个很好的竞争环境;然而对于老员工而言,来自内部的竞争压力未免也太大了。”
对于竞争激烈的互联网公司而言,提倡狼性文化完全无可厚非,但是这种狼性应该体现在对问题的处理、竞争对手争夺中,要干劲求结果;对内部也狼,就很不人性了。百度的狼性文化让所有员工都保持了一颗时刻学习的心,也把很多老员工推向了竞争对手的怀里。
360员工:进公司容易出去难
某位360在职员工表示,在360:“做错了不会被开掉,甚至由于管理机制的松散也不会被记录在案,但一顿痛骂是在所难免的。这种暴力的风格像病毒一样自上而下传下来,每一级的Leader都被深深传染,大家都充满戾气,对下属犯的哪怕很小的错误都很容易大发雷霆、说脏话、拍桌子甚至摔东西。除了周鸿祎身边的极少数人,其他人都时常被骂得狗血喷头,颜面扫地。”
不过,360也有很多优点,否则早就招不到人了。360跟水浒梁山很像的一点还在于:即便你是小喽啰,也可能天天看到宋江——周鸿祎。该员工还表示:“360的上级会像家长那样,对个人表现出极大的关心,老周会突然跑到你身后看着你的电脑屏幕拍拍肩膀问你最近怎么样?离开时随手拿起你桌上的零食边走边吃。”如果你觉得这是老周信任你的表现,那你可就大错特错了。因为“周鸿祎则压根儿就从来没信任过底下人,对总监以下(包括任职期限不长的很多总监)都是进行信息屏蔽的。”
在这样的文化下,新人可能因为周鸿祎突然的一个问候产生有存在感,也可能因为一次狗血淋头的批骂而甩手走人。新人可以随时打破规则与流程做出成绩,但是一年多以后就会因为信任天花板感到迷茫。而当你迷茫想走时,梁山泊的特质再一次显现了:“任何一个员工要跳槽都要经过几道关口的反复盘问,一直要谈到齐向东,如果在比较重要的岗位,周鸿祎会亲自约谈。去哪里?为什么要走?对什么不满?待遇提高一些是否愿意留下来?如果发现你是要去竞争对手阵营就会更难放行。如果你是真的不喜欢这里或有非常好的选择决意离开,就会非常麻烦。据说需要签很多约束性文件,让你感到跳槽风险很大,弄得就像离一次婚一样,麻烦到让你最后放弃跳槽为止。”
腾讯员工:注重对我的培养,却不懂得如何留住我
曾就职于腾讯的董先生说:“腾讯内部环境氛围都不错,待遇上也不错,整体员工素质也很高。”在腾讯的企业文化里,对员工的发展坚守的是“重视员工成长”,如果你是毕业生,在腾讯的工作幸福度将会非常高。原因是“你可以参加新生培训,同时还可以接触到强势的平台资源。大量的新人虽然是刚刚毕业做产品,哪怕全新做一个产品,在QQ tips和其他交叉推广资源的拉动下瞬间用户量过百万那是常事。这样的成就感是在其他公司比较难享受到的。”
问题是:对于新人而言,腾讯的架构太成熟了,在这里个人的价值被平台价值掩盖,因此不少新人还是会选择离开腾讯,原因很简单,在这找不到自己曾经梦想的那种激情。 于是,新人刚刚成熟后,也想要离职;但是对比360的层层盘问,在腾讯想走人则轻松的多。董先生他的领导重金挖过来的人才,但是在最后的离职面谈中,HR更像是例行公事,并没有做深入沟通。这样一来,腾讯花在员工培训上的成果很可能是为他人做嫁衣裳。因此,腾讯的企业文化看起来很好,但是如何落到实处很重要。
================================================
FILE: docs/android/Android-Interview/经验分享/史上最全 Android 面试资料集合.md
================================================

最近看到很多人都在找工作, 而且很多人都感觉今年找工作比去年难很多, 竞争力也增加不少, 因此激发我整理这份资料, 希望能帮到正在找或者准备找工作的童鞋们.
首先我们能否获得一个面试机会, 那肯定是从简历开始, 简历需要做好功夫, 一份好的简历才足够吸引企业得到面试机会, 接着就是面试了, 面试前必须要先做好准备, 多看一下前辈们总结面试题, 有哪一方面不足的地方赶紧补充一下, 还有要了解一下你即将面试那家公司.
> 感谢[@Android开发日常](http://weibo.com/AndroidDevDaily)(专注分享 Android 优质开源项目以及高质量开发资料) 支持
### 教你写简历
- [你真的会写简历么?](http://mp.weixin.qq.com/s?__biz=MzA4NTQwNDcyMA==&mid=402970472&idx=1&sn=b9738c66fb5750c2515d57357c01a83f&scene=21#wechat_redirect)
- [80% 以上简历都是不合格的](http://j.codekk.com/blogs/detail/5705bcdf4a38205862ef4770)
- [推荐两个技术简历模板](http://j.codekk.com/blogs/detail/5705bcdf4a38205862ef476f)
- [精益技术简历之道——改善技术简历的 47 条原则](http://lucida.me/blog/lean-technical-resume/)
- [关于程序员求职简历](https://mdluo.github.io/blog/about-resume/)
- [程序员简历模板列表](https://github.com/geekcompany/ResumeSample)
### 面试题
- [国内一线互联网公司内部面试题库](https://github.com/JackyAndroid/AndroidInterview-Q-A)
- [Android 开发工程师面试指南](https://github.com/GeniusVJR/LearningNotes)
- [一个五年 Android 开发者百度, 阿里, 聚美, 映客的面试心经](http://gdky005.com/2016/07/08/%E4%B8%80%E4%B8%AA%E4%BA%94%E5%B9%B4Android%E5%BC%80%E5%8F%91%E8%80%85%E7%99%BE%E5%BA%A6%E3%80%81%E9%98%BF%E9%87%8C%E3%80%81%E8%81%9A%E7%BE%8E%E3%80%81%E6%98%A0%E5%AE%A2%E7%9A%84%E9%9D%A2%E8%AF%95%E5%BF%83%E7%BB%8F/)
- [整理常见 Android 面试问题](https://github.com/leerduo/InterviewQuestion)
- [2016 Android 某公司面试题](http://yuweiguocn.github.io/2016/04/13/interview-2016-big-company/)
- [面试后的总结](http://kymjs.com/code/2016/03/08/01/)
- [Android 面试题整理](http://www.jianshu.com/p/a22450882af2)
- [Android interview questions for 2-5 yrs experienced](http://androidquestions.quora.com/Android-interview-questions-for-2-5-yrs-experienced)
- [Android interview questions](http://androidquestions.quora.com/Android-interview-questions)
- [40 个 Android 面试题](http://www.devstore.cn/essay/essayInfo/7195.html)
- [Android 名企面试题及涉及知识点整理](https://github.com/Mr-YangCheng/ForAndroidInterview)
- [亲爱的面试官,这个我可没看过!(Android部分)](http://www.jianshu.com/p/89f19d67b348)
### 做题
看完面试题之后那就来做一下面试题目吧, 目前找到两个网站
- [SillGun](http://skillgun.com/android/interview-questions-and-answers)(国外网站, 自备梯子)
- [牛客网](http://www.nowcoder.com/)
### 聊面试
[(帅张)stormzhang](http://stormzhang.com/) 跟你谈一下面试那些事儿
- [面试时企业最看中你什么能力?](http://mp.weixin.qq.com/s?__biz=MzA4NTQwNDcyMA==&mid=2650661810&idx=1&sn=f8c1ca67527459db3189a978f0e44cef&scene=23&srcid=08101MZAPzGR1MC1C577enim#rd)
- [我面试到底问什么?](https://zhuanlan.zhihu.com/p/21343656?refer=stormzhang)
- [Android 面试那些事儿](https://zhuanlan.zhihu.com/p/21565914?refer=stormzhang)
### 知乎讨论
- [面试时, 问哪些问题能试出一个 Android 应用开发者真正的水平?](https://www.zhihu.com/question/19765032)
- [我用个假简历去面试 android 的结果为什么会这样?](https://www.zhihu.com/question/38982159)
- [怎么准备Android面试?](https://www.zhihu.com/question/37483907)
### 互联网招聘平台
- [拉勾-专注互联网职业机会](http://www.lagou.com/)
- [简寻-让职位推荐更精准](https://jianxun.io/)
- [100 offer-帮最好的互联网人发现更好的offer](https://100offer.com/)
- [BOSS 直聘-互联网招聘神器](https://www.bosszhipin.com/home/#index)
- [LinkedIn (领英)](https://www.linkedin.com/)
- [哪上班](https://www.nashangban.com/)
### 感谢
非常感谢上面分享面试资料以及面试经验的前辈们!
有前辈在前面带路, 我们后辈真心感到幸福.
### 祝福
最后祝正在找工作的的童鞋们, 马到成功, 心想事成, 事事如意!
> 原文链接:G军仔,http://www.jianshu.com/p/d1efe2f31b6d
================================================
FILE: docs/android/Android-Interview/经验分享/国内一线互联网公司内部面试题库.md
================================================
## 国内一线互联网公司内部面试题库
以下面试题来自于百度、小米、乐视、美团、58、猎豹、360、新浪、搜狐内部题库
熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。
GitHub:https://github.com/JackyAndroid/AndroidInterview-Q-A
GitBook:https://www.gitbook.com/book/jackyandroid/androidinterview/details
掘金: https://gold.xitu.io/user/562dc7cc60b20fc9817962a2
## 目录
* [java基础](#java)
* [接口的意义-百度](#接口的意义-百度)
* [抽象类的意义-乐视](#抽象类的意义-乐视)
* [内部类的作用-乐视](#内部类的作用-乐视)
* [父类的静态方法能否被子类重写-猎豹](#父类的静态方法能否被子类重写-猎豹)
* [java排序算法-美团](#java排序算法-美团)
* [列举java的集合和继承关系-百度-美团](#列举java的集合和继承关系-百度-美团)
* [java虚拟机的特性-百度-乐视](#java虚拟机的特性-百度-乐视)
* [哪些情况下的对象会被垃圾回收机制处理掉-美团-小米](#哪些情况下的对象会被垃圾回收机制处理掉-美团-小米)
* [进程和线程的区别-猎豹-美团](#进程和线程的区别-猎豹-美团)
* [==和equals和hashCode的区别-乐视](#java中==和equals和hashCode的区别-乐视)
* [常见的排序算法时间复杂度-小米](#常见的排序算法时间复杂度-小米)
* [HashMap的实现原理-美团](#HashMap的实现原理-美团)
* [java状态机](#java状态机)
* [int-char-long各占多少字节数](#int-char-long各占多少字节数)
* [int与integer的区别](#int与integer的区别)
* [string-stringbuffer-stringbuilder区别-小米-乐视-百度](#string-stringbuffer-stringbuilder区别-小米-乐视-百度)
* [java多态-乐视](#java多态-乐视)
* [什么导致线程阻塞-58-美团](#什么导致线程阻塞-58-美团)
* [抽象类接口区别-360](#抽象类接口区别-360)
* [容器类之间的区别-乐视-美团](#容器类之间的区别-乐视-美团)
* [内部类](#内部类)
* [hashmap和hashtable的区别-乐视-小米](#hashmap和hashtable的区别-乐视-小米)
* [ArrayMap对比HashMap](#arraymap对比hashmap)
* [安卓](#android)
* [如何导入外部数据库](#如何导入外部数据库)
* [本地广播和全局广播有什么差别](#本地广播和全局广播有什么差别)
* [intentService作用是什么,AIDL解决了什么问题?-小米](#intentService作用是什么,AIDL解决了什么问题-小米)
* [Activity,Window,View三者的差别,fragment的特点?-360](#Activity,Window,View三者的差别,fragment的特点-360)
* [描述一次网络请求的流程-新浪](#描述一次网络请求的流程-新浪)
* [Handler、Thread和HandlerThread的差别-小米](#Handler,Thread和HandlerThread的差别-小米)
* [低版本SDK实现高版本api-小米](#低版本SDK实现高版本api-小米)
* [Ubuntu编译安卓系统-百度](#Ubuntu编译安卓系统-百度)
* [launch mode应用场景-百度-小米-乐视](#LaunchMode应用场景-百度-小米-乐视)
* [Touch事件传递流程-小米](#Touch事件传递流程-小米)
* [view绘制流程-百度](#View绘制流程-百度)
* [多线程-360](#多线程-360)
* [线程同步-百度](#线程同步-百度)
* [什么情况导致内存泄漏-美团](#什么情况导致内存泄漏-美团)
* [ANR定位和修正](#ANR定位和修正)
* [什么情况导致oom-乐视-美团](#什么情况导致oom-乐视-美团)
* [Android Service与Activity之间通信的几种方式](#Service与Activity之间通信的几种方式)
* [Android各个版本API的区别](#Android各个版本API的区别)
* [Android代码中实现WAP方式联网-360](#Android代码中实现WAP方式联网-360)
* [如何保证service在后台不被kill](#如何保证service在后台不被Kill)
* [Requestlayout,onlayout,onDraw,DrawChild区别与联系-猎豹](#Requestlayout,onlayout,onDraw,DrawChild区别与联系-猎豹)
* [invalidate()和postInvalidate()的区别及使用-百度](#invalidate()和postInvalidate()的区别及使用-百度)
* [Android动画框架实现原理](#Android动画框架实现原理)
* [Android为每个应用程序分配的内存大小是多少?-美团](#Android为每个应用程序分配的内存大小是多少?-美团)
* [Android View刷新机制-百度-美团](#View刷新机制-百度-美团)
* [LinearLayout对比RelativeLayout-百度](#LinearLayout和RelativeLayout性能对比-百度)
* [优化自定义view百度-乐视-小米](#优化自定义view百度-乐视-小米)
* [ContentProvider-乐视](#ContentProvider-乐视)
* [fragment生命周期](#Fragment生命周期)
* [volley解析-美团-乐视](#volley解析-美团-乐视)
* [Android Glide源码解析](Glide源码解析)
* [Android 设计模式](#Android设计模式)
* [架构设计-搜狐](#架构设计-搜狐)
* [Android属性动画特性-乐视-小米](#Android属性动画特性-乐视-小米)
* [专题](#专题)
* [性能优化](#性能优化)
* [架构分析](#架构分析)
* [阿里巴巴](#阿里面试题)
* [腾讯](#腾讯)
## java
#### 接口的意义-百度
规范、扩展、回调、通知机制
#### 抽象类的意义-乐视
为其子类提供一个公共的类型,封装子类中得重复内容
定义抽象方法,子类虽然有不同的实现 但是定义是一致的
#### 内部类的作用-乐视
1. 内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立
2. 在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类
3. 创建内部类对象的时刻并不依赖于外围类对象的创建
4. 内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体
5. 内部类提供了更好的封装,除了该外围类,其他类都不能访问
#### 父类的静态方法能否被子类重写-猎豹
不能,子类继承父类后,用相同的静态方法和非静态方法,这时非静态方法覆盖父类中的方法(即方法重写),父类的该静态方法被隐藏(如果对象是父类则调用该隐藏的方法),另外子类可继承父类的静态与非静态方法,至于方法重载我觉得它其中一要素就是在同一类中,不能说父类中的什么方法与子类里的什么方法是方法重载的体现
#### java排序算法-美团
http://blog.csdn.net/qy1387/article/details/7752973
#### 列举java的集合和继承关系-百度-美团

#### java虚拟机的特性-百度-乐视
Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用模式Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。
#### 哪些情况下的对象会被垃圾回收机制处理掉-美团-小米
Java 垃圾回收机制最基本的做法是分代回收。内存中的区域被划分成不同的世代,对象根据其存活的时间被保存在对应世代的区域中。一般的实现是划分成3个世代:年轻、年老和永久。内存的分配是发生在年轻世代中的。当一个对象存活时间足够长的时候,它就会被复制到年老世代中。对于不同的世代可以使用不同的垃圾回收算法。进行世代划分的出发点是对应用中对象存活时间进行研究之后得出的统计规律。一般来说,一个应用中的大部分对象的存活时间都很短。比如局部变量的存活时间就只在方法的执行过程中。基于这一点,对于年轻世代的垃圾回收算法就可以很有针对性。
#### 进程和线程的区别-猎豹-美团
简而言之,一个程序至少有一个进程,一个进程至少有一个线程。
线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。如果有兴趣深入的话,我建议你们看看《现代操作系统》或者《操作系统的设计与实现》。对就个问题说得比较清楚。
#### java中==和equals和hashCode的区别-乐视
http://blog.csdn.net/tiantiandjava/article/details/46988461
#### 常见的排序算法时间复杂度-小米
| 排序法 | 最差时间分析 | 平均时间复杂度 | 稳定度 | 空间复杂度 |
| :---- | :------------------- | :------------------- | :--- | :----------------------- |
| 冒泡排序 | O(n2) | O(n2) | 稳定 | O(1) |
| 快速排序 | O(n2) | O(nlog2n) | 不稳定 | O(log2n)~O(n) |
| 选择排序 | O(n2) | O(n2) | 稳定 | O(1) |
| 二叉树排序 | O(n2) | O(nlog2n) | 不一顶 | O(n) |
| 插入排序 | O(n2) | O(n2) | 稳定 | O(1) |
| 堆排序 | O(nlog2n) | O(nlog2n) | 不稳定 | O(1) |
| 希尔排序 | O | O | 不稳定 | O(1) |
#### HashMap的实现原理-美团
1.HashMap概述:
HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
2.HashMap的数据结构:
在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。

从上图中可以看出,HashMap底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。
#### 状态机
http://www.jdon.com/designpatterns/designpattern_State.htm
#### int-char-long各占多少字节数
| 类 | 位数 | 字节数 |
| ------ | :--- | :--- |
| byte | 8 | 1 |
| short | 16 | 2 |
| int | 32 | 4 |
| long | 64 | 8 |
| float | 32 | 4 |
| double | 64 | 8 |
| char | 16 | 2 |
#### int与integer的区别
http://www.cnblogs.com/shenliang123/archive/2011/10/27/2226903.html
#### string-stringbuffer-stringbuilder区别-小米-乐视-百度
String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)
简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后,JVM 的 GC 就会开始工作,那速度是一定会相当慢的。
而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:
```java
String S1 = "This is only a" + "simple" + " test";
StringBuffer Sb = new StringBuffer("This is only a").append("simple").append("test");
```
你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个
`String S1 = “This is only a” + “ simple” + “test”;` 其实就是:
`String S1 = “This is only a simple test”;` 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:
```java
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
```
这时候 JVM 会规规矩矩的按照原来的方式去做
在大部分情况下 StringBuffer 快于 String
StringBuffer
Java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append("le") 会使字符串缓冲区包含“startle”,而 z.insert(4, "le") 将更改字符串缓冲区,使之包含“starlet”。
在大部分情况下 StringBuilder 快于 StringBuffer
java.lang.StringBuilder
java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同
#### java多态-乐视
Java多态性理解
Java中多态性的实现
什么是多态
面向对象的三大特性:封装、继承、多态。从一定角度来看,封装和继承几乎都是为多态而准备的。这是我们最后一个概念,也是最重要的知识点。
多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实
际类型,根据其实际的类型调用其相应的方法。
多态的作用:消除类型之间的耦合关系。
现实中,关于多态的例子不胜枚举。比方说按下 F1 键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。
下面是多态存在的三个必要条件,要求大家做梦时都能背出来!
多态存在的三个必要条件
- 要有继承
- 要有重写
- 父类引用指向子类对象
多态的好处:
1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3 所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。
4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
Java中多态的实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。
#### 什么导致线程阻塞-58-美团
线程的阻塞
为了解决对共享存储区的访问冲突,Java 引入了同步机制,现在让我们来考察多个线程对共享资源的访问,显然同步机制已经不够了,因为在任意时刻所要求的资源不一定已经准备好了被访问,反过来,同一时刻准备好了的资源也可能不止一个。为了解决这种情况下的访问控制问题,Java 引入了对阻塞机制的支持
阻塞指的是暂停一个线程的执行以等待某个条件发生(如某资源就绪),学过操作系统的同学对它一定已经很熟悉了。Java 提供了大量方法来支持阻塞,下面让我们逐一分析。
1.sleep() 方法:sleep() 允许 指定以毫秒为单位的一段时间作为参数,它使得线程在指定的时间内进入阻塞状态,不能得到CPU时间,指定的时间一过,线程重新进入可执行状态。
典型地,sleep() 被用在等待某个资源就绪的情形:测试发现条件不满足后,让线程阻塞一段时间后重新测试,直到条件满足为止。
2.suspend() 和 resume() 方法:两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume() 被调用,才能使得线程重新进入可执行状态。典型地,suspend() 和 resume() 被用在等待另一个线程产生的结果的情形:测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后,调用 resume() 使其恢复。
3.yield() 方法:yield() 使得线程放弃当前分得的 CPU 时间,但是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程.
4.wait() 和 notify() 方法:两个方法配套使用,wait() 使得线程进入阻塞状态,它有两种形式,一种允许 指定以毫秒为单位的一段时间作为参数,另一种没有参数,前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的 notify() 被调用.
初看起来它们与 suspend() 和 resume() 方法对没有什么分别,但是事实上它们是截然不同的。区别的核心在于,前面叙述的所有方法,阻塞时都不会释放占用的锁(如果占用了的话),而这一对方法则相反。
上述的核心区别导致了一系列的细节上的区别。
首先,前面叙述的所有方法都隶属于 Thread 类,但是这一对却直接隶属于 Object 类,也就是说,所有对象都拥有这一对方法。初看起来这十分不可思议,但是实际上却是很自然的,因为这一对方法阻塞时要释放占用的锁,而锁是任何对象都具有的,调用任意对象的 wait() 方法导致线程阻塞,并且该对象上的锁被释放。而调用 任意对象的notify()方法则导致因调用该对象的 wait() 方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。
其次,前面叙述的所有方法都可在任何位置调用,但是这一对方法却必须在 synchronized 方法或块中调用,理由也很简单,只有在synchronized 方法或块中当前线程才占有锁,才有锁可以释放。同样的道理,调用这一对方法的对象上的锁必须为当前线程所拥有,这样才有锁可以释放。因此,这一对方法调用必须放置在这样的 synchronized 方法或块中,该方法或块的上锁对象就是调用这一对方法的对象。若不满足这一条件,则程序虽然仍能编译,但在运行时会出现IllegalMonitorStateException 异常。
wait() 和 notify() 方法的上述特性决定了它们经常和synchronized 方法或块一起使用,将它们和操作系统的进程间通信机制作一个比较就会发现它们的相似性:synchronized方法或块提供了类似于操作系统原语的功能,它们的执行不会受到多线程机制的干扰,而这一对方法则相当于 block 和wakeup 原语(这一对方法均声明为 synchronized)。它们的结合使得我们可以实现操作系统上一系列精妙的进程间通信的算法(如信号量算法),并用于解决各种复杂的线程间通信问题。
关于 wait() 和 notify() 方法最后再说明两点:
第一:调用 notify() 方法导致解除阻塞的线程是从因调用该对象的 wait() 方法而阻塞的线程中随机选取的,我们无法预料哪一个线程将会被选择,所以编程时要特别小心,避免因这种不确定性而产生问题。
第二:除了 notify(),还有一个方法 notifyAll() 也可起到类似作用,唯一的区别在于,调用 notifyAll() 方法将把因调用该对象的 wait() 方法而阻塞的所有线程一次性全部解除阻塞。当然,只有获得锁的那一个线程才能进入可执行状态。
谈到阻塞,就不能不谈一谈死锁,略一分析就能发现,suspend() 方法和不指定超时期限的 wait() 方法的调用都可能产生死锁。遗憾的是,Java 并不在语言级别上支持死锁的避免,我们在编程中必须小心地避免死锁。
以上我们对 Java 中实现线程阻塞的各种方法作了一番分析,我们重点分析了 wait() 和 notify() 方法,因为它们的功能最强大,使用也最灵活,但是这也导致了它们的效率较低,较容易出错。实际使用中我们应该灵活使用各种方法,以便更好地达到我们的目的。
#### 抽象类接口区别-360
1.默认的方法实现
抽象类可以有默认的方法实现完全是抽象的。接口根本不存在方法的实现
2.实现
子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。
子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现
3.构造器
抽象类可以有构造器
接口不能有构造器
4.与正常Java类的区别
除了你不能实例化抽象类之外,它和普通Java类没有任何区
接口是完全不同的类型
5.访问修饰符
抽象方法可以有public、protected和default这些修饰符
接口方法默认修饰符是public。你不可以使用其它修饰符。
6.main方法
抽象方法可以有main方法并且我们可以运行它
接口没有main方法,因此我们不能运行它。
7.多继承
抽象类在java语言中所表示的是一种继承关系,一个子类只能存在一个父类,但是可以存在多个接口。
8.速度
它比接口速度要快
接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。
9.添加新方法
如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。
如果你往接口中添加方法,那么你必须改变实现该接口的类。
#### 容器类之间的区别-乐视-美团
http://www.cnblogs.com/yuanermen/archive/2009/08/05/1539917.html
http://alexyyek.github.io/2015/04/06/Collection
http://tianmaying.com/tutorial/java_collection
#### 内部类
http://www.cnblogs.com/chenssy/p/3388487.html
#### hashmap和hashtable的区别-乐视-小米
http://www.233.com/ncre2/JAVA/jichu/20100717/084230917.html
#### ArrayMap对比HashMap
http://lvable.com/?p=217
## Android
#### 如何导入外部数据库
把原数据库包括在项目源码的 res/raw
android系统下数据库应该存放在 /data/data/packagename/ 目录下,所以我们需要做的是把已有的数据库传入那个目录下.操作方法是用FileInputStream读取原数据库,再用FileOutputStream把读取到的东西写入到那个目录.
#### 本地广播和全局广播有什么差别
因广播数据在本应用范围内传播,不用担心隐私数据泄露的问题。
不用担心别的应用伪造广播,造成安全隐患。
相比在系统内发送全局广播,它更高效。
#### intentService作用是什么,AIDL解决了什么问题-小米
生成一个默认的且与主线程互相独立的工作者线程来执行所有传送至onStartCommand() 方法的Intetnt。
生成一个工作队列来传送Intent对象给你的onHandleIntent()方法,同一时刻只传送一个Intent对象,这样一来,你就不必担心多线程的问题。在所有的请求(Intent)都被执行完以后会自动停止服务,所以,你不需要自己去调用stopSelf()方法来停止。
该服务提供了一个onBind()方法的默认实现,它返回null
提供了一个onStartCommand()方法的默认实现,它将Intent先传送至工作队列,然后从工作队列中每次取出一个传送至onHandleIntent()方法,在该方法中对Intent对相应的处理。
AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。
AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量级。它是使用代理类在客户端和实现端传递数据。
#### Activity/Window/View三者的差别,fragment的特点-360
Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图)
LayoutInflater像剪刀,Xml配置像窗花图纸。
1. 在Activity中调用attach,创建了一个Window
2. 创建的window是其子类PhoneWindow,在attach中创建PhoneWindow
3. 在Activity中调用setContentView(R.layout.xxx)
4. 其中实际上是调用的getWindow().setContentView()
5. 调用PhoneWindow中的setContentView方法
6. 创建ParentView:作为ViewGroup的子类,实际是创建的DecorView(作为FramLayout的子类)
7. 将指定的R.layout.xxx进行填充,通过布局填充器进行填充[其中的parent指的就是DecorView]
8. 调用到ViewGroup
9. 调用ViewGroup的removeAllView(),先将所有的view移除掉
10. 添加新的view:addView()
fragment 特点
- Fragment可以作为Activity界面的一部分组成出现
- 可以在一个Activity中同时出现多个Fragment,并且一个Fragment也可以在多个Activity中使用
- 在Activity运行过程中,可以添加、移除或者替换Fragment
- Fragment可以响应自己的输入事件,并且有自己的生命周期,它们的生命周期会受宿主Activity的生命周期影响
#### 描述一次网络请求的流程-新浪

#### Handler,Thread和HandlerThread的差别-小米
http://blog.csdn.net/guolin_blog/article/details/9991569
http://droidyue.com/blog/2015/11/08/make-use-of-handlerthread/
从Android中Thread(java.lang.Thread → java.lang.Object)描述可以看出,Android的Thread没有对Java的Thread做任何封装,但是Android提供了一个继承自Thread的类HandlerThread(android.os.HandlerThread → java.lang.Thread),这个类对Java的Thread做了很多便利Android系统的封装。
android.os.Handler可以通过Looper对象实例化,并运行于另外的线程中,Android提供了让Handler运行于其它线程的线程实现,也是就HandlerThread。HandlerThread对象start后可以获得其Looper对象,并且使用这个Looper对象实例Handler。
#### 低版本SDK实现高版本api-小米
自己实现或@TargetApi annotation
#### Ubuntu编译安卓系统-百度
1. 进入源码根目录
2. build/envsetup.sh
3. lunch
4. full(编译全部)
5. userdebug(选择编译版本)
6. make -j8(开启8个线程编译)
#### LaunchMode应用场景-百度-小米-乐视
standard,创建一个新的Activity。
singleTop,栈顶不是该类型的Activity,创建一个新的Activity。否则,onNewIntent。
singleTask,回退栈中没有该类型的Activity,创建Activity,否则,onNewIntent+ClearTop。
注意:
1. 设置了singleTask启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的Task存在; 如果存在这样的Task,它就会在这个Task中启动,否则就会在新的任务栈中启动。因此, 如果我们想要设置了singleTask启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。
2. 如果设置了singleTask启动模式的Activity不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity实例, 如果存在,就会把位于这个Activity实例上面的Activity全部结束掉,即最终这个Activity 实例会位于任务的Stack顶端中。
3. 在一个任务栈中只有一个singleTask启动模式的Activity存在。他的上面可以有其他的Activity。这点与singleInstance是有区别的。
singleInstance,回退栈中,只有这一个Activity,没有其他Activity。
singleTop适合接收通知启动的内容显示页面。
例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。
singleTask适合作为程序入口点。
例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。
singleInstance应用场景:
闹铃的响铃界面。 你以前设置了一个闹铃:上午6点。在上午5点58分,你启动了闹铃设置界面,并按 Home 键回桌面;在上午5点59分时,你在微信和朋友聊天;在6点时,闹铃响了,并且弹出了一个对话框形式的 Activity(名为 AlarmAlertActivity) 提示你到6点了(这个 Activity 就是以 SingleInstance 加载模式打开的),你按返回键,回到的是微信的聊天界面,这是因为 AlarmAlertActivity 所在的 Task 的栈只有他一个元素, 因此退出之后这个 Task 的栈空了。如果是以 SingleTask 打开 AlarmAlertActivity,那么当闹铃响了的时候,按返回键应该进入闹铃设置界面。
#### Touch事件传递流程-小米
[Android-三张图搞定Touch事件传递机制](http://hanhailong.com/2015/09/24/Android-三张图搞定Touch事件传递机制/)
#### View绘制流程-百度
[公共技术点之 View 绘制流程](http://www.codekk.com/blogs/detail/54cfab086c4761e5001b253f)
#### 多线程-360
* Activity.runOnUiThread(Runnable)
* View.post(Runnable),View.postDelay(Runnable,long)
* Handler
* AsyncTask
#### 线程同步-百度
[Java基础笔记 – 线程同步问题 解决同步问题的方法 synchronized方法 同步代码块](http://www.itzhai.com/java-based-notebook-thread-synchronization-problem-solving-synchronization-problems-synchronized-block-synchronized-methods.html#read-more)
[Android线程间交互(Java synchronized & Android Handler)](http://www.juwends.com/tech/android/android-inter-thread-comm.html)
单例
```java
public class Singleton{
private volatile static Singleton mSingleton;
private Singleton(){
}
public static Singleton getInstance(){
if(mSingleton == null){\\A
synchronized(Singleton.class){\\C
if(mSingleton == null)
mSingleton = new Singleton();\\B
}
}
return mSingleton;
}
}
```
#### 什么情况导致内存泄漏-美团
1.资源对象没关闭造成的内存泄漏
描述:资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不仅存在于 java虚拟机内,还存在于java虚拟机外。如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄漏。因为有些资源性对象,比如 SQLiteCursor(在析构函数finalize(),如果我们没有关闭它,它自己会调close()关闭),如果我们没有关闭它,系统在回收它时也会关闭它,但是这样的效率太低了。因此对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,然后才置为null.在我们的程序退出时一定要确保我们的资源性对象已经关闭。
程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。
2.构造Adapter时,没有使用缓存的convertView
描述:以构造ListView的BaseAdapter为例,在BaseAdapter中提供了方法:
`public View getView(int position, ViewconvertView, ViewGroup parent)`
来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的 view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。由此可以看出,如果我们不去使用 convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。 ListView回收list item的view对象的过程可以查看:
android.widget.AbsListView.java → voidaddScrapView(View scrap) 方法。
示例代码:
```java
public View getView(int position, ViewconvertView, ViewGroup parent) {
View view = new Xxx(...);
...
return view;
}
```
修正示例代码:
```java
public View getView(int position, ViewconvertView, ViewGroup parent) {
View view = null;
if (convertView != null) {
view = convertView;
populate(view, getItem(position));
...
} else {
view = new Xxx(...);
...
}
return view;
}
```
3.Bitmap对象不在使用时调用recycle()释放内存
描述:有时我们会手工的操作Bitmap对象,如果一个Bitmap对象比较占内存,当它不在被使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。可以看一下代码中的注释:
```
/**
* Free up the memory associated with thisbitmap's pixels, and mark the
* bitmap as "dead", meaning itwill throw an exception if getPixels() or
* setPixels() is called, and will drawnothing. This operation cannot be
* reversed, so it should only be called ifyou are sure there are no
* further uses for the bitmap. This is anadvanced call, and normally need
* not be called, since the normal GCprocess will free up this memory when
* there are no more references to thisbitmap.
*/
```
4.试着使用关于application的context来替代和activity相关的context
这是一个很隐晦的内存泄漏的情况。有一种简单的方法来避免context相关的内存泄漏。最显著地一个是避免context逃出他自己的范围之外。使用Application context。这个context的生存周期和你的应用的生存周期一样长,而不是取决于activity的生存周期。如果你想保持一个长期生存的对象,并且这个对象需要一个context,记得使用application对象。你可以通过调用 Context.getApplicationContext() or Activity.getApplication()来获得。更多的请看这篇文章如何避免Android内存泄漏。
5.注册没取消造成的内存泄漏
一些Android程序可能引用我们的Anroid程序的对象(比如注册机制)。即使我们的Android程序已经结束了,但是别的引用程序仍然还有对我们的Android程序的某个对象的引用,泄漏的内存依然不能被垃圾回收。调用registerReceiver后未调用unregisterReceiver。
比如:假设我们希望在锁屏界面(LockScreen)中,监听系统中的电话服务以获取一些信息(如信号强度等),则可以在LockScreen中定义一个 PhoneStateListener的对象,同时将它注册到TelephonyManager服务中。对于LockScreen对象,当需要显示锁屏界面的时候就会创建一个LockScreen对象,而当锁屏界面消失的时候LockScreen对象就会被释放掉。
但是如果在释放 LockScreen对象的时候忘记取消我们之前注册的PhoneStateListener对象,则会导致LockScreen无法被垃圾回收。如果不断的使锁屏界面显示和消失,则最终会由于大量的LockScreen对象没有办法被回收而引起OutOfMemory,使得system_process 进程挂掉。
虽然有些系统程序,它本身好像是可以自动取消注册的(当然不及时),但是我们还是应该在我们的程序中明确的取消注册,程序结束时应该把所有的注册都取消掉。
6.集合中对象没清理造成的内存泄漏
我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。
#### ANR定位和修正
如果开发机器上出现问题,我们可以通过查看/data/anr/traces.txt即可,最新的ANR信息在最开始部分。
* 主线程被IO操作(从4.0之后网络IO不允许在主线程中)阻塞。
* 主线程中存在耗时的计算
* 主线程中错误的操作,比如Thread.wait或者Thread.sleep等
Android系统会监控程序的响应状况,一旦出现下面两种情况,则弹出ANR对话框
* 应用在5秒内未响应用户的输入事件(如按键或者触摸)
* BroadcastReceiver未在10秒内完成相关的处理
* Service在特定的时间内无法处理完成 20秒
* 使用AsyncTask处理耗时IO操作。
* 使用Thread或者HandlerThread时,调用`Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)`设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同。
* 使用Handler处理工作线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程。
* Activity的onCreate和onResume回调中尽量避免耗时的代码
* BroadcastReceiver中onReceive代码也要尽量减少耗时,建议使用IntentService处理
#### 什么情况导致oom-乐视-美团
[Android内存优化之OOM](http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0920/3478.html)
- 使用更加轻量的数据结构
- Android里面使用Enum
- Bitmap对象的内存占用
- 更大的图片
- onDraw方法里面执行对象的创建
- StringBuilder
#### Service与Activity之间通信的几种方式
- 通过Binder对象
- 通过broadcast(广播)的形式
#### Android各个版本API的区别
http://blog.csdn.net/lijun952048910/article/details/7980562
#### Android代码中实现WAP方式联网-360
http://blog.csdn.net/asce1885/article/details/7844159
#### 如何保证service在后台不被Kill
一、onStartCommand方法,返回START_STICKY
1.START_STICKY
在运行onStartCommand后service进程被kill后,那将保留在开始状态,但是不保留那些传入的intent。不久后service就会再次尝试重新创建,因为保留在开始状态,在创建 service后将保证调用onstartCommand。如果没有传递任何开始命令给service,那将获取到null的intent。
2.START_NOT_STICKY
在运行onStartCommand后service进程被kill后,并且没有新的intent传递给它。Service将移出开始状态,并且直到新的明显的方法(startService)调用才重新创建。因为如果没有传递任何未决定的intent那么service是不会启动,也就是期间onstartCommand不会接收到任何null的intent。
3.START_REDELIVER_INTENT
在运行onStartCommand后service进程被kill后,系统将会再次启动service,并传入最后一个intent给onstartCommand。直到调用stopSelf(int)才停止传递intent。如果在被kill后还有未处理好的intent,那被kill后服务还是会自动启动。因此onstartCommand不会接收到任何null的intent。
二、提升service优先级
在AndroidManifest.xml文件中对于intent-filter可以通过`android:priority = "1000"`这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
三、提升service进程优先级
Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是:
1. 前台进程( FOREGROUND_APP)
2. 可视进程(VISIBLE_APP )
3. 次要服务进程(SECONDARY_SERVER )
4. 后台进程 (HIDDEN_APP)
5. 内容供应节点(CONTENT_PROVIDER)
6. 空进程(EMPTY_APP)
当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以使用startForeground 将service放到前台状态。这样在低内存时被kill的几率会低一些。
四、onDestroy方法里重启service
service +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service;
五、Application加上Persistent属性
六、监听系统广播判断Service状态
通过系统的一些广播,比如:手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的Service是否还存活,别忘记加权限啊。
#### Requestlayout,onlayout,onDraw,DrawChild区别与联系-猎豹
requestLayout()方法 :会导致调用measure()过程 和 layout()过程 。
将会根据标志位判断是否需要ondraw
onLayout()方法(如果该View是ViewGroup对象,需要实现该方法,对每个子视图进行布局)
调用onDraw()方法绘制视图本身 (每个View都需要重载该方法,ViewGroup不需要实现该方法)
drawChild()去重新回调每个子视图的draw()方法
#### invalidate()和postInvalidate()的区别及使用-百度
http://blog.csdn.net/mars2639/article/details/6650876
#### Android动画框架实现原理
Animation框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是整个View,实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用`canvas.concat(transformToApply.getMatrix()),`通过矩阵运算完成动画帧,如果动画没有完成,继续调用invalidate()函数,启动下次绘制来驱动动画,动画过程中的帧之间间隙时间是绘制函数所消耗的时间,可能会导致动画消耗比较多的CPU资源,最重要的是,动画改变的只是显示,并不能相应事件。
#### Android为每个应用程序分配的内存大小是多少-美团
android程序内存一般限制在16M,也有的是24M
#### View刷新机制-百度-美团
由ViewRoot对象的performTraversals()方法调用draw()方法发起绘制该View树,值得注意的是每次发起绘图时,并不会重新绘制每个View树的视图,而只会重新绘制那些“需要重绘”的视图,View类内部变量包含了一个标志位DRAWN,当该视图需要重绘时,就会为该View添加该标志位。
调用流程 :
mView.draw()开始绘制,draw()方法实现的功能如下:
1. 绘制该View的背景
2. 为显示渐变框做一些准备操作(见5,大多数情况下,不需要改渐变框)
3. 调用onDraw()方法绘制视图本身 (每个View都需要重载该方法,ViewGroup不需要实现该方法)
4. 调用dispatchDraw ()方法绘制子视图(如果该View类型不为ViewGroup,即不包含子视图,不需要重载该方法)值得说明的是,ViewGroup类已经为我们重写了dispatchDraw ()的功能实现,应用程序一般不需要重写该方法,但可以重载父类函数实现具体的功能。
#### LinearLayout和RelativeLayout性能对比-百度
1. RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View2次onMeasure
2. RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。
3. 在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。
最后再思考一下文章开头那个矛盾的问题,为什么Google给开发者默认新建了个RelativeLayout,而自己却在DecorView中用了个LinearLayout。因为DecorView的层级深度是已知而且固定的,上面一个标题栏,下面一个内容栏。采用RelativeLayout并不会降低层级深度,所以此时在根节点上用LinearLayout是效率最高的。而之所以给开发者默认新建了个RelativeLayout是希望开发者能采用尽量少的View层级来表达布局以实现性能最优,因为复杂的View嵌套对性能的影响会更大一些。
#### 优化自定义view百度-乐视-小米
为了加速你的view,对于频繁调用的方法,需要尽量减少不必要的代码。先从onDraw开始,需要特别注意不应该在这里做内存分配的事情,因为它会导致GC,从而导致卡顿。在初始化或者动画间隙期间做分配内存的动作。不要在动画正在执行的时候做内存分配的事情。
你还需要尽可能的减少onDraw被调用的次数,大多数时候导致onDraw都是因为调用了invalidate().因此请尽量减少调用invaildate()的次数。如果可能的话,尽量调用含有4个参数的invalidate()方法而不是没有参数的invalidate()。没有参数的invalidate会强制重绘整个view。
另外一个非常耗时的操作是请求layout。任何时候执行requestLayout(),会使得Android UI系统去遍历整个View的层级来计算出每一个view的大小。如果找到有冲突的值,它会需要重新计算好几次。另外需要尽量保持View的层级是扁平化的,这样对提高效率很有帮助。
如果你有一个复杂的UI,你应该考虑写一个自定义的ViewGroup来执行他的layout操作。与内置的view不同,自定义的view可以使得程序仅仅测量这一部分,这避免了遍历整个view的层级结构来计算大小。这个PieChart 例子展示了如何继承ViewGroup作为自定义view的一部分。PieChart 有子views,但是它从来不测量它们。而是根据他自身的layout法则,直接设置它们的大小。
#### ContentProvider-乐视
http://blog.csdn.net/coder_pig/article/details/47858489
#### Fragment生命周期
 
#### volley解析-美团-乐视
http://a.codekk.com/detail/Android/grumoon/Volley%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90
#### Glide源码解析
http://www.lightskystreet.com/2015/10/12/glide_source_analysis/
http://frodoking.github.io/2015/10/10/android-glide/
#### Android设计模式
http://blog.csdn.net/bboyfeiyu/article/details/44563871
#### 架构设计-搜狐

http://www.tianmaying.com/tutorial/AndroidMVC
#### Android属性动画特性-乐视-小米
如果你的需求中只需要对View进行移动、缩放、旋转和淡入淡出操作,那么补间动画确实已经足够健全了。但是很显然,这些功能是不足以覆盖所有的场景的,一旦我们的需求超出了移动、缩放、旋转和淡入淡出这四种对View的操作,那么补间动画就不能再帮我们忙了,也就是说它在功能和可扩展方面都有相当大的局限性,那么下面我们就来看看补间动画所不能胜任的场景。
注意上面我在介绍补间动画的时候都有使用“对View进行操作”这样的描述,没错,补间动画是只能够作用在View上的。也就是说,我们可以对一个Button、TextView、甚至是LinearLayout、或者其它任何继承自View的组件进行动画操作,但是如果我们想要对一个非View的对象进行动画操作,抱歉,补间动画就帮不上忙了。可能有的朋友会感到不能理解,我怎么会需要对一个非View的对象进行动画操作呢?这里我举一个简单的例子,比如说我们有一个自定义的View,在这个View当中有一个Point对象用于管理坐标,然后在onDraw()方法当中就是根据这个Point对象的坐标值来进行绘制的。也就是说,如果我们可以对Point对象进行动画操作,那么整个自定义View的动画效果就有了。显然,补间动画是不具备这个功能的,这是它的第一个缺陷。
然后补间动画还有一个缺陷,就是它只能够实现移动、缩放、旋转和淡入淡出这四种动画操作,那如果我们希望可以对View的背景色进行动态地改变呢?很遗憾,我们只能靠自己去实现了。说白了,之前的补间动画机制就是使用硬编码的方式来完成的,功能限定死就是这些,基本上没有任何扩展性可言。
最后,补间动画还有一个致命的缺陷,就是它只是改变了View的显示效果而已,而不会真正去改变View的属性。什么意思呢?比如说,现在屏幕的左上角有一个按钮,然后我们通过补间动画将它移动到了屏幕的右下角,现在你可以去尝试点击一下这个按钮,点击事件是绝对不会触发的,因为实际上这个按钮还是停留在屏幕的左上角,只不过补间动画将这个按钮绘制到了屏幕的右下角而已。
### 专题
### 性能优化
#### [Android性能优化典范 - 第1季](http://hukai.me/android-performance-patterns/)
1. **Render Performance** Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成。我们可以通过一些工具来定位问题,比如可以使用HierarchyViewer来查找Activity中的布局是否过于复杂,也可以使用手机设置里面的开发者选项,打开Show GPU Overdraw等选项进行观察。你还可以使用TraceView来观察CPU的执行情况,更加快捷的找到性能瓶颈。
2. **Understanding Overdraw** Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次的UI结构里面,如果不可见的UI也在做绘制的操作,这就会导致某些像素区域被绘制了多次。这就浪费大量的CPU以及GPU资源。Overdraw有时候是因为你的UI布局存在大量重叠的部分,还有的时候是因为非必须的重叠背景。例如某个Activity有一个背景,然后里面的Layout又有自己的背景,同时子View又分别有自己的背景。仅仅是通过移除非必须的背景图片,这就能够减少大量的红色Overdraw区域,增加蓝色区域的占比。这一措施能够显著提升程序性能。
3. **Understanding VSYNC** Refresh Rate:代表了屏幕在一秒内刷新屏幕的次数,这取决于硬件的固定参数,例如60Hz。Frame Rate:代表了GPU在一秒内绘制操作的帧数,例如30fps,60fps。通常来说,帧率超过刷新频率只是一种理想的状况,在超过60fps的情况下,GPU所产生的帧数据会因为等待VSYNC的刷新信息而被Hold住,这样能够保持每次刷新都有实际的新的数据可以显示。但是我们遇到更多的情况是帧率小于刷新频率。
4. **Tool:Profile GPU Rendering** 性能问题如此的麻烦,幸好我们可以有工具来进行调试。打开手机里面的开发者选项,选择Profile GPU Rendering,选中On screen as bars的选项。
5. **Why 60fps?** 我们通常都会提到60fps与16ms,可是知道为何会是以程序是否达到60fps来作为App性能的衡量标准吗?这是因为人眼与大脑之间的协作无法感知超过60fps的画面更新。开发app的性能目标就是保持60fps,这意味着每一帧你只有16ms=1000/60的时间来处理所有的任务。
6. **Android, UI and the GPU** 在Android里面那些由主题所提供的资源,例如Bitmaps,Drawables都是一起打包到统一的Texture纹理当中,然后再传递到GPU里面,这意味着每次你需要使用这些资源的时候,都是直接从纹理里面进行获取渲染的。当然随着UI组件的越来越丰富,有了更多演变的形态。例如显示图片的时候,需要先经过CPU的计算加载到内存中,然后传递给GPU进行渲染。文字的显示更加复杂,需要先经过CPU换算成纹理,然后再交给GPU进行渲染,回到CPU绘制单个字符的时候,再重新引用经过GPU渲染的内容。动画则是一个更加复杂的操作流程。为了能够使得App流畅,我们需要在每一帧16ms以内处理完所有的CPU与GPU计算,绘制,渲染等等操作。
7. **Invalidations, Layouts, and Performance** 任何时候View中的绘制内容发生变化时,都会重新执行创建DisplayList,渲染DisplayList,更新到屏幕上等一系列操作。这个流程的表现性能取决于你的View的复杂程度,View的状态变化以及渲染管道的执行性能。举个例子,假设某个Button的大小需要增大到目前的两倍,在增大Button大小之前,需要通过父View重新计算并摆放其他子View的位置。修改View的大小会触发整个HierarcyView的重新计算大小的操作。如果是修改View的位置则会触发HierarchView重新计算其他View的位置。如果布局很复杂,这就会很容易导致严重的性能问题。我们需要尽量减少Overdraw。
8. **Overdraw, Cliprect, QuickReject** 我们可以通过canvas.clipRect()来帮助系统识别那些可见的区域。这个方法可以指定一块矩形区域,只有在这个区域内才会被绘制,其他的区域会被忽视。这个API可以很好的帮助那些有多组重叠组件的自定义View来控制显示的区域。同时clipRect方法还可以帮助节约CPU与GPU资源,在clipRect区域之外的绘制指令都不会被执行,那些部分内容在矩形区域内的组件,仍然会得到绘制。
9. **Memory Churn and performance** 执行GC操作的时候,所有线程的任何操作都会需要暂停,等待GC操作完成之后,其他操作才能够继续运行。Memory Churn内存抖动,内存抖动是因为大量的对象被创建又在短时间内马上被释放。瞬间产生大量的对象会严重占用Young Generation的内存区域,当达到阀值,剩余空间不够的时候,也会触发GC。即使每次分配的对象占用了很少的内存,但是他们叠加在一起会增加Heap的压力,从而触发更多其他类型的GC。这个操作有可能会影响到帧率,并使得用户感知到性能问题。
10. **Garbage Collection in Android** 原始JVM中的GC机制在Android中得到了很大程度上的优化。Android里面是一个三级Generation的内存模型,最近分配的对象会存放在Young Generation区域,当这个对象在这个区域停留的时间达到一定程度,它会被移动到Old Generation,最后到Permanent Generation区域。如果不小心在最小的for循环单元里面执行了创建对象的操作,这将很容易引起GC并导致性能问题。通过Memory Monitor我们可以查看到内存的占用情况,每一次瞬间的内存降低都是因为此时发生了GC操作,如果在短时间内发生大量的内存上涨与降低的事件,这说明很有可能这里有性能问题。我们还可以通过Heap and Allocation Tracker工具来查看此时内存中分配的到底有哪些对象。
11. **Performance Cost of Memory Leaks** 内存泄漏指的是那些程序不再使用的对象无法被GC识别,这样就导致这个对象一直留在内存当中,占用了宝贵的内存空间。显然,这还使得每级Generation的内存区域可用空间变小,GC就会更容易被触发,从而引起性能问题。
12. **Memory Performance** 通常来说,Android对GC做了大量的优化操作,虽然执行GC操作的时候会暂停其他任务,可是大多数情况下,GC操作还是相对很安静并且高效的。但是如果我们对内存的使用不恰当,导致GC频繁执行,这样就会引起不小的性能问题。
13. **Tool - Memory Monitor** Android Studio中的Memory Monitor可以很好的帮助我们查看程序的内存使用情况。
14. **Battery Performance** 我们应该尽量减少唤醒屏幕的次数与持续的时间,使用WakeLock来处理唤醒的问题,能够正确执行唤醒操作并根据设定及时关闭操作进入睡眠状态。某些非必须马上执行的操作,例如上传歌曲,图片处理等,可以等到设备处于充电状态或者电量充足的时候才进行。触发网络请求的操作,每次都会保持无线信号持续一段时间,我们可以把零散的网络请求打包进行一次操作,避免过多的无线信号引起的电量消耗。关于网络请求引起无线信号的电量消耗
15. **Understanding Battery Drain on Android** 使用WakeLock或者JobScheduler唤醒设备处理定时的任务之后,一定要及时让设备回到初始状态。每次唤醒无线信号进行数据传递,都会消耗很多电量,它比WiFi等操作更加的耗电
16. **Battery Drain and WakeLocks** 这正是JobScheduler API所做的事情。它会根据当前的情况与任务,组合出理想的唤醒时间,例如等到正在充电或者连接到WiFi的时候,或者集中任务一起执行。我们可以通过这个API实现很多免费的调度算法。
#### [Android性能优化典范 - 第2季](http://hukai.me/android-performance-patterns-season-2/)
1. **Battery Drain and Networking** 我们可以有针对性的把请求行为捆绑起来,延迟到某个时刻统一发起请求。这部分主要会涉及到Prefetch(预取)与Compressed(压缩)这两个技术。对于Prefetch的使用,我们需要预先判断用户在此次操作之后,后续零散的请求是否很有可能会马上被触发,可以把后面5分钟有可能会使用到的零散请求都一次集中执行完毕。对于Compressed的使用,在上传与下载数据之前,使用CPU对数据进行压缩与解压,可以很大程度上减少网络传输的时间。
2. **Wear & Sensors** 首先我们需要尽量使用Android平台提供的既有运动数据,而不是自己去实现监听采集数据,因为大多数Android Watch自身记录Sensor数据的行为是有经过做电量优化的。其次在Activity不需要监听某些Sensor数据的时候需要尽快释放监听注册。还有我们需要尽量控制更新的频率,仅仅在需要刷新显示数据的时候才触发获取最新数据的操作。另外我们可以针对Sensor的数据做批量处理,待数据累积一定次数或者某个程度的时候才更新到UI上。最后当Watch与Phone连接起来的时候,可以把某些复杂操作的事情交给Phone来执行,Watch只需要等待返回的结果。
3. **Smooth Android Wear Animation** 在Android里面一个相对操作比较繁重的事情是对Bitmap进行旋转,缩放,裁剪等等。例如在一个圆形的钟表图上,我们把时钟的指针抠出来当做单独的图片进行旋转会比旋转一张完整的圆形图的所形成的帧率要高56%。
4. **Android Wear Data Batching** 仅仅在真正需要刷新界面的时候才发出请求,尽量把计算复杂操作的任务交给Phone来处理,Phone仅仅在数据发生变化的时候才通知到Wear,把零碎的数据请求捆绑一起再进行操作。
5. **Object Pools** 使用对象池技术有很多好处,它可以避免内存抖动,提升性能,但是在使用的时候有一些内容是需要特别注意的。通常情况下,初始化的对象池里面都是空白的,当使用某个对象的时候先去对象池查询是否存在,如果不存在则创建这个对象然后加入对象池,但是我们也可以在程序刚启动的时候就事先为对象池填充一些即将要使用到的数据,这样可以在需要使用到这些对象的时候提供更快的首次加载速度,这种行为就叫做预分配。使用对象池也有不好的一面,程序员需要手动管理这些对象的分配与释放,所以我们需要慎重地使用这项技术,避免发生对象的内存泄漏。为了确保所有的对象能够正确被释放,我们需要保证加入对象池的对象和其他外部对象没有互相引用的关系。
6. **To Index or Iterate?** for index的方式有更好的效率,但是因为不同平台编译器优化各有差异,我们最好还是针对实际的方法做一下简单的测量比较好,拿到数据之后,再选择效率最高的那个方式。
7. **The Magic of LRU Cache** 使用LRU Cache能够显著提升应用的性能,可是也需要注意LRU Cache中被淘汰对象的回收,否者会引起严重的内存泄露。
8. **Using LINT for Performance Tips** Lint已经集成到Android Studio中了,我们可以手动去触发这个工具,点击工具栏的Analysis → Inspect Code,触发之后,Lint会开始工作,并把结果输出到底部的工具栏,我们可以逐个查看原因并根据指示做相应的优化修改。
9. **Hidden Cost of Transparency** 通常来说,对于不透明的View,显示它只需要渲染一次即可,可是如果这个View设置了alpha值,会至少需要渲染两次。
10. **Avoiding Allocations in onDraw()** 首先onDraw()方法是执行在UI线程的,在UI线程尽量避免做任何可能影响到性能的操作。虽然分配内存的操作并不需要花费太多系统资源,但是这并不意味着是免费无代价的。设备有一定的刷新频率,导致View的onDraw方法会被频繁的调用,如果onDraw方法效率低下,在频繁刷新累积的效应下,效率低的问题会被扩大,然后会对性能有严重的影响。
11. **Tool: Strict Mode** Android提供了一个叫做Strict Mode的工具,我们可以通过手机设置里面的开发者选项,打开Strict Mode选项,如果程序存在潜在的隐患,屏幕就会闪现红色。我们也可以通过StrictMode API在代码层面做细化的跟踪,可以设置StrictMode监听那些潜在问题,出现问题时如何提醒开发者,可以对屏幕闪红色,也可以输出错误日志。
12. **Custom Views and Performance** Useless calls to onDraw():我们知道调用View.invalidate()会触发View的重绘,有两个原则需要遵守,第1个是仅仅在View的内容发生改变的时候才去触发invalidate方法,第2个是尽量使用ClipRect等方法来提高绘制的性能。Useless pixels:减少绘制时不必要的绘制元素,对于那些不可见的元素,我们需要尽量避免重绘。Wasted CPU cycles:对于不在屏幕上的元素,可以使用Canvas.quickReject把他们给剔除,避免浪费CPU资源。另外尽量使用GPU来进行UI的渲染,这样能够极大的提高程序的整体表现性能。
13. **Batching Background Work Until Later**
1.AlarmManager 使用AlarmManager设置定时任务,可以选择精确的间隔时间,也可以选择非精确时间作为参数。除非程序有很强烈的需要使用精确的定时唤醒,否者一定要避免使用他,我们应该尽量使用非精确的方式。2.SyncAdapter 我们可以使用SyncAdapter为应用添加设置账户,这样在手机设置的账户列表里面可以找到我们的应用。这种方式功能更多,但是实现起来比较复杂。我们可以从这里看到官方的培训课程:http://developer.android.com/training/sync-adapters/index.html 3.JobSchedulor 这是最简单高效的方法,我们可以设置任务延迟的间隔,执行条件,还可以增加重试机制。
14. **Smaller Pixel Formats** Android的Heap空间是不会自动做兼容压缩的,意思就是如果Heap空间中的图片被收回之后,这块区域并不会和其他已经回收过的区域做重新排序合并处理,那么当一个更大的图片需要放到heap之前,很可能找不到那么大的连续空闲区域,那么就会触发GC,使得heap腾出一块足以放下这张图片的空闲区域,如果无法腾出,就会发生OOM。
15. **Smaller PNG Files** 尽量减少PNG图片的大小是Android里面很重要的一条规范。相比起JPEG,PNG能够提供更加清晰无损的图片,但是PNG格式的图片会更大,占用更多的磁盘空间。到底是使用PNG还是JPEG,需要设计师仔细衡量,对于那些使用JPEG就可以达到视觉效果的,可以考虑采用JPEG即可。
16. **Pre-scaling Bitmaps** 对bitmap做缩放,这也是Android里面最遇到的问题。对bitmap做缩放的意义很明显,提示显示性能,避免分配不必要的内存。Android提供了现成的bitmap缩放的API,叫做createScaledBitmap()
17. **Re-using Bitmaps** 使用inBitmap属性可以告知Bitmap解码器去尝试使用已经存在的内存区域,新解码的bitmap会尝试去使用之前那张bitmap在heap中所占据的pixel data内存区域,而不是去问内存重新申请一块区域来存放bitmap。利用这种特性,即使是上千张的图片,也只会仅仅只需要占用屏幕所能够显示的图片数量的内存大小。
18. **The Performance Lifecycle** Gather:收集数据,Insight:分析数据,Action:解决问题
#### [Android性能优化典范 - 第3季](http://hukai.me/android-performance-patterns-season-3/)
1. **Fun with ArrayMaps** 为了解决HashMap更占内存的弊端,Android提供了内存效率更高的ArrayMap。它内部使用两个数组进行工作,其中一个数组记录key hash过后的顺序列表,另外一个数组按key的顺序记录Key-Value值
2. **Beware Autoboxing** 有时候性能问题也可能是因为那些不起眼的小细节引起的,例如在代码中不经意的“自动装箱”。我们知道基础数据类型的大小:boolean(8 bits), int(32 bits), float(32 bits),long(64 bits),为了能够让这些基础数据类型在大多数Java容器中运作,会需要做一个autoboxing的操作,转换成Boolean,Integer,Float等对象
3. **SparseArray Family Ties** 为了避免HashMap的autoboxing行为,Android系统提供了SparseBoolMap,SparseIntMap,SparseLongMap,LongSparseMap等容器。
4. **The price of ENUMs** Android官方强烈建议不要在Android程序里面使用到enum。
5. **Trimming and Sharing Memory** Android系统提供了一些回调来通知应用的内存使用情况,通常来说,当所有的background应用都被kill掉的时候,forground应用会收到onLowMemory()的回调。在这种情况下,需要尽快释放当前应用的非必须内存资源,从而确保系统能够稳定继续运行。Android系统还提供了onTrimMemory()的回调,当系统内存达到某些条件的时候,所有正在运行的应用都会收到这个回调
6. **DO NOT LEAK VIEWS** 避免使用异步回调,避免使用Static对象,避免把View添加到没有清除机制的容器里面
7. **Location & Battery Drain** 其中存在的一个优化点是,我们可以通过判断返回的位置信息是否相同,从而决定设置下次的更新间隔是否增加一倍,通过这种方式可以减少电量的消耗
8. **Double Layout Taxation** 布局中的任何一个View一旦发生一些属性变化,都可能引起很大的连锁反应。例如某个button的大小突然增加一倍,有可能会导致兄弟视图的位置变化,也有可能导致父视图的大小发生改变。当大量的layout()操作被频繁调用执行的时候,就很可能引起丢帧的现象。
9. **Network Performance 101** 减少移动网络被激活的时间与次数,压缩传输数据
10. **Effective Network Batching** 发起网络请求与接收返回数据都是比较耗电的,在网络硬件模块被激活之后,会继续保持几十秒的电量消耗,直到没有新的网络操作行为之后,才会进入休眠状态。前面一个段落介绍了使用Batching的技术来捆绑网络请求,从而达到减少网络请求的频率。那么如何实现Batching技术呢?通常来说,我们可以会把那些发出的网络请求,先暂存到一个PendingQueue里面,等到条件合适的时候再触发Queue里面的网络请求。
11. **Optimizing Network Request Frequencies** 前面的段落已经提到了应该减少网络请求的频率,这是为了减少电量的消耗。我们可以使用Batching,Prefetching的技术来避免频繁的网络请求。Google提供了GCMNetworkManager来帮助开发者实现那些功能,通过提供的API,我们可以选择在接入WiFi,开始充电,等待移动网络被激活等条件下再次激活网络请求。
12. **Effective Prefetching** 类似上面的情况会频繁触发网络请求,但是如果我们能够预先请求后续可能会使用到网络资源,避免频繁的触发网络请求,这样就能够显著的减少电量的消耗。可是预先获取多少数据量是很值得考量的,因为如果预取数据量偏少,就起不到减少频繁请求的作用,可是如果预取数据过多,就会造成资源的浪费。
#### [Android性能优化典范 - 第4季](http://hukai.me/android-performance-patterns-season-4/)
1. **Cachematters for networking** 想要使得Android系统上的网络访问操作更加的高效就必须做好网络数据的缓存。这是提高网络访问性能最基础的步骤之一。从手机的缓存中直接读取数据肯定比从网络上获取数据要更加的便捷高效,特别是对于那些会被频繁访问到的数据,需要把这些数据缓存到设备上,以便更加快速的进行访问。
2. **Optimizing Network Request Frequencies** 首先我们要对网络行为进行分类,区分需要立即更新数据的行为和其他可以进行延迟的更新行为,为不同的场景进行差异化处理。其次要避免客户端对服务器的轮询操作,这样会浪费很多的电量与带宽流量。解决这个问题,我们可以使用Google Cloud Message来对更新的数据进行推送。然后在某些必须做同步的场景下,需要避免使用固定的间隔频率来进行更新操作,我们应该在返回的数据无更新的时候,使用双倍的间隔时间来进行下一次同步。最后更进一步,我们还可以通过判断当前设备的状态来决定同步的频率,例如判断设备处于休眠,运动等不同的状态设计各自不同时间间隔的同步频率。
3. **Effective Prefetching** 到底预取多少才比较合适呢?一个比较普适的规则是,在3G网络下可以预取1-5Mb的数据量,或者是按照提前预期后续1-2分钟的数据作为基线标准。在实际的操作当中,我们还需要考虑当前的网络速度来决定预取的数据量,例如在同样的时间下,4G网络可以获取到12张图片的数据,而2G网络则只能拿到3张图片的数据。所以,我们还需要把当前的网络环境情况添加到设计预取数据量的策略当中去。判断当前设备的状态与网络情况,可以使用前面提到过的GCMNetworkManager。
4. **Adapting to Latency** 一个典型的网络操作行为,通常包含以下几个步骤:首先手机端发起网络请求,到达网络服务运营商的基站,再转移到服务提供者的服务器上,经过解码之后,接着访问本地的存储数据库,获取到数据之后,进行编码,最后按照原来传递的路径逐层返回。常来说,我们可以把网络请求延迟划分为三档:例如把网络延迟小于60ms的划分为GOOD,大于220ms的划分为BAD,介于两者之间的划分为OK(这里的60ms,220ms会需要根据不同的场景提前进行预算推测)。
5. **Minimizing Asset Payload** 为了能够减小网络传输的数据量,我们需要对传输的数据做压缩的处理,这样能够提高网络操作的性能。首先需要做的是减少图片的大小,其次需要做的是减少序列化数据的大小。
6. **Service Performance Patterns** Service是Android程序里面最常用的基础组件之一,但是使用Service很容易引起电量的过度消耗以及系统资源的未及时释放。避免错误的使用Service,例如我们不应该使用Service来监听某些事件的变化,不应该搞一个Service在后台对服务器不断的进行轮询(应该使用Google Cloud Messaging)。如果已经事先知道Service里面的任务应该执行在后台线程(非默认的主线程)的时候,我们应该使用IntentService或者结合HanderThread,AsycnTask Loader实现的Service。
7. **Removing unused code** Android为我们提供了Proguard的工具来帮助应用程序对代码进行瘦身,优化,混淆的处理。它会帮助移除那些没有使用到的代码,还可以对类名,方法名进行混淆处理以避免程序被反编译。
8. **Removing unused resources** 所幸的是,我们可以使用Gradle来帮助我们分析代码,分析引用的资源,对于那些没有被引用到的资源,会在编译阶段被排除在APK安装包之外,要实现这个功能,对我们来说仅仅只需要在build.gradle文件中配置shrinkResource为true就好了
9. **Perf Theory: Caching** 当我们讨论性能优化的时候,缓存是最常见最有效的策略之一。无论是为了提高CPU的计算速度还是提高数据的访问速度,在绝大多数的场景下,我们都会使用到缓存。
10. **Perf Theory: Approximation(近似法)** 例如使用一张比较接近实际大小的图片来替代原图,换取更快的加载速度。所以对于那些对计算结果要求不需要十分精确的场景,我们可以使用近似法则来提高程序的性能。
11. **Perf Theory: Culling(遴选,挑选)** 一个提高性能的方法是逐步对数据进行过滤筛选,减小搜索的数据集,以此提高程序的执行性能。例如我们需要搜索到居住在某个地方,年龄是多少,符合某些特定条件的候选人,就可以通过逐层过滤筛选的方式来提高后续搜索的执行效率。
12. **Perf Theory: Threading** 使用多线程并发处理任务,从某种程度上可以快速提高程序的执行性能。对于Android程序来说,主线程通常也成为UI线程,需要处理UI的渲染,响应用户的操作等等。
13. **Perf Theory: Batching** 网络请求的批量执行是另外一个比较适合说明batching使用场景的例子,因为每次发起网络请求都相对来说比较耗时耗电,如果能够做到批量一起执行,可以大大的减少电量的消耗。
14. **Serialization performance** 数据序列化的行为可能发生在数据传递过程中的任何阶段,例如网络传输,不同进程间数据传递,不同类之间的参数传递,把数据存储到磁盘上等等。通常情况下,我们会把那些需要序列化的类实现Serializable接口(如下图所示),但是这种传统的做法效率不高,实施的过程会消耗更多的内存。但是我们如果使用GSON库来处理这个序列化的问题,不仅仅执行速度更快,内存的使用效率也更高。Android的XML布局文件会在编译的阶段被转换成更加复杂的格式,具备更加高效的执行性能与更高的内存使用效率。
15. **Smaller Serialized Data** 数据呈现的顺序以及结构会对序列化之后的空间产生不小的影响。
16. **Caching UI data** 缓存UI界面上的数据,可以采用方案有存储到文件系统,Preference,SQLite等等,做了缓存之后,这样就可以在请求数据返回结果之前,呈现给用户旧的数据,而不是使用正在加载的方式让用户什么数据都看不到,当然在请求网络最新数据的过程中,需要有正在刷新的提示。至于到底选择哪个方案来对数据进行缓存,就需要根据具体情况来做选择了。
17. **CPU Frequency Scaling** 调节CPU的频率会执行的性能产生较大的影响,为了最大化的延长设备的续航时间,系统会动态调整CPU的频率,频率越高执行代码的速度自然就越快。我们可以使用Systrace工具来导出CPU的执行情况,以便帮助定位性能问题。
#### [Android性能优化典范 - 第5季](http://hukai.me/android-performance-patterns-season-5/)
1. **Threading Performance** AsyncTask: 为UI线程与工作线程之间进行快速的切换提供一种简单便捷的机制。适用于当下立即需要启动,但是异步执行的生命周期短暂的使用场景。HandlerThread: 为某些回调方法或者等待某些任务的执行设置一个专属的线程,并提供线程任务的调度机制。ThreadPool: 把任务分解成不同的单元,分发到各个不同的线程上,进行同时并发处理。IntentService: 适合于执行由UI触发的后台Service任务,并可以把后台任务执行的情况通过一定的机制反馈给UI。
2. **Understanding Android Threading** 通常来说,一个线程需要经历三个生命阶段:开始,执行,结束。线程会在任务执行完毕之后结束,那么为了确保线程的存活,我们会在执行阶段给线程赋予不同的任务,然后在里面添加退出的条件从而确保任务能够执行完毕后退出。
3. **Memory & Threading** 不要在任何非UI线程里面去持有UI对象的引用。系统为了确保所有的UI对象都只会被UI线程所进行创建,更新,销毁的操作,特地设计了对应的工作机制(当Activity被销毁的时候,由该Activity所触发的非UI线程都将无法对UI对象进行操作,否者就会抛出程序执行异常的错误)来防止UI对象被错误的使用。
4. **Good AsyncTask Hunting** AsyncTask虽然提供了一种简单便捷的异步机制,但是我们还是很有必要特别关注到他的缺点,避免出现因为使用错误而导致的严重系统性能问题。
5. **Getting a HandlerThread** HandlerThread比较合适处理那些在工作线程执行,需要花费时间偏长的任务。我们只需要把任务发送给HandlerThread,然后就只需要等待任务执行结束的时候通知返回到主线程就好了。另外很重要的一点是,一旦我们使用了HandlerThread,需要特别注意给HandlerThread设置不同的线程优先级,CPU会根据设置的不同线程优先级对所有的线程进行调度优化。
6. **Swimming in Threadpools** 线程池适合用在把任务进行分解,并发进行执行的场景。通常来说,系统里面会针对不同的任务设置一个单独的守护线程用来专门处理这项任务。
7. **The Zen of IntentService** 默认的Service是执行在主线程的,可是通常情况下,这很容易影响到程序的绘制性能(抢占了主线程的资源)。除了前面介绍过的AsyncTask与HandlerThread,我们还可以选择使用IntentService来实现异步操作。IntentService继承自普通Service同时又在内部创建了一个HandlerThread,在onHandlerIntent()的回调里面处理扔到IntentService的任务。所以IntentService就不仅仅具备了异步线程的特性,还同时保留了Service不受主页面生命周期影响的特点。
8. **Threading and Loaders** 当启动工作线程的Activity被销毁的时候,我们应该做点什么呢?为了方便的控制工作线程的启动与结束,Android为我们引入了Loader来解决这个问题。我们知道Activity有可能因为用户的主动切换而频繁的被创建与销毁,也有可能是因为类似屏幕发生旋转等被动原因而销毁再重建。在Activity不停的创建与销毁的过程当中,很有可能因为工作线程持有Activity的View而导致内存泄漏(因为工作线程很可能持有View的强引用,另外工作线程的生命周期还无法保证和Activity的生命周期一致,这样就容易发生内存泄漏了)。除了可能引起内存泄漏之外,在Activity被销毁之后,工作线程还继续更新视图是没有意义的,因为此时视图已经不在界面上显示了。
9. **The Importance of Thread Priority** 在Android系统里面,我们可以通过android.os.Process.setThreadPriority(int)设置线程的优先级,参数范围从-20到24,数值越小优先级越高。Android系统还为我们提供了以下的一些预设值,我们可以通过给不同的工作线程设置不同数值的优先级来达到更细粒度的控制。
10. **Profile GPU Rendering : M Update** 从Android M系统开始,系统更新了GPU Profiling的工具来帮助我们定位UI的渲染性能问题。早期的CPU Profiling工具只能粗略的显示出Process,Execute,Update三大步骤的时间耗费情况。
#### [官方性能优化系列教程](https://www.youtube.com/playlist?list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE)
### 架构分析
[MVVM](http://tech.meituan.com/android_mvvm.html)
[MVP](https://code.tutsplus.com/series/how-to-adopt-model-view-presenter-on-android--cms-1012)
### 阿里面试题
#### 进程间通信方式
1. 通过Intent在Activity、Service或BroadcastReceiver间进行进程间通信,可通过Intent传递数据
2. AIDL方式
3. Messenger方式
4. 利用ContentProvider
5. Socket方式
6. 基于文件共享的方式
#### 什么是协程
我们知道多个线程相对独立,有自己的上下文,切换受系统控制;而协程也相对独立,有自己的上下文,但是其切换由自己控制,由当前协程切换到其他协程由当前协程来控制。
#### 内存泄露是怎么回事
由忘记释放分配的内存导致的
#### 程序计数器,引到了逻辑地址(虚地址)和物理地址及其映射关系
虚拟机中的程序计数器是Java运行时数据区中的一小块内存区域,但是它的功能和通常的程序计数器是类似的,它指向虚拟机正在执行字节码指令的地址。具体点儿说,当虚拟机执行的方法不是native的时,程序计数器指向虚拟机正在执行字节码指令的地址;当虚拟机执行的方法是native的时,程序计数器中的值是未定义的。另外,程序计数器是线程私有的,也就是说,每一个线程都拥有仅属于自己的程序计数器。
#### 数组和链表的区别
数组是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素。但是如果要在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中。同样的道理,如果想删除一个元素,同样需要移动大量元素去填掉被移动的元素。如果应用需要快速访问数据,很少或不插入和删除元素,就应该用数组。
链表恰好相反,链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起。比如:上一个元素有个指针指到下一个元素,以此类推,直到最后一个元素。如果要访问链表中一个元素,需要从第一个元素开始,一直找到需要的元素位置。但是增加和删除一个元素对于链表数据结构就非常简单了,只要修改元素中的指针就可以了。如果应用需要经常插入和删除元素你就需要用链表数据结构了。
#### 二叉树的深度优先遍历和广度优先遍历的具体实现
http://www.i3geek.com/archives/794
#### 堆的结构
年轻代(Young Generation)、年老代(Old Generation)和持久代(Permanent
Generation)。其中持久代主要存放的是Java类的类信息,与垃圾收集要收集的Java对象关系
不大。年轻代和年老代的划分是对垃 圾收集影响比较大的。
#### bitmap对象的理解
http://blog.csdn.net/angel1hao/article/details/51890938
#### 什么是深拷贝和浅拷
浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值,这个方式被称为浅拷贝。
深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所有非引用成员变量值,还要为引用类型的成员变量创建新的实例,并且初始化为形式参数实例值。这个方式称为深拷贝
#### 对象锁和类锁是否会互相影响
对象锁:Java的所有对象都含有1个互斥锁,这个锁由JVM自动获取和释放。线程进入synchronized方法的时候获取该对象的锁,当然如果已经有线程获取了这个对象的锁,那么当前线程会等待;synchronized方法正常返回或者抛异常而终止,JVM会自动释放对象锁。这里也体现了用synchronized来加锁的1个好处,方法抛异常的时候,锁仍然可以由JVM来自动释放。
类锁: 对象锁是用来控制实例方法之间的同步,类锁是用来控制静态方法(或静态变量互斥体)之间的同步。其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的。我们都知道,java类可能会有很多个对象,但是只有1个Class对象,也就是说类的不同实例之间共享该类的Class对象。Class对象其实也仅仅是1个java对象,只不过有点特殊而已。由于每个java对象都有1个互斥锁,而类的静态方法是需要Class对象。所以所谓的类锁,不过是Class对象的锁而已。获取类的Class对象有好几种,最简单的就是MyClass.class的方式。
类锁和对象锁不是同1个东西,一个是类的Class对象的锁,一个是类的实例的锁。也就是说:1个线程访问静态synchronized的时候,允许另一个线程访问对象的实例synchronized方法。反过来也是成立的,因为他们需要的锁是不同的。
#### looper架构
http://wangkuiwu.github.io/2014/08/26/MessageQueue/
#### 自定义控件原理
http://www.jianshu.com/p/988326f9c8a3
#### binder工作原理
Binder是客户端和服务端进行通讯的媒介
#### ActivityThread,Ams,Wms的工作原理
ActivityThread: 运行在应用进程的主线程上,响应 ActivityManangerService 启动、暂停Activity,广播接收等消息。
ams:统一调度各应用程序的Activity、内存管理、进程管理
#### Java中final,finally,finalize的区别
- final 用于声明属性,方法和类, 分别表示属性不可变, 方法不可覆盖, 类不可继承
- finally 是异常处理语句结构的一部分,表示总是执行
- finalize 是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等. JVM不保证此方法总被调用
#### 一个文件中有100万个整数,由空格分开,在程序中判断用户输入的整数是否在此文件中。说出最优的方法
#### 两个进程同时要求写或者读,能不能实现?如何防止进程的同步?
#### volatile 的意义?
防止CPU指令重排序
#### 单例
```java
public class Singleton{
private volatile static Singleton mSingleton;
private Singleton(){
}
public static Singleton getInstance(){
if(mSingleton == null){\\A
synchronized(Singleton.class){\\C
if(mSingleton == null)
mSingleton = new Singleton();\\B
}
}
return mSingleton;
}
}
```
#### Given a string, determine if it is a palindrome(回文,如果不清楚,按字面意思脑补下), considering only alphanumeric characters and ignoring cases.
For example, "A man, a plan, a canal: Panama" is a palindrome. "race a car" is not a palindrome.
Note: Have you consider that the string might be empty? This is a good question to ask during an interview. For the purpose of this problem, we define empty string as valid palindrome.
```java
public boolean isPalindrome(String palindrome){
char[] palindromes = palidrome.toCharArray();
if(palindromes.lengh == 0){
return true
}
Arraylist temp = new Arraylist();
for(int i=0;i'a' && palindromes[i]<'z')||palindromes[i]>'A' && palindromes[i]<'Z')){
temp.add(palindromes[i].toLowerCase());
}
}
for(int i=0;i 来源:微信公众号「LJ 说」,id:「LjNotes」。
“你居然要从腾讯离职了!?”
这是身边朋友得知我要离开后的反应,似乎大家都难以理解这样的决定。
从行业环境来看,中国互联网正处于一派繁荣之境;从公司形势来看,也正要准备大刀阔斧地干一番大事业;从个人发展来看,自己在公司也会担任越来越重要的角色。
所有的环境都是好的,更加显得离职的决策不理智。
HR 系统弹窗给出最后的挽留:你确定要提交离职申请吗?
经过各种综合考虑后,我还是点了“确定”按钮,正式从工作了三年的腾讯离职。
一直有朋友问,在腾讯的工作感觉怎么样?
关于这个问题,从来没有好好思考过,觉得当局者迷,尽量做好手上工作就是了。
现在终于有时间梳理一番。
回想起这几年的经历,既有取得成就的喜悦,也有遭受挫折的失落,个中唏嘘,在离开之际,希望与你分享一二。
## 大公司之病

3 年前,我面试完,从腾讯出来,融入了深南大道熙熙攘攘的下班人群中。
在过天桥的时候,我特意拍了一张腾大的夜景,留作纪念,表示我终于要到腾讯上班了。
虽然还没正式通知,不过凭着面试反馈,我知道自己终究还是要进入这家梦寐已久的公司了。
3 年后,同样是腾讯大厦,我站的位置已经发生改变。
从外面的仰望变成了里面的远眺,心情体会也随之改变。
只要在大型企业工作过的人,都会被大公司病深深困扰着。
### 你厉害还是平台厉害
BAT 的光环是非常牛逼的,它意味着你进入国内任何一家互联网公司都畅通无阻,它意味着你可以对外分享自己的经验和心得,享受着他人崇拜的目光。
然而,在一家几万人的巨头企业,几乎每个人都是一个普通员工,毫无存在感可言,其中滋味就如人饮水,冷暖自知。
看《权利的游戏》,我在想,龙妈拥有三条喷火巨龙,为什么还要四处斡旋、拉帮结派,直接骑着三条龙到处喷火,不早就征服七大王国了吗。
直到有一幕场景,大龙“Drogo”在斗兽场,被很多小兵拿着矛乱刺,身受重伤,我才反应过来,不管龙妈和她的三条龙再厉害,始终赢不了训练有素的军队。
这就是大企业的一个缩影。
公司征战,并不需要一个能斗天斗地的英雄,而是需要一支能打仗的队伍。
尽管在招聘的时候,大公司往往会筛选出最厉害的一批人,但这并不代表着每个人都举足轻重。
事实上,不管你是清北名校毕业光环加持,还是二三本拼搏多年进入大平台,公司想要的结果其实都一样。
公司希望每个一线的员工坚守着自己一亩三分地,不需要你把控全局,不需要你战略思考,只要努力地当好螺丝钉。
每个人手上分到一小块工作,然后在未来的很长一段时间内,不断地重复着这个工作,成为这个小模块的“专家”。
负责个性化皮肤的,可能几年内都在钻研怎么把更多皮肤卖出去;写文案的,长年累月地追着微博热点写文章;做渠道运营的,风雨无阻地盯着各个渠道把自己的广告上线……
并不是说公司不重视个人创造力,恰恰相反,公司希望的是大家发挥创造力,把自己变成更可靠的螺丝钉,成为一个更靠谱的零部件。
全公司上下形成一股合力,用军队的方式赢得战争。
赢的方式,不是靠武艺高超的英雄,而是让所有人在统一指挥下,移动、格挡、举矛、刺杀,每个动作都如此简单,但千军万马在一起,就能击破对手。
这也就意味着铁打的营盘流水的兵,在大平台工作,一件事情成功之后,很容易让人觉得是因为自己牛逼,其实真正的原因是平台的力量。
同一件事情,放张三能做成,放李四也 OK。
在这里,你不是英雄,你是一个日夜训练着重复动作的小兵。更可悲的是,对于绝大部分人而言,公司压根没计划让你成为一个英雄或将军。
你只是千军万马中的一员,平台缺少了你,马上能找到一个人填补上去,而你一旦离开了平台,就会发现很难再复制以往的成功。
### 无尽的流程和制度
把大象放进冰箱一共要三步:打开冰箱门、放进大象、关上冰箱门。
但是在大公司,这个流程就远不止三步了。
你要给个报告写清楚把大象放到冰箱的意义和重要性,搞清楚哪种冰箱放哪种大象,把开门动作、放大象的路线描绘清楚,把关门的力度写出来,拿着完整的方案找项目经理去排期,直到有人力来把大象放进冰箱。
一个产品或功能,从无到有需要经历漫长的流程。一个大企业的员工,每天为制度所困。
某些产品一两年内都没有可感知的外观变化,例如微信,有人就会问这么多工作人员都在忙些什么呢。
其实工作人员都很忙,忙在了“流程”和“制度”上。
当你们是一个三五人的创业团队,大家就坐在一起,有事情吼一声就可以。比如说想要做一个功能改变,可能就是抬起头跟对面的开发说要怎么怎么改,半天之后就能在产品上看到了。线上反馈好,就保留,反馈不好就改回来,不过是几个小时的事情。
然而,对于一个巨型产品来说,所有人的 80% 精力并不是在做“正经的工作”。
每个产品经理电脑上都躺着十几份写好的需求文档,在等候着漫长的项目排期。等排期终于到了的时候,有的需求已经不再适用了,或者写它的产品经理已经走了,要是需求和人都还在的话,那就要谢天谢地,守得云开见明月,终于要上线了。
每个开发脑子里都存放着许多改进方案,很多可能就是改一行代码的事情,但是不能擅自改动,所有的改动都应该以产品需求为主,否则出了问题那就闯大祸了。
遇到跨团队、跨部门沟通,更加是考验人的忍耐力,找一个接口人要花上大半天。对方要么不回复,要么回一句“这不是我负责的”。好不容易对接上了,好家伙,群里面出现四五个接口人,每个人都得交待一遍来龙去脉。
除此之外,每个人身上还背负着各种会议、分享、周报月报,PPT 模板成了最受欢迎的文件。
能够安心写代码、写需求的时间,算下来也许还真的没有20%。但工作还是要完成的,于是就只好加班加班,成为了互联网行业的一大特色。
流程制度是一个好东西,也是一个坏东西。
好的地方在于保证企业这条大船高效率地运转,坏的地方在于牺牲了个人效率来满足集体的效率。
### 逃不过的修罗场
对于大企业工作的朋友,是万万不能问什么时候升职的。就像不能问魏忠贤魏公公什么时候生个小孩,这是要杀头的大罪。
越是受过高等教育的人,越是想着要改变世界。当初怀着远大的志向进入大公司,想要施展拳脚做一件不凡的事情。
但几年后,大多数人的志气早已被磨消。修身齐家治国平天下,他们连修身都做不好。
眼看着身边的朋友在中小公司鹤立鸡群,一路扶摇直上,成为有决策权的管理者,而自己只是数年如一日地坐在小隔间,每周想着如何跟老板汇报工作。
也许离 CEO 的办公室只有十米不到的距离,也许每天还能跟几个高管寒暄一下,似乎离他们好近,但是心里明白这种阶层的差距是一道无法逾越的鸿沟。
HR 在设计个人发展体系的时候,给每个人都提供了两种路径,一个是专业能力晋级,一个是管理职能晋升。
所有人都能在专业能力通道上一步步地打怪升级,最终成为高级产品经理、高级工程师,甚至专家 xx。
但是在管理通道上,坑位就那么几个,而且大企业内具有管理头衔的人流动性远远低于普通员工,于是国企中“一个萝卜一个坑”的现象在创新的互联网企业同样存在。
不少人已经工作十多年,但仍然是一线普通员工。
至于谁能晋升,这个话题,不说也罢。
要是运气不好,赶上了“宫廷大戏”,轻则工作上举步维艰,重则随着失败一方的领导一起离开。
这里就是一个几万人的修罗场,陷于其中的人,个个都身不由己。
## 外面的世界很精彩?

前面说了那么多,你可能会以为我在痛陈大公司的弊端,但这并非我本意。
我并没有在真正意义上的创业团队工作过,但也有过小团队的经历,加上平时和不少创业团队的朋友交流,对小公司的辛酸也是略知一二。总结起来,不过是几个字:人少事杂、管理混乱、野蛮生长。
### 人少事杂
在小团队,可能出现最多的头衔是“全栈 xx”,这并不是说明他有多厉害,而是在一个人手不足的团队中,每个人可能都身兼数职。
写前端页面的,可能没人把写好的接口交给你,而是需要自己写服务器脚本、自己调优数据库,还得自己盯着运维数据,宕机了得马上修复。
做产品的,不是只打开 word 来写需求文档,用户调研、交互图得自己做,上线后的运营还得自己跟。
做运营的,更加是无所不包,大到策划一个线上活动,小到做客服回答用户的咨询。
每个人也很忙,似乎什么都能做。
这也是小团队吸引人的噱头,能对付过来的人,就成为一个真正的“全栈”,疲于奔命的人,就什么都做什么都学不精。
### 管理混乱
小团队是否意味着效率高呢,其实也可能存在更加胡乱的管理。
曾听朋友讲过他的经历。一个普通员工,需要同时向两个领导汇报,而两个领导还经常互掐,于是该朋友就一脸懵逼了,经常接收到两个完全相反的指令。
还有可能,前一周刚刚跟另外一个团队开完会,达成决定做个方案,下周再找他们就发现整个团队被老板裁撤了。
又或者,团队在短时间内爆发性增长,为了融资,为了数字,找来了一批新人,大家都面面相觑,不知道谁该做什么,本来公司也并不是因为业务需要而招新人,所以干脆大家都逛淘宝、刷微博。
如果说大公司内部的身不由己还有章可循,小公司的变化就是充满着惊喜。
### 野蛮生长
大公司令人艳羡的地方就是有很多现成的基础服务,而在小团队干活的人都会非常痛苦,大多时候都需要自己造轮子。
CDN 网络需要自己搭建,大数据平台需要自己开发,账号体系需要自己建设,支付系统需要从零开始……
一个最简单的例子,大公司有成熟的数据体系,每个可以看各种各样的报表,以便调整运营策略,但是小团队可能看个数据就需要提导数据的需求,等到一两周之后才能看到。
从一片荒芜中把业务从零开始做起来,是一件很锻炼人的事情,但其实背后更多的是资源浪费。
## 都是围城

万物皆有裂痕,要看到裂痕中照进来的光,而不是裂痕本身。
一位长者曾说过,一个人的命运啊,当然要靠自我奋斗,但也要考虑到历史进程。
历史的进程和外部的环境,都是我们所不能控制的,但是说到自我奋斗的话,大公司却提供了温暖的襁褓。
### 在正规化中成长
流程制度的反面就是“正规化”。
当有人问我要不要去大公司的时候,我都会回答,如果有合适的机会就去吧。不为别的,就为了体验这种正规化的流程制度。
管理两三个人的时候可以靠命令,管理二三十个人的时候可以凭个人魅力,管理几百人、上万人就只能依赖于流程制度了。
前面说过流程是牺牲个人效率满足集体效率,从个人成长而言,依然能从中学习到受益终身的东西。
你可以知道一个业务从零到一是怎么搭建团队的,各个团队通过什么样的流程进行配合,各司其职代表着每个环节都能产出精品,于是你就知道一个优秀的作品应该是怎么样的,以后碰到类似的场景就有经验了。
总而言之,身处在“正规军”当中,虽然自己只是其中的普通一员,但是也可以耳濡目染地学习到最顶尖的产品是如何打造出来的。
当然,前提是你有心去了解和学习。
### 站在巨人肩膀上
大公司汇聚了最优秀的资源,包括人才、技术、资金、经验等。
在平时,如果你想了解或钻研某一事物,往往能在内网上找到独家优质的经验分享。
更进一步,可以直接联系这个领域的高手咨询请教。内部使用的软件,上至 CEO 下至电脑维修小哥,都静静地躺在好友列表里,等着你联系。
在大公司工作的人,是真正的能做到聚焦于业务逻辑本身,而不用被琐碎的杂事打扰。
行政上,公司配备了饭堂、班车、体检、节假日福利、家人福利等等,让你能安心地工作。
业务上,有专门的基础服务部门,IT设备、开发组件、大数据平台、安全防御、用户数据等等,都可以拿来马上用。
个人成长上,虽然不是每个人都能平步青云,但是完善的薪酬福利让每个人都能获得相对合理的回报,各种培训让大家都能适当跳出舒适区获得成长。
这些基础服务都是十多年无数人的心血积累,可想而知,站在这样一个巨人的肩膀上,新人可以获得更高速的成长。
### 围城里外的人
前段时间见到一位大学好友,在外闯荡多年,辗转了几个公司,现在已经是带着小团队的“总监”。
我说,这几年间你升职加薪,走上人生巅峰,让人好生羡慕啊。最重要的是可以根据自己想法去实施一些方案,而不会被束手束脚,跟随着高速成长的公司也能让自己的思维和能力快速成长。
而他谈到小公司的经历,眼中难掩失落,反而羡慕大公司内提供的坚实后盾。更让我惊讶的是他其实已经在找BAT的机会,准备年后就进入巨头企业了,即使放弃管理者的头衔做一个普通员工。
所以你看啊,大公司就是一座围城,外面的人想进去,里面的人想出来。
而他们想进去或想出来的原因,其实都是一样的东西。
================================================
FILE: docs/android/Android-Interview/经验分享/我为什么离开锤子科技?.md
================================================
我在2015年3月入职锤子科技,最近几天离职,现在特别想把这不到两年的时间里的经历和我对这家公司的想法写下来。最近一段时间公司发生了大面积的裁员,但是我并不属于这一次陆陆续续的裁员的范围,而是自己提出离职的,最后发生了一些不愉快的事情,后面也会提到。
我2012年本科毕业的时候对自己要去什么样的公司完全没有概念,我的专业是软件工程,但是当时不想去任何一家IT 公司,于是我选择了出国留学。锤子科技是2012年5月份创立的,我在大学期间是一名典型的罗粉,但就是这样我还是没有太关心这家由老罗创立的公司,心里甚至觉得老罗有玩票的嫌疑,而且那个时候出国的手续基本办完了,所以也有点行色匆匆的意思,就没有特别关注这家公司。
锤子科技的第一个ROM是在2013年3月份发布的,当时人在国外,全程看了发布会的回放,我第一时间刷了这个ROM,虽然问题多多,但是非常喜欢这个系统的很多细节。我第一次动念头想要去锤子科技上班是T1 发布会之后,当时T1 发布之后我也是属于第一批预定的用户。因为我是南方人,回国后找工作简历直接先投了锤子科技,因为如果不行,我是不太可能来北京工作的。当然从面试到最后入职都很顺利,我入职的时候差不多是T2 这个项目刚开始的时候。说到当时入职锤子科技我还是比较感激公司的,因为这是我的第一份工作,之前没有任何Android 相关的开发经验。入职之后知道公司在当时项目非常紧张,需要来了就能干活的人·。想到公司愿意招我这个新人,我心里是有几分侥幸和感谢的。
锤子科技在科技圈的公司里可能算名气比较大的企业了,对于它的各种说法和想法都很多,这两年时间确实和公司一起经历了很多。但是在这个时候我最想提的一个点是公司的一次营销活动,就是让大家参与进来以“天生骄傲”为题写一些自己天生骄傲的经历。我觉得这个可能是这个公司最吸引我的点,也是我作为一个罗粉,老罗最吸引我的点,就是有一种永远要做正确的事情的骄傲。
我还记得的一个“天生骄傲”的故事是老罗转发的一则,一个人因为工作原因用车很多,他开的是自己的车但是公司会给他报油费,他每次会特别留心记下哪些是因为工作原因用车,哪些不是,每次向公司报销的时候,会去掉平时非工作用车的里程数。·我记得原作者的表达要更让我震撼一些,我自己转述的有点啰嗦,反正意思是差不多的。刚到公司那一会我的确相信这是一家天生骄傲的公司,并且可能是由内而外的,并不简单是公司的营销策略。
因为就我当时的观察,来锤子科技入职的同事,有一部分是和我一样的罗粉,他们可能是被相同的价值观吸引来的。还有一部分在入职之前并不知道老罗是谁,但是加入公司之后对这种价值观是很认同的,当然这肯定不包括所有的同事,但我想在我入职那会儿应该包括了大部分同事。但是现在是不是这样,甚至是否公司还能相信自己天生骄傲,我都是不敢确信的。
我一直觉得,我的性格是那种,如果在有选择自由的情况下,还愿意做自己不喜欢做的事情,那肯定是有一种我认为正确的价值观或者理想之类的东西在激励我,我相信这也是很多人的情况。我在锤子科技工作的第一年,有一段时间项目特别紧,几乎每天都要工作到9 到10 点钟。我是很不喜欢加班的,工作做完都是想尽早回家做自己的事情,毕竟工作这么忙了,难得有时间干自己喜欢干的事情,说白了我理解的工作就是自己生活的保障,并没有什么特别大的野心要在并不是自己兴趣的工作上有什么作为。虽然这样,只要是觉得有必要在当天做完的工作,不管到多晚我都会做完的,当时让我有这种决心的,可能就是那种对公司的认同感。
我入职的时候,面试我的软件副总裁是跟我说过公司的工作时间制度的,锤子科技是采用那种弹性工作制,虽然有一个规定的早十点到晚七点的工作时间,但是只要能保证工作做完,并不强制一定要十点到,七点走,但是如果规定时间内工作做不完,就得自觉加班。这是当时面试我的软件这一块的副总裁原话跟我说的。
说实话,我当时对这种工作制度的想法是很理想化的,非常认同,并且也是这么做的。刚入职那会安排我的工作是先理解代码,看文档,刚开始的一周我基本晚上都是7 点准时走,说实话一天时间里有些代码我翻来覆去能看两三遍,基本也都能看懂,而且我也不觉得再多看一两个小时效果会好,毕竟按我学习东西的节奏我不想一天时间看太多东西。但是第二周我们20几个人的组的经理马上找我谈话了,我立刻就意识到有些事情可能并不是我想象的那样,不过他最后给出的理由我也算勉强接受了,他给的理由是要和组里的同事保持步调一致,不然可能有时候找不到你。当然在之后差不多两年的工作时间里,我慢慢对弹性工作制的认识从理想化的状态变成了公司不愿意给加班费,因为所谓的弹性工作制就是一种可以让你每天加班到10点但是不用付薪水的制度。
关于工作时间,甚至做到了你没事情做也得在公司待着的地步,感觉就是如果7 点准时走会有人不爽,而这个不爽的人就是我们软件部门实际的负责人,这个人后来升到了软件副总裁的位置,在他升上去之前有些东西还处于含含糊糊的地带,等到他升上去了之后这些都变成了实质的制度。顺便一说,我在公司的两年多时间,弹性工作制从来都是从7 点往后弹的,这倒不是说我们真的有多忙,只是如果你每天的工作时间恰好只有9 个小时,那就会有人找你谈话,不管你的工作做没做完,做得好不好。
当然我还是愿意相信公司的很多同事是从理想化的角度来理解弹性工作制的,包括当时面试我的前副总裁,他是一位很和蔼的中年大叔,大概好像几个月前退休了。可是为什么在我眼里公司慢慢变得不那么骄傲了呢?甚至我现在确信公司已经不再有脸面在自己内部员工面前说我们是一家天生骄傲的公司了,为什么会变呢?这可能得好好说一说我们这个组的经理,从他可能能侧面说明这个问题的原因。
我们的这位经理是在原来他的经理升上去之后被提拔的,可能就是所谓的自己人吧,但是这个人到底能力怎么样,我觉得可能公司并没有明确考核过,或者甚至本身就没有考核这一步吧,毕竟我对公司管理不是很清楚。我们的软件组里其实并没有明确区分技术和管理的Leader,可以理解为我们的经理需要兼顾这两个方面的工作。
我们组大概维护手机软件部分的大大小小几个模块,锤子的软件部分可以说是很出彩的,但是说我们公司软件的技术多么牛逼,我真不敢说,因为我们的工作主要在于实现产品提出的需求,所以只要能实现了产品功能和性能上的需求,并没有人在意你是怎么实现的,至少我们组完全没有所谓软件架构,如果你负责的某一个小模块需要实现一个新需求,那么从设计方案到软件架构到coding很有可能都是你一个人完成的,公司很有可能没有第二个人知道你是怎么实现的。
这里说一下在我眼里我们组的经理每天的工作似乎就是满足于不挨他上级的骂,所以像整个组的bug 数量和新需求是否超期这些敏感数据是他最关心的。经常遇到的情况是,有一些bug 比较不好分析,或者需要仔细分析前因后果再做合理修改,但是他会在你分析bug 期间催你,经常用到的句式是:“某某,你那个bug 优先级比较高,快点看一下”,好像我们没有在看一样。而且有时候为了降低bug 数量,他还要经常帮我们解bug,有时候他不好意思让我们来加班,自己周六跑到公司解bug,然后我们周一来了发现他解得不对还要帮他擦屁股。倒不是说他技术有多差,只是组里那么多模块的代码他并不都熟悉。只要当天bug 数量降低了,他就满意了。不过话又说回来帮组里同事解bug 也算是他完成他技术Leader的工作吧。
另外虽然他是大组经理,但是其实下面按模块还是分了几个小组的,一般小组内的工作都是我们组长分的。我们小组组长的方式我是很认同的,有的时候他并不会主动给我们分bug,我们会自己从他那里取,这种方法看似放任,但其实我们组长是基于对我们的了解以及建立在这种了解之上的信任才这么做的,这种方式和公司的弹性工作制本质上是类似的,我觉得我们小组内这样合作的方式是很合适并且效率很高的。然而我们这位经理经常越过我们组长给我们分bug,有的时候他不太了解我们组内工作的分配,这样分bug反而会给组内同事造成困扰和压力。在工作的这几年时间内,我们的经理似乎对我们完全没有什么具体的了解,只是象征性的组织过几次团建,吃过几次饭而已。
我想这对他做管理方面的工作是很致命的,因为他要做的不只是每天催我们尽快解bug 而已。也有很多同事为他解释,说他是工程师出生,人又内向,所以有时候表达不到位,但是我想说的是,既然这样,他为什么能做20 几个人团队的经理?他似乎只是作为一个单向的通道存在,项目催的紧了,他就也来催我们一下。其实问题可能很简单,因为他是自己人,有的时候看到他被骂心里其实也很难受,但是这样能力的人当上经理,可能也是从侧面反映了,为什么我越来越感到公司不那么天生骄傲了。
我写这些的目的是很明确的,字里行间都能看出我是带着对公司管理层的怨恨的,因为他们可能就是锤子科技变成今天这样的罪魁祸首。这里说一下我离职的原因,今年公司软件团建的时候采取了很幼稚的形式(发小学的时候用的那种大红奖状,完了竟然没有奖金)奖励了一些加班时间最多,解bug数量最多的同事,我对这样的价值取向是很不认同的,因为这对不用加班就可以把工作做完甚至做得更好的同事是不公平的。
借着酒劲,我在公司群里说了很难听的话,顺便在当晚老罗和我们互动的微信群里问了过年红包还会不会发,结果是直接被退群。当然我后来很后悔,本来年后我也打算离职回老家了,还是忍一忍的好,毕竟后面经历的事情都非常荒诞。我再到公司的时候发现我的办公电脑被收走了,据说公司邮箱也被封了,据说是经理怕我再做出可怕的事情说出可怕的话。但是公司HR对我说公司的正常裁员已经结束了,也不会开我,这里我真想说难道让我把电脑搬回来继续干吗?我实在没有心力和公司耗下去,就自己提了离职。
我在职期间有一次经理找我聊天问我为什么最近工作不积极对公司有什么不满,我主要对他说了两点,一是公司取消本来就屈指可数的中秋节红包福利为什么不在公司层面通知一下(我和同事等了一天发红包,虽然锤科福利不多,但是逢年过节是直接给现金红包的,每次领红包都很开心),二是公司裁员为什么采取遮遮掩掩的态度,因为即使你不说外面的人一样知道,反而如果你对内部员工都不开诚布公,却会造成我们的恐慌和懈怠。
经理的答复是,这个不可能按你想象得那么理想化的,其他公司都是这样的。其实从他这番话也大概能了解为什么公司在做出这些决定的时候是这样的态度,因为公司的管理层似乎都被他这样的人占领了,他这句话在我看来好像就是锤子科技变得不再特殊的宣言吧。这里想告诉那些还想来锤子科技入职的朋友,了解一家公司不能光看公司自己的官博。
其实最后我还想说一句,锤子科技没有做错任何事情,因为站在公司角度来看,简直可以用为了盈利把所有问题都说通,但是这家公司已经不能再公开宣称自己天生骄傲了。也许正是被天生骄傲的价值观吸引来的,在离开的时候看清公司的现状才不会有任何遗憾。
================================================
FILE: docs/android/Android-Interview/经验分享/我为什么要离开华为?.md
================================================
> 原文链接:微信公众号[小李成长笔记]
到 9 月中旬,我在华为工作就满 6 年了。
同事听说我要离职,都很诧异。干的好好的啊,怎么突然说要走?
是啊,在现在的部门这么久了,人和事都很熟了,偶然有些小摩擦,都可以理解和接受。那为什么要走?
华为的 34,胶片文化,强绩效主义,部门墙,研发的低效等等这些,大家说过很多,就不再重复了。在我看来,这些都是微不足道的外因,我完全不认同,但可以理解。
真正推动我下定决心离开的还是内因:我那颗躁动不安的心。
在华为 3 年后,工作真的变成了工作。我常常想不起来昨天都做了些什么,只是模糊记得接了几个电话,帮助客户解决了几个问题,接入了几个莫名其妙的会议,回复了几个邮件。就这样一周过去了,一个月过去了,一年也过去了...
职级在升,工资在涨,年终奖也一年比一年多。可我却越来越心虚,越来越焦虑。
有 2 个我一直在争辩。一个我:现实点,这就是份工作,出卖时间,换取工资而已。干嘛期望那么多?另一个我:还这么年轻,就认命了吗。想想这些年你都干了些啥。每天处理些 stupid 问题,一年年重复自己,你还想像这样过多少年?
2 个我不停的争吵,日子在争吵中慢慢过去。
我知道不能再这样下去了,我要行动起来。我要做准备,离开这个安逸,不再成长的环境。
## 学习 Andoid 开发,重拾开发乐趣
16 年 Android 很火。我想学 Android 开发,买了《第一行代码》,边看书边搭环境,敲代码。买 vpn,用 google 搜索问题答案。关注了张哥的公众号「stormzhang」,知道了 stackoverflow 网站,github 网站。知道了开源软件。慢慢摸索,年底时也能做个还能用的 app 了。上传到应用商店,看到后台统计数据,每天有上百人下载,也有一些用户评论说不错,很喜欢。感觉很充实,很有成就感。
## 走出去,接触外面的世界
在华为的日子,每天按部就班工作,大家都很勤奋,专注。只需要埋头干活就可以了。慢慢的,好像和外面的世界隔离了。
当我第一次参加一个武汉产品经理交流活动,看到不大的会议室里坐满了上百名自发参加的朋友,被大家渴望知识和交流的态度感动,原来,我们身边还有这样一群人。
也参加过几次程序员自发组织的编程活动,大家一起结对编程,分享各自的工作流,推荐好用的工具和软件。能感受到他们对自己工作的热爱,让我羡慕感动。大周末的,放弃陪老婆孩子的休息时间,穿越大半个城市,和一群素未谋面的伙伴编程,绝对的真爱。当然,我们也成了网上的好朋友,虽然平时不咋联系,但大家知道,我们都是一类人。
## 关注互联网大 V,了解另一个世界
这期间关注了好多互联网行业大v的公众号。有耿直风趣的冯大辉,温和幽默的 MacTalk,黑白灰道都熟的 Caoz,硅谷 Airbnb 美女程序员 angena,Android 开发者帅比 stormzhang...每天看他们的文章,看他们写自己的从业感悟,写互联网行业的灰与黑,写曾经的迷茫和奋斗...真实有力,催人奋发。牛人都在奋斗,我还在温室里等死。
## 偶遇付费社群,见识网赚套路开眼界
转眼到了 17 年,好像一夜之间,知识付费就火了起来。
机缘巧合之下,加入了网友亦仁的生财有道小密圈,亲身经历了圈主 30 天收百万入圈费,见识圈主高超的运营手法,圈友大牛们分享的各种生财,吸粉套路。彻底改变了我对广告,对一些互联网业务的认知。
以往的我,对各种广告很不屑,认为都是骗人的。ppt 教程,excel 教程,这么 low 的东西,我可是 it 专家,哪看的上这些...
选择性无视,不看,不听,不想。
现在我会去想为什么会有这个,有多大市场,针对哪些人群,它们有哪些套路,有哪些值得学习的地方?这个事情有哪些门槛,如果我去做,可以吗。
脑袋瓜被慢慢的打开,不再是以前那个非黑即白,只有 0 和 1 的工科男死脑筋了。
还加入了刘大猫的财富移动城堡。了解到刘大猫,是看了他写的自传文,一个从高中开始就做网站,做淘宝客,做流量变现,27 岁就积累千万财富的大牛人。听他分享各种总结,经验和看法,思路清晰,态度诚恳。不满足现状,完全放弃还很赚钱的淘宝客生意,坚决转型公司和个人发展方向。让我汗颜,想到自己畏惧风险,待在舒适圈里不愿出来,无地自容。
还有好多社群,这些社群让我有了“近距离”观察和交流大牛的机会。他们就像存在你身边,就是你的一个学长或者朋友,你好像看着他们一步步成长为大牛,有时候会想,或许有一天,我也会牛起来。
## 开发微信小程序,体验流量的威力
网上和群友交流,不能光说不练,你总得有些拿的出手的东西。听再多的套路,经验不如亲自去实践下。
趁着小程序这股东风,自学开发了一个文字转语音的小工具。从 app 名的选择,简介,到搜索关键词,app 界面,功能都做了一些思考。开发上线后,收集用户反馈,和用户交流使用场景,慢慢的每天用户竟然有近 300 了,排名也一直上升到第一名。
有天看后台数据,访问量突然增加了 10 倍,当天新增用户 3.5 k。吓坏了,以为后台出统计故障了。原来是知晓程序公众号当天的文章推荐了。那天好多用户联系我,夸工具好用,确实帮他们解决了一些问题。好开心,体验了一把网红的感觉。
## 以后咋发展
写到这里,可能很多朋友会问,你写了这么多瞎折腾的经历,和你离职到底有啥关系呢,是要转行搞互联网产品开发吗?老实说,我也不肯定。
我只知道这些经历潜移默化改变了我,让我不再封闭,不再纠结。我庆幸这些经历让现在的我经过华为近 6 年的“摧残”后,心还火热,对未来还留有希望。
工作咋办呢,32 岁“高龄”了,还要去做程序员吗,还有公司要吗?没事,我觉得自己还年轻,如何做产品,还有很多可以学,我也相信,华为 6 年的经历,磨练,纠结,折腾,这些都是我未来宝贵的财富。
终于,我做了选择,不再纠结,重新出发。
================================================
FILE: docs/android/Android-Interview/经验分享/扫清Android面试障碍.md
================================================
## [扫清Android面试障碍](http://chaojimiaomiao.github.io/2016/05/08/%E6%89%AB%E6%B8%85Android%E9%9D%A2%E8%AF%95%E9%9A%9C%E7%A2%8D.html)
怎样快速突破初级瓶颈,变身高级开发?怎样在短时间内提高自我身价,月薪提高50%?你是否是个代码高手,面试中却发挥不出来,想进阶却摸不着头脑。博主在互联网行业摸爬滚打,百面成钢。特来总结与分享自己面试的心路历程和经验。
本系列将分为四大部分切入,包括**第一部分面试前的准备**:从长期来看要做点什么来提高自己的身价,短期内怎样迅速进入面试状态,以及如何准备简历才能吸引HR的眼球。**第二部分是安卓初级中级高级面试题**,大概会有几十个问题,基本覆盖了小白到大牛进阶的所有会被问到的问题。**第三部分是除了安卓经验**,你还会被问到哪些问题。**第四部分是关于 offer的选择**,以及一起探讨未来的职业规划。从这四部分看来,已经涵盖了一个程序员的方方面面。我一直觉得面试也是一种考试,只要是考试就有套路,有套路就能被总结,能被总结就能被练习,就好比高考模拟卷或者培训班,能教你的也就是反复练习。
先交代一下背景:博主本科毕业于国内某985大学,10年大二开始接触Android开发,参加了两届谷歌举办的全国大学生安卓应用竞赛并获奖。实习和工作都在上海的互联网公司做app开发。曾误入 iOS深处,沉醉不知归路。后来惊醒还是转投回安卓的世界中去。目前工作三年。本文的目的在于总结回顾上一波的面试,给未来的自己看看当时的努力与心情,更重要的是希望对业内还在迷茫中想要提高自己的开发们指点迷津。
前两个月,我面试了上海多家互联网公司,按规模上至阿里携程新美大,中至爱奇艺安居客B站平安科技,下至格瓦拉触宝科技蜻蜓fm,偏至招行信用卡微鲸科技等。并非有意要面那么多,只是一开始行动力太旺盛不小心简历投多了。秉承“自己投的简历,跪着也要面完”;以及想一窥上海互联网公司发展情况等多种心理下,横扫了各大Android面试题。经验积累了不少,从简历准备到技术准备再到扯淡环节,甚至于怎样针对不同的公司不同的面试官提出不一样的问题等等。
这整个过程不是一帆风顺的,就像给程序做优化一样,一点点完善、一点点让自己的表现趋近完美。我当时甚至会在家对着镜子针对可能被问到的问题,练习说话的语速和表情。请理解一个心机 girl 总会想太多,比如有的问题面试官或许会觉得这道题是他的杀手锏,那你就不要表现出一副做了充分准备、分分钟秒杀他的气势。毕竟咱面的是普通开发,最后还得在人手底下做事呢~ 这种情况下最好的办法是面露一点点思考与回忆交加的表情,一点点说出对方希望你说出来的答案;而不是一股脑全说完了。当然了,不同的面试官有不同的套路,比如我最欣赏携程的一个初面面试官,能感觉到那是一个智商超群的人。和聪明人讲话,你就不用再拐弯抹角了。Anyway,假如这个面试官最后露出了满意的笑容,那就恭喜你成功了
面试真的是个体力活,有两次我都想放弃了懒得再面了,让我继续坚持下去的除了有始有终的信念以外,还有照云兄一句“ 所谓自由就是随时拥有说’不’的权利。” 我理解就是给自己多一种选择。这一波面试下来,最遗憾的还是阿里几个想让我去的部门都在杭州,但我是上海人还要在交大在职读研。另外,上海的BAT Android岗位实在是太少了,腾讯基本就不在上海招。曾有冲动为了工作收起行囊就那么离家去杭州,但理智最终制止了我。阿里现在有点像软件界的华为,基本打来的电话都在晚上八点,有种血汗工厂的感觉。总体来说,上海的互联网公司规模都没成气候,还是中小企业居多。看了好几年上海互联网的起起落落,唯有”恨其不争“能形容这种感受了。PS:我最后选择了一份”钱多事少离家近“的工作:请不必问我现在何处,因为我一定会对公司和薪资守口如瓶。
话不多扯,上文的各种体会是为了下文抛砖引玉。这个系列的文章除了全面,更重要的补全除技术以外的短板。比如,当一个面试官问你:**你的职业规划是什么**。相信每个面试者都被问过。
大部分人的内心OS想必是:
what,职业规划是什么?
what,这个问题究竟有什么意义?
what,我该怎么回答他?
如果技术面过了,栽在这种问题上岂不吃亏?相反假如你答得好,却会为你的薪资增加筹码。其实这个问题究竟该怎么回答,要具体情况具体分析。首先要看这家公司处于它这个行业的什么位置,它未来的公司战略规划是什么,它想招进来一个怎样的人,它希望你发挥的是什么作用,坐在你对面的是app leader还是CTO 抑或是HR?都会有不同的最佳回答。因为每个人想听到的是不一样的“实话”,实话打引号表示经过包装以后的答案。
关键就是你得理解这话背后的意思,面试官为什么要问这个问题呢,他想知道的无非是:
1. 你会在这家公司呆多久?
2. 你未来可能处于公司什么样的角色中。
3. 你能否适应公司现有文化?
4. 你能为公司发挥多少价值。
5. 面试官还有自己的小算盘。
如果坐在你对面的是app leader,你说你以后想做到这里的技术leader,那你一定是撞枪口上了,除非他就是要离职前招个leader进来。请注意这种情况是很有可能发生的。大多数面试官进来不会介绍他的职位,面试level 也未必和面试顺序正相关。这就好像在一个暗箱中博弈,通过察言观色和判断得到的信息是有限的,知己知彼你才能不出错,然后才是怎样最大化说出对方想听到的接近答案。
## 面试前的准备
- [长期准备:](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section)
- [1. 订阅几个高质量的公众号](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section-1)
- [2. 加入一个本地android组织](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#android)
- [3. 看几本必看的进阶书](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section-2)
- [4. 收藏几个博客,紧跟几个专家](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section-3)
- [5. 写自己的独立技术博客](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section-4)
- [6. 看源码](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section-5)
- [7. 提交自己的开源代码](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section-6)
- [短期准备:](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section-7)
- [1. 去NewCoder刷题](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#newcoder)
- [2. 去极客学院阅读几本微书](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section-8)
- [3. 看几篇分析源码的文章](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section-9)
- [4. 梳理一下知识体系,找出薄弱环节](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section-10)
- [简历的准备:](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section-11)[有几点](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section-12)[千万别…](http://www.bingjie.me/2016/05/12/%E6%89%AB%E6%B8%85%E9%9D%A2%E8%AF%95%E5%89%8D%E7%9A%84%E5%87%86%E5%A4%87.html#section-13)
有的时候我们在职场上会碰到各种各样的坑…… 不管是创业公司倒闭啦,新同事合不来啦,氛围太差受不了啦。如果说女人的安全感来自于独立,那么程序员的安全感就是手中有技术,心中有源码。想飞得更高,有哪些是你平时可以做的呢?
本篇接上一篇 [扫清面试障碍](http://www.bingjie.me/2016/05/08/%E6%89%AB%E6%B8%85Android%E9%9D%A2%E8%AF%95%E9%9A%9C%E7%A2%8D.html)。上篇主要抛砖引玉,提到了许多技术和非技术相关的面试技巧等。本篇讲述面试前的准备,这不仅是技术实力的积累,还有相当一部分软实力的积累。即使是暂时没有跳槽想法的技术人,也应当生于忧患之中。行业的发展非常迅速,逆水行舟不进则退。危机意识很重要,厚积薄发才能更上一层楼。
友情刺激大家: [《高二Android大牛是这样炼成的》](http://chuansong.me/n/329510551337)
面试前的准备可分为长期准备,和短期准备。首先声明,文中提到的书籍以及公众号,博客等,都是我自己觉得特别优秀的,绝没收任何广告费
### 长期准备:
#### 1. 订阅几个高质量的公众号
很多大厂都有自己的微信订阅号,很多人的阅读时间非常琐碎,那么你就可以在地铁上、在等公交车的间隙去刷刷最新技术的发展。订阅号贵精不贵多,某个订阅号里的文章一天也最多一篇,不然就容易粗制滥造。这里推荐几个高质量的android公众号:
腾讯Bugly: weixinBugly。

是[腾讯bugly](http://www.bingjie.me/2016/05/12/bugly.qq.com),专门做性能监控的平台,里面的文章也都是总结bugly bbs上企鹅工程师文章的精华。发送频率很低,质量都不错。后期面试中很多关于内存泄漏的答案都来自于此。
移动开发前线:bornmobile。info主编徐川个人的微信公众号,里面的文章有原创也有很多精华集锦。关键是都比较严肃,不像某些个人公众号发展到后期变个人的独白段子手,干货也多,由于大都是搬很多个人博客和采访,所以质量还不错。
Android程序员:androidtrending。公众号所有者应该是汤涛。虽然Android技术公众号不少,个人感觉这个公众号是比较能紧跟潮流的。也没有什么废话而是纯技术。
程序媛:programgirl。一个程序媛发声的平台,更新不定期,`欢迎所有女程序员都来投稿,投稿地址:chaojimiaomiao@qq.com`. 比如本期android面试就会连载在里面。
#### 2. 加入一个本地android组织
大学时期我开始沉迷于android技术,但当时不善社交自命清高,往往是孤军奋战。回过头看,一个人的力量是有限的,只有交流才能进步,闭关锁国是没前途的。结识一批有同样追求的同行,甚至有很多比自己厉害许多的专家人才,你才能看到你未来努力的方向。人外有人,天外有天,千万别做井底之蛙。信息时代信息的交换是有价值的,小伙伴们一起努力也会将你带入一个好的氛围。
但是要谨慎地选择伙伴。我知道男生聚在一起最容易犯的错误是互相影响,比如大家一起去打一盘游戏啦,各种吹牛或恭维啦,,这些都是不可取的。低调而务实的小伙伴们聚在一起才有创造力,你们共同完成一个梦想一件事。
这里举个例子,https://github.com/LittleFriendsGroup/ 里的AndroidSdkSourceAnalysis。 他们发起了一个开源项目:18天认领android源码解析。这就是共同进步共同成长的典型呐~ 朋友应当是志同道合的,而非没目标的乌合之众。
#### 3. 看几本必看的进阶书
市面上入门书籍泛滥,而适合中高级的主流技术书实在太少。一方面是能写这种书的大牛懒得写,据我所知每卖出一本技术书,作者才拿到4块钱稿费。而中高级的受众面毕竟窄,即使热卖,卖出一万本,那么所拿稿费也不过是4万。然而有这种水平的开发者根本不缺这几万块钱。写书是一件特别耗费精力的事,除了内容还要排版,吃力不讨好。更何况还会面临盗版横行的情况,就更不值了。写书仅剩的吸引人的价值,恐怕是成书后带来的名声与成就感。由于这种客观情况的存在,市面上粗制滥造的书实在太多,我在此帮大家剔除糟粕,列举几本我觉得值得的书。
**推荐书单:**
**《Android开发艺术探索》任玉刚**
业界良心!里面的很多东西面试都被问到了!

**《App研发录》包建强**
[App研发录](https://read.douban.com/ebook/16178944/):架构设计、Crash分析和竞品技术分析。这是一本非常务实的书,书里提到的内容都可以直接拿来用在项目上。这个作者原先是搞.net的,工作十多年经验非常丰富。
摘录一段读后感:
> “落地”,是阅读此书的最大感受,大到技术架构、竞品分析、发布流程,小到每个Crash、员工座位安排、开展技术分享、简历筛选,作者总在寻求落地的解决方案,细细阅读,你不觉得这种方案有多么高大上,不觉得背后有多么华丽的理论支撑,但是你会觉得,一切都是踏踏实实、真真切切可落地实践的,为工作带来不少的实践指导。
**《Android内核设计思想》**
这本书写得很深,基本是这三本书里最接近底层的书了,读起来也比较晦涩。需要有一定的理解能力。
全书从操作系统的基础知识入手,全面剖析进程/线程、内存管理、Binder机制、GUI显示系统、多媒体管理、输入系统等核心技术在Android中的实现原理。书中讲述的知识点大部分来源于工程项目研发,因而具有较强的实用性,希望可以让读者“知其然,更知其所以然”。全书分为编译篇、系统原理篇、应用原理篇、系统工具篇共4篇22章,基本涵盖了参与Android开发所需具备的知识。
#### 4. 收藏几个博客,紧跟几个专家
有一阵我很迷茫,不知道继续进步的方向,也不知道我能达到什么样的程度。我甚至因为找不到安卓上进步的空间而横向求索,玩了一年的iOS开发。就在这时,我的偶像来了。偶然间一次搜索,翻到了 hukai.me。(当然发现作者长得帅也是一个激动的原因)
原来安卓还可以这么玩~!可以像胡凯一样紧跟谷歌的最新视频教程并翻译它们。 也可以像 [代码家](http://www.bingjie.me/2016/05/12/daimajia.com) 那样写控件造轮子。代码家甚至因为轮子造得好而被谷歌发现,发出了工作邀请。
具体你可以关注哪些安卓的优秀博客可以见 [这个链接](https://github.com/chaojimiaomiao/androidBlogCN):
博客地址
- [柳志超博客](http://liuzhichao.com/)
- [代码家](http://blog.daimajia.com/)
- [胡凯](http://hukai.me/)
- [禅](http://www.bingjie.me/)
- [Trinea](http://www.trinea.cn/)
- [方杰](http://blog.fangjie.info/)
- [技术小黑屋](http://droidyue.com/)
- [程序亦非猿](http://yifeiyuan.me/)
- [脉脉不得语](http://www.inferjay.com/)
- [陈启超的博客](http://chenqichao.me/)
#### 5. 写自己的独立技术博客
见贤思齐焉。
有了那么几个专家榜样,我的视野突然变开阔了,也想变成像他们一样厉害的人。这个时候你已经阅读了几本书,也有了一定的积累,自然而然也会想发表自己的看法和见解。
总之,克服瓶颈期的最好的办法就是六个字——总结、归纳、演绎。把你的收获都写到自己的博客上吧。最好是独立的博客,一方面你会收获到折腾独立博客的乐趣,另一方面它也是你的个人品牌,假如你能长期积累、坚持的话。独立博客唯一的缺点是导流。当然,你对自己的技术总结,目标是为了精益求精,为了自己的进步成长,至于读者多不多,倒是其次的。这个后期在面试中也大有裨益。别人刚认识你的时候对你不了解,你扔出一个博客地址,胜过你的千言万语。
没事的时候就去写写博客吧,记住__不要写很多生活琐事__,而是__记录进步__。别人不是为了看你的个人秀而来到你的空间,而是搜索到你对技术新的见解,觉得对他可能会有帮助才过来的。牢骚什么的,写到你的社交网站上去。
有的人很勤奋,博客天天更新。有量而没有质,感觉很空虚。我主张坚持精品博文才是正道,,毕竟信息已经那么泛滥了,不要再为互联网制造过剩的垃圾辣。。。(真的不是教你懒) 想要写一个优秀的博客,不仅要有实际的项目积累和广泛的阅读积累以外,uml类图,流程图,顺序图等,也是你必不可少的好助手。假如再加上__思维导图__,不仅使你的思路更清晰,读者也能一目了然,有一个全局观。现在就开始试试这些工具吧,会让你的博客更严谨更正式,更熠熠生辉。
#### 6. 看源码
这里列举几个你必须要看的源码:
- Binder
- LruCache
- Handler
- AsyncTask
- EventBus
不要怀疑,这些在面试中一定会被问到的。前期你看过源码也会淡忘的,先有一个大致的印象就行。
#### 7. 提交自己的开源代码
写什么样的开源代码,有这么几个方向。
一是你博客中的例子。一个好的技术博客不仅有图有文字,假如有例子,更胜过苍白的自然语言。百闻不如一见,说得再多也不如实际一个例子。
二是自定义的控件基础库。这个主要集中在酷炫的动画,还有交互更简洁的自定义控件上。这方面的大牛比如很多国外的库,还有国内代码家博客上提到的开源库~
三是有关测试方面的工具。像leakCannary, blockCannary等,能让开发者更好地测试内存卡顿泄漏等。
四是一些反编译的工具。
五是一个完整的上架作品。
### 短期准备:
#### 1. 去NewCoder刷题
这个网站主要包括了几套公司真题,比如有 [Android的](https://www.nowcoder.com/contestRoom?mutiTagIds=642),[算法讲解](http://www.nowcoder.com/live/2),[数据结构](http://www.nowcoder.com/review#3)。
有时间的可以去上面刷刷题,题量较大
#### 2. 去极客学院阅读几本微书
没时间阅读厚重的大部头怎么办?有一些不出版的非纸质微书也是极好的选择。极客学院有[几个系列](http://wiki.jikexueyuan.com/list/android/) 写得不错,比如《深入理解 Android 卷》系列,《Java 集合学习指南》等。
做工程的开发者容易陷入埋头写代码的怪圈,实际上多看一些技术书,吸收别人的思想精华进步会更快。
#### 3. 看几篇分析源码的文章
在长期准备中,你已经接触过一些源码了;当然你可能跳槽时间比较紧,那不如关注一下这个开源项目吧,里面包括了大量的 android源码分析。
ANDROID SDK 源码解析:[AndroidSdkSourceAnalysis](https://github.com/LittleFriendsGroup/AndroidSdkSourceAnalysis)
如果你有时间,你也可以参与到这个项目中去。
#### 4. 梳理一下知识体系,找出薄弱环节
总结、总结,再总结。
总结是一个人非常重要的品质,在总结中思考自己的不足,完善自我。不仅适用于面试,也适用于职场,日常生活等等。常思考,才可能变成一个智慧的人。
具体有哪些可能的薄弱环节,可以看下一篇整理的30个发散性问题。
### 简历的准备:
写好简历也是一个重要的环节。程序员最好常备一份简历,以备不时之需。另一方面,更新简历的过程中也会明白,哪些经历是无用功,哪些是加分项。
#### 有几点
1、尽量避免主观表述,少一点语义模糊的形容词,除非是大公司大牛,已经有成果撑腰,否则慎用「熟悉…」、「使用过…」
2、多一点表意清楚,语气肯定的数量词、名词、成果描述。一定要将自己的优势和期望明晰地表达出来,便于招聘方能对候选人有更准确的定位:
- 介绍技术:最近几份工作经历中所参与过的产品、项目、角色
- 在工作中做的项目的技术细节
- 克服过的技术难点与细节
- 感兴趣的技术
- 在程序马拉松上参加的项目或者是业余的个人项目(+link)
- 如果领导过技术团队,写下带的团队的规模与管理风格
- 介绍自己:过往有特点经历、擅长的方向、对互联网的理解、职业发展规划
3、突出重点。重要的放前面,不重要的经历往后排。尽量注明每段经历的时间,不然技术官或hr会一头雾水。比如你面试 Android开发,iOS的经历就放后面一笔带过,另外时间越远的优先级也越低。对了,记得把联系方式写在开头,不然对方联系不到你,可就把你忘了。
3、试试用markdown语法,注意下排版,预览再提交,版面整洁、干净,也是加分项。
4、HR/技术负责人更喜欢看到一份显示「职业上升趋势」的简历。比如你做开发五年,跳过两三次槽。那么你的职位,你所做的技术难度应当是越来越具挑战,而不是依然罗列各种琐碎的需求实现。
5、牛人讲结果,普通人讲过程。话虽如此,你只要不太啰嗦,该列出的事情还是要列出来的。不仅如此,你在该项目中发挥了什么作用,有什么反思,也可以写出来。记住,你出卖的不仅是技术,还有能力。
#### 千万别…
1、真实的反映你的工作,别浮夸。
因为你的面试官之后一定会问起浮夸的事情,假如你不能自圆其说,会留下非常不好的印象。
2、记得最好不要出现“**精通**”等词汇。
很少有人能精通JAVA,精通数据库,这样的字眼基本等于自杀。好的办法是阐述事实。比如用JAVA开发过什么系统,在什么项目中深入接触数据库等等。
3、简历上的所有技术,你必须谙熟于心。
甚至你应当练习几遍,找出可能发散出去的所有问题。只有你非常熟悉,并且在面试中足够自信,你才有能力引导面试官问到你想要的坑中。
4、简历长度不要超过三页。最好是两页这样一目了然,当然如果从业经历比较长,也可以多写点。
5、别撒谎。天下没有不透风的墙。假如你不想让人知道什么,你可以不写;假如你在原公司的锻炼机会太少,那么你可以将经历写到自己的开源项目中去。
## 三十道android开放题
为姗姗来迟的安卓面试题表示抱歉。
大家可以先思考一下这些问题,答案会过一阵在后文放出。
### 基础题
- Activity生命周期和启动模式,以及使用场景
- Service的生命周期,如何启用/停用Service
- 可能导致OOM内存溢出的情况有哪些,怎么解决
- Android中的动画有哪几类,它们的特点和区别是什么
- 注册广播几种方式
- 如何自定义View
- 程序crash的所有可能原因
- android动画
- Android操作系统分层
### 中级题
- Android事件处理机制
- 内存泄露的案例
- 图片加载库的使用及比较,内在逻辑分析
- 网络库的使用和比较
- android线程间通信
- android进程间通信。Binder源码与Looper关系等
- 设计模式在android中的应用,手写几个典型模式
- annotation 以及java反射机制
- Java虚拟机
- Java几种线程池
### 高级题
- 热修复技术,原理及其应用
- react native
- 几种架构模式
- 新建一个工程,需要加入哪些库和模块,该怎么设计
有关测试:
- DDMS + MAT
- monkey test和logcat命令的常用过滤参数
- android作优化有哪些可以考虑的方向?
### 开放题
- 当我在浏览器中输入一个url,世界发生了什么。
- http和https的区别
- 几种加密方式区别,对称与非对称。
- 你还了解什么其他的语言?和Java对比一下。
> 原文链接:冰洁的技术博客,http://www.bingjie.me/
================================================
FILE: docs/android/Android-Interview/经验分享/技术硬碰硬—阳哥带你玩转上海Android招聘市场.md
================================================
# 1. 挑战公司No.1:上海创梯信息科技有限公司
公司地址:上海杨浦区昆明路1209号尚凯大厦副楼504室
面试时间:5月12日 10:00 AM.
面试结果:顺利砍下Android技术总监,15K offer
面试过程:
10:00 到公司,前台MM给了张面试人员登记表,10分钟搞定表格。
10:30 由于公司BOSS正在面试其他人,因此,又等了几分钟。
10:40 在BOSS办公室与BOSS斗智斗勇,聊了有接近1个小时。
疯狂的笔试+面试记录(前方内容“高能”:funk:,请准备高度精神集中前行):
## 1. 笔试
由于BOSS正在打造公司新业务,刚刚开始组建公司技术团队,公司没有人懂IT技术,故本次面试没有笔试题,额
## 2. 面试过程问答精选:
旁白:进入办公室后,我淡定等待,约莫几分钟后,一位35岁左右,看起来非常老道的BOSS走了进来。几句寒暄之后,问了我一些关于我的学校、专业、工作经验、接触的Android项目等普通流水线式的没有营养问题,轻松搞定!接着,BOSS终于切入到了重点:
BOSS问:其实我们想做一个快递业务的APP,类似于滴滴打车。用户如果想要寄快递,只需要打开APP,查找附近都有哪些快递员,然后直接跟附近的快递员联系。如此,既能方便用户,又能提高快递员的收入。
我(阳哥)答:我有一个问题想要问一下,咱们公司(注意,一定要说“咱们”,让别人感觉你已经融入他们的公司团队了)不像顺丰,不是典型的物流公司,为什么我们要做快递类的APP呢(主动沟通交流,有问题就问,这样面试官才能跟你聊起来!)?
BOSS答:你知道的那些物流公司现在都是各自为政。例如,你用顺丰快递,你可以下载个顺丰的APP。但是,你以后可能还要用中通、申通、圆通等等这些物流公司,难道你要下载十几个APP吗?而我们要做通用的快递类APP!
BOSS问:你知道一个APP重要的是什么吗?
我(阳哥)答:用户体验!
BOSS说:不对,是流量,也就是用户数量(好吧,阳哥作为技术屌丝,关注多的就是APP用户体验,所以,不敢去反驳他,先顺着他的意思来)。
BOSS问:如果让你去做一个类似于滴滴打车的APP,你认为自己做的出来吗?
我(阳哥)答:像滴滴打车这样的APP,不仅仅只是客户端的问题。它不是由几个简单的客户端程序员就能做出来的,实际上,它应该是由一个技术团队完成的大型项目。您目前能够看得见的仅仅是用户客户端,看不见的是庞大的后台系统。说详细点就是:滴滴打车这样的项目应该分3部分:服务器端,用户客户端,出租车司机客户端。服务部端考虑的是数据的存储,业务的调度处理,以及与各个客户端的数据交互。而用户客户端我个人理解主要是一个UI的显示和与用户数据交互的功能。比如,用户将自己的当前坐标发送到服务器端(当前坐标可以通过百度地图、高德地图获取),服务器根据用户的坐标查找附近的所有空闲状态的出租车,然后将用户的用车需求推送到出租车司机客户端端。出租车司机接收到信息后,如果愿意接这笔单子,就向服务器发送同意信息。服务器就是作为一个中介将用户与出租车司机联系起来。大概逻辑就是这样一个过程,中间的技术细节比较多。总之,一个人做滴滴打车是不太现实的(大家可以看出来,这一段,阳哥是傻瓜式教学,没有说的太复杂,好让BOSS能够听明白。不然,技术说的太深,BOSS就不知道说什么了,还怎么聊的开心。面试的最终目的就是让对方觉得看你很顺眼,这是关键!)。
(顺便啰嗦一下,黑马的Android课程中有部分JavaWEB课程。我们做为APP开发人员,不管是服务器端还是移动端都应该有所了解。如果仅仅会移动端开发技术而不懂服务端知识,长久看来,确实会很影响Android程序员向更高层次发展。)
BOSS问:那么,如果我让你负责客户端的开发呢?
我(阳哥)答:客户端Android开发并不难,比如支付宝是一个很强大的金融系统。但是,你让我做它的Android端开发,我感觉我没问题。毕竟,Android客户端重点是信息的展示和与用户的交互。所以一个人做客户端是没有问题的。但是,目前市场上的企业很少有一个人做一个客户端项目的。市场竞争如此激烈,一个人做耗时太长,可能你还没有做出来,产品已经被淘汰了。因此,应该多招几个Android程序员,这样团队就算有人员流失也不会影响整个公司的发展(展示自己对于项目组人数把控的个人看法)。
旁白:几轮PK下来,BOSS基本上对我已经很信服了。
BOSS说:其实,在面试你之前,我已经招聘到了两个移动开发的程序员,一个是Android程序员(6K),一个是iOS程序员(8K),你可以看一下他们两个的面试登记信息和他们的简历。
我(阳哥)问:根据这两份简历可以看出来,这两个人的技术有些一般(不是装逼,他们的简历写的确实有点LOW)。
BOSS问:是的,我看的出来,你的经验要比他们丰富地多。所以,我准备让你出任我们公司的技术总监,带着他们两个做客户端开发,你认为你有信心做好吗?
我(阳哥)答:这个职位我以前没有做过,所以心里没有多大的底(阳哥认为这样的问题确实比较考验人,你直接回答“可以,没问题”,就会显得你浮夸、不谨慎、办事不牢靠。如果你直接回答“不能”,又显得你不敢担当,没有上进和挑战的精神。因此回答这样的问题必须两者兼顾,既要谦虚谨慎又要表现出富有挑战精神)。
BOSS说:我知道你没有做过,但是,一个人挑战任何一样新工作之前都是没有做过的。你有没有想过一旦你能够胜任我们的公司的技术总监,你以后的身价将和现在完全不同,所以,对自己要有一些信心(BOSS故意画大饼,就说明你有戏了!)。当然,这是一个管理岗位,需要什么样的技术人员你可以招。
我(阳哥)说:好吧,其实我希望挑战一下,但是我不一定能够达到您对我那么高的期望(始终保持谦虚的态度很重要!你的态度决定别人对待你的态度!)。
BOSS问:你尽力就好,请问你的期望月薪是多少?
我(阳哥)答:15k(第一次面试,我心里也不太清楚上海的市场,15k一般是黑马班里的大神级同学要的薪资,所以,试水一下)。
BOSS说:好的,没问题(竟然没有砍价:L,额,土豪公司)。
旁白:随后,阳哥又和BOSS聊了一些其他内容,由于BOSS马上要开会,就告诉阳哥如果你同接受我们的邀请,那么我希望我们明天下午可以好好聊聊。。。。之后,一堆寒暄,不列出来了。虽然,第一家面试就这样结束了,没有技术上太多的PK。但是,却使阳哥在精神上却得到了巨大的鼓励,面试第二家上海公司有了更大的信心!
## 面试吐槽
阳哥的上海处女面就这样丢掉了!遗憾的是BOSS不太懂技术,没有碰撞出技术的火花。但是,让人幸运的是他提供给我了一个技术总监的岗位。整个过程可以看到,面试的时候,面试官一方面会明中考察我们的技术。另一方面,在暗中实际上也在考察我们的沟通能力、思维逻辑能力、管理能力等这些软实力。所以,黑马的每一位达人,在黑马拼命码代码的同事,别忘了多和你的小伙伴分享技术,不要忘记中午的时候抓住每一次的公开演讲机会。有时候,一个人综合实力远大于单纯的技术竞争力!加油吧,骚年们!
# 2. 挑战公司No.2:上海复深蓝信息技术有限公司
公司地址:上海市徐汇区漕河泾开发区虹梅路2007号1号楼
面试时间:5月12日 14:00 PM.
面试结果:顺利砍下Android工程师,17K offer+1K补助 = 18K 月薪:victory:
面试过程:
14:00 到公司,前台MM给了一张面试登记表和一张Android笔试试题,然后一位和蔼的大叔(技术大拿)将我带公司接待处,让我开始笔试。
14:20 笔试完成,笔试很简单,做完后把试题交给前台,前台帮我联系面试官。
14:25 跟一个年龄大概在25~30岁之间的年轻技术官进行了接近1个小时的面试(通过交谈阳哥感觉面试官应该是项目经理或者开发组组长)。
15:20 人事面试,人事面试后提前跟我说CTO会对我进行一个电话复试。
第二天晚上大概19:00,公司CTO对我进行了技术复试,总共持续了31分钟。电话复试题要比初试难的多了,姜还是老的辣。我把复试的对话录音保存下来了,作为以后上海黑马就业指导课程的案例讲解(内容何止“高能”,简直就是高达!)。
疯狂的笔试+面试记录(前方内容“残酷”:funk:,请准备受虐心态前行):
## 1. 笔试
笔试时出现了一个小插曲,和大家分享一下。阳哥笔试所在的接待区是一个半开放式的区域,共有3张桌子,每张桌子上都有一支签字笔。我先用第一张桌子,发现笔是坏的(郁闷),然后换到第二张桌子,发现笔还是坏的(心想:尼玛,这么霉,顺便汗一下),最后只能换到第三张桌子,你猜怎么滴,对,笔还是坏的(想要骂娘了,FUCK!)。没辙了,翻遍我的背包,自己也没带笔。难道企业是用这种方式考察一个应聘者的吗?这怎么办?
我想去前台借吧,前台肯定有(不要去人事那里借,前台毕竟只是前台,不会管你太多的细节,人事可就不一样了,他们会认为一个面试者来比试不带笔是极不严肃的表现)。热心的前台MM很乐意地把自己的笔借给了我(心里一阵暖啊!这家必须拿下!)。
为了方便大家更清晰的看到笔试题目,阳哥手录笔试题和答案,看你能做对多少?!
Q:Android的四大组件有哪些?
A:Activity、Service、ContentProvider、BroadcastReceiver。
Q:请描述下Activity的生命周期?
A:onCreate、onStart、onResume、onPause、onStop、onDestroy、onRestart。
Q:如何将一个Activity设置成窗口模式?
A:将Activity的样式设置成:android:theme="@android:style/Theme.Dialog
Q:如何退出Activity?如何安全退出已调用多个Activity的Application?
A:调用Activity的finish方法可以退出当前Activity。可以自定义一个Application,在Application中声明一个成员变量ArrayList用于存放打开的Activity,当退出时遍历ArrayList,依次调用Activity的finish方法。
Q:请介绍下Android的五种布局。
A:LinearLayout、RelativeLayout、FrameLayout、RelativeLayout、TableLagout
Q:请介绍下Android的数据存储方式。
A:SharedPreference、XML、SQLite、文件系统
Q:DDMS和TraceView的区别。
A:DDMS 的全称是Dalvik Debug Monitor Service,是 Android 开发环境中的Dalvik虚拟机调试监控服务。TraceView是程序性能分析器
Q:说说Activity、Intent、Service以及他们之间的关系。
A:Activity负责界面的显示和用户的交互,Intent封装了数据,可以实现Activity之间以及Activity和Service之间数据的传递。Service运行在后台进程,一般我们会让给其运行一些后台任务,Activity通过StartService(Intent)或者BindService(Intent)可以启动Service。
Q:请介绍一下ContentProvider是如何实现数据共享的。
A:我们可以定义一个类继承ContentProvider,然后覆写该类的insert、delete、update等方法,在这些方法里访问数据库等资源。同时将我们ContentProvider注册在AndroidManifest文件中,其他应用需要使用的时候只需获取ContentResolver,然后通过ContentResolver访问即可。
## 2. ROUND 1:PK项目经理技术面试问答精选
项目经理问:Activity都有哪些生命周期?
我(阳哥)答:这个问题其实在笔试题中我已经给出答案了(此时,阳哥表示非常疑惑~)。
项目经理说:我知道,你再说一遍。
旁白:当时阳哥我真没搞明白,为何笔试上的题目他还是问我一遍,而且笔试上的好几道题他都重复问了一遍。现在想想应该是他怀疑我笔试的时候作弊了,比如我可以百度什么的。好吧,我不就是笔试的时候出去跟前台妹子借了一支笔,然后又把笔试题给拍了个照片而已嘛。而且,我那3G的联通定制机安装的移动4G的卡,只能享受2G的网速,我打开个百度都得几分钟。算了,不能和面试官较劲!我忍!
我(阳哥)答:Activity有以下生命周期回调方法,比如常用的有onCreate、onStart、onResume、onPause、onStop、onDestroy、onRestart。默认情况下,如果我们不给Activity设置横竖屏配置信息的话,在横竖屏切换时会将一个Activity销毁掉然后重新创建。
项目经理问:Fragment你用过吗?
我(阳哥)答:这个当然用过呀。现在的应用中基本都有Fragment的应用,Fragment比较小巧灵活。
项目经理问:那Fragment跟Activity之间是如何实现值传递的?
旁白:其实项目经理在问我会不会Fragment的时候,我已经预料到接下来会问我Fragment跟Activity直接的值传递问题。对于前面的问题,如果我说不会,就不会有下面的问题,但是如果说不会的话,那么项目经理很可能因为这一个问题而把我PASS掉,因为Fragment是Android中一个非常重要的知识,这个是必须会的(黑马的Android基础课程中有一天就是讲Fragment的)。如果连这个都不会,那么再好的面试技巧也挽救不了同学们的!
我(阳哥)答:Activity可以先获取FragmentSupportManager或者FragmentManager,前者是v4包下的,向下兼容因此用的比较多。然后这些Manager通过Fragment的tag或者id调用findFragmentByTag("tag"),findFragmentById("id")找到我们需要的Fragment对象,然后通过调用Fragment对象的方法来进行值的传递。
项目经理问:Android中都有哪些组件需要在清单文件中注册?
旁白:四大组件是学习Android的必会知识点,也是黑马Android基础中的重点内容,因此这个问题同学们其实应该是很好回答的!
我(阳哥)答:一般来说四大组件都需要在AndroidManifest.xml中进行注册,不过其中Activity、Service、ContentResolver是必须注册的,而BroadCastReceiver可以在清单文件中注册,也可以不注册,这也分别叫做静态注册和动态注册。
旁白:在Android中一般通过XML文件注册的组件,我们叫静态注册,而通过代码注册或者创建的组件我们叫做动态注册。动态注册和静态注册这两个名称听起来很高大山,其实理解起来so easy滴!
项目经理问:你自己有做过自定义控件吗?
我(阳哥)答:自定义控件做过,比如我们项目中的SlideMenu,LazyViewPager,Pull2RefreshListView,VerticalSeekbar,RandomLayout等都是自定义控件。
项目经理问:那你说说View的绘制过程?
我(阳哥)答:View绘制是从根节点(Activity是DecorView)开始,他是一个自上而下的过程。View的绘制经历三个过程:Measure、Layout、Draw。
旁白:黑马的老版本课程体系中有2天的自定义控件,在这两天课程中同学们能够学会SlideMenu,Pull2RefreshListView,优酷菜单等自定义控件,目前的黑马课程又对自定义控制进行了加强,添加了多种QQ5.0新特性内容,当然难度其实也不小。
项目经理问:ListView你们应该有用过吧?
我(阳哥)答:这个在我们的项目中应用的很多,其实在如今所有流行的App中,ListView都有一个大量的应用,说ListView是一个使用率高的控件都不为过。
项目经理问:ListView的优化你们是怎么做的?
我(阳哥)答:ListView的优化有多种多样的策略。在我们的项目中主要做了如下优化。1、重用ConvertView,2、给ConvertView绑定ViewHolder,3、分页加载数据,4、使用缓存。前两个是通用的解决方案,后两个是针对我们业务的个性化解决方案。我们的数据来自服务端,如果服务端有1000条数据的话,我们客户端不可能傻瓜式的一次性用ListView把这些数据全部加载进来,因此我们就用分页加载数据,每次加载20页,当用户请求更多的时候再获取更多数据,网络的访问就算网速再快也多多少少会有一定的延迟,因此我们的网络请求是异步处理的,同时从网络加载来的数据使用了2级缓存来处理,第一级是内存级别的缓存,第二级是本地文件的缓存。当ListView加载数据的时候首先从内存中找,如果找不到再去本地文件中找,只有都找不到的情况下才去请求网络。
旁白:ListView的优化是黑马课程一个重要的知识点,因此大家上课的时候这个必须得学会,不然在以后的面试中肯定会栽跟头的。
## 3. ROUND 2:第二轮PK CTO(非人类)技术面试问答精选
旁白:第二轮技术复试是在第二天晚上7点时开始的,当时,阳哥我刚从外面面试完回到家中。跟我聊的是他们公司的CTO,通过聊天也能感受到他的技术非同寻常,前几个问题问我时感觉多方有种咄咄逼人的气势(貌似面试的人太多了,对于被面试人员都是不屑的口气)。不过几轮技术PK后,发现原来CTO对人类也可以这么温柔和气的(尼玛,技术好才能被人看得起啊!心底话!)。
CTO问:说说你对泛型的了解?
我(阳哥)答:泛型是jdk5.0版本出来的新特性,他的引入主要有两个好处,一是提高了数据类型的安全性,可以将运行时异常提高到编译时期,比如ArrayList类就是一个支持泛型的类,这样我们给ArrayList声明成什么泛型,那么他只能添加什么类型的数据。第二,也是我个人认为意义远远大于第一个的就是他实现了我们代码的抽取,大大简化了代码的抽取,提高了开发效率。比如我们对数据的操作,如果我们有Person、Department、Device三个实体,每个实体都对应数据库中的一张表,每个实体都有增删改查方法,这些方法基本都是通用的,因此我们可以抽取出一个BaseDao,里面提供CRUD方法,这样我们操作谁只需要将我之前提到的三个类作为泛型值传递进去就OK了。而数据的安全性,其实程序员本身通过主观意识是完全可以避免的,何况某些情况下,我们还真的想在ArrayList中既添加String类型的数据又添加Integer类型的数据。
CTO问:你知道Java的继承机制吗?
我(阳哥)答:知道呀,这个问题很简单呀!java是单继承多实现呀。
CTO问:那你知道java为何这样设计吗?
旁白:从上面的问题也可以看出越是资历老的程序猿越喜欢刨根问底,因此如果同学们面试的时候遇到一个年龄稍微大点的程序员,那么一定要提前做好思想准备了,他可能先问你一个看似很简单的问题,然后再追问一个很深的思想或者原理。
我(阳哥)答:为何Java这样设计,其实这也是我一直的一个小疑惑。不过我是这样理解的。我只能用反证法,如果一个类继承了类A和类B,A和B都有一个C方法,那么当我们用这个子类对象调用C方法的时候,jvm就晕了,因为他不能确定你到底是调用A类的C方法还是调用了B类的C方法。而多实现就不会出现这样的问题,假设A和B都是接口,都有C方法,那么问题就能解决了,因为接口里的方法仅仅是个方法的声明,并没有实现,子类实现了A和B接口只需要实现一个C方法就OK了,这样调用子类的C方法时,Java不至于神志不清。从另外一个方面考虑的话应该就是Java是严格的面向对象思想的语言,一个孩子只能有一个亲爸爸。
CTO问:Java的异常体系你知道吗?
我(阳哥)答:知道呀,顶层是Throwable接口,往下分了两大类,一个RunntimeException另一个是普通的Exception。
CTO问:那你知道这两类异常的区别吗?
我(阳哥)答:当然知道,java的命名是见名知意的。从名字上我们也知道RunntimeException就是运行时异常,在运行的时候才能被jvm发现导致程序的终止,而普通Exception必须进行try、catch处理,或者在方法上用throws声明。
CTO问:那你的期望薪资是多少?
我(阳哥)答:我期望的薪资已经给贵公司人事说过了,是17k。
CTO问:你这么年轻,就想要到17k呀!
我(阳哥)问:对的,我是还年轻,高中同样是学习3年,有的考上了重点大学,有的却只考上了个大专院校,甚至落榜,不同的人学习能力是完全不一样的,甚至可以用天壤之别来形容,因此如果只简单的用时间来衡量一个人的价值显然就是不太合理的,比尔盖茨跟我这样大年龄的时候已经是亿万富翁了,而我还在找17、18k薪水的工作(前面的问题已经回答的这么漂亮了,谈薪水的时候一定要表现出绝对的自信!)。
CTO问:你说的对,不过我还得问你几个问题,你说你们项目中有用到图片吗?
我(阳哥)答:这个当然有呀,我们新闻客户端基本上每条新闻都有图片,只有图文并茂的新闻才会有人看。
CTO问:那你说你们遇到OOM异常吗?
我(阳哥)说:这个前期的时候我们的APP确实遇到过这样的问题,不过现在新的版本早就吧这些问题给解决了。
CTO问:那你们是怎么解决的?
我(阳哥)答:OOM异常是Android中经常遇到的一个问题,程序员稍微不注意可能就导致其产生。因为Android的每一个应用都是一个Davlik虚拟机,该虚拟机的默认堆内存只有16M,远远无法跟我们的PC机比较,因此和容易导致OOM(Out Of Memory)异常的产生。导致这样的异常主要有以下原因:1、加载大图片或数量过多的图片,因为图片是超级耗内存的,2、操作数据库的时候Cursor忘记关闭,3、资源未释放,比如io流,file等,4、内存泄露。我们用用的OOM主要是加载图片导致的。因为后面的三种原因都是可以通过约束程序员的编码规范来进行预防,或者使用性能分析工具来检查。
CTO问:好的,那你们的图片是怎么处理的?
旁白:随后这就是CTO面试应聘者的一个习惯,他会追着一个知识点往死里问,直到问到系统的底层,或者他能理解的底。
我(阳哥)答:图片的处理主要用两种方式。我们的应用中有两处用到了图片,一个是ListView中展示的图片缩略图,这种情况的特点是数量大,但是单个图片内存小,只有几kb,另外一种是大图片,就是用户通过手机拍摄的图片,然后通过http的post提交的方式提交到服务器上。然后在客户端将这个大图片也展示出来。对于第一种情形,我们是通过三种技术手段来解决问题的,一是图片的缓存策略,二是ListView的优化,其实在上面我已经讲过,三是WeakRefrence(弱引用)的使用。对于第二种情形,我们主要是首先通过BitmapFactory.Options参数获取图片的宽和高,然后再根据我们ImageView的宽高对图片进行一个很大比例压缩。
CTO问:那你说说弱引用是怎么使用的?
我(阳哥)答:WeakRefrence是一个类,在ArrayList中我们把这个类作为对象传递进去,把我们的图片放在WeakRefrence里面,这样当davlik虚拟机内存不够用的时候,就会把WeakRefrence对象回收掉,这样我们在WeakRefrence里面保存的数据也被回收了。
## 面试吐槽
阳哥在上海的第二面终于遇到懂技术的人,把笔试、技术一面、人事、技术二面一气呵成的通了个关,不拖泥带水,最终人事给了基本薪资17k+1k多补助的offer,这种感觉也许只有你经历过了才能体会吧!相信黑马学子经过四个月的刻苦磨练也能远远超过我的水平。加油吧,骚年们!
这家公司所在楼有两层是高德地图的!
阳哥冒死偷拍的笔试题!
阳哥录用通知邮件!
# 3. 挑战公司No.3:中阜投融资产管理股份有限公司---中投融
公司地址:上海市静安区威海路228号招商局广场南楼21楼
面试时间:5月12日 16:30 PM.
面试结果:顺利拿下Android工程师,15K offer+1k住房补贴=16k:victory:
面试过程:
16:30 到公司,因为这一天安排了3家面试,这家本来是安排的16:00的,但是迟到了半个小时,不过企业招人都比较急,这个可以理解。
16:30~16:40 填写面试登记表,这家没有笔试题,填完后坐在公司前台附件的沙发上等了几分钟,桌子上放了一盘水果糖,诱人,也不敢吃,哈哈。
16:40~17:15 跟一位Android程序员进行第一轮PK。
17:20~17:50 跟项目经理进行第二轮PK。
17:50~18:00 跟人事谈薪资。
疯狂的笔试+面试记录(前方内容“高能”:funk:,请准备高度精神集中前行):
## 1. 笔试
这一家没有笔试题,其实阳哥发现一个规律,一般Android开发团队刚刚组建的,或者Android开发人员不多的企业基本都没有笔试这一环节,这可能是他们公司的Android开发团队各方面还没有形成一套标准的流程原因吧。
## 2. 第一轮技术面试过程问答精选
旁白:面试我的哥们儿比较腼腆,也许是他也刚进公司没多久的缘故,好像才4个月的样子。他主要问了我都做过哪些Android项目,怎么学习的Android,都做过哪些Android控件,然后他又问了一个他们公司目前正在做的项目遇到的一个难题,问我怎么解决。
PS:最后这个问题,阳哥感觉他并不是在考察我的技术,而是以请教我问题的态度在向我咨询了。面试能面到这种程度,基本已经有戏了。
面试官问:介绍下你都做过哪些Android项目?
我(阳哥)答:这自己主要做过3个项目,新闻类的,应用平台类的,手机管理类的,其中自己参与多也做的成熟的是新闻类的一款App。
旁白:上面的三种类型的项目,都是黑马Android课程体系中的教案,因此介绍项目基本没压力。
面试官问:那你在项目的开发中担任一个什么角色?
旁白:这样的问题其实很多面试官都问我了,感觉被问到的概率有80%,此种问题显然是想考察我们的担当能力,技术担当和责任担当。在上海黑马66期的开班典礼上,我是这样给大家说的,我们66期有70多位同学,我们班分成10个小组,每个小组选出一名组长,组长负责全组的学习,组长不是固定不变的,每周考试一次,每次考试成绩高者为组长。每次考试如果这个组的平均分在班排名低的,组长得无条件接受惩罚。在黑马,没有个人排名,只有团队排名,我们更注重团队的协同能力,而不注重个人的表现。
我(阳哥)答:我在这个项目中属于主要参与者之一吧,或者说是主要负责人,我们Android项目不像是javaweb项目那样需要大量的程序员,像我们的项目,总共2到3个程序员3个月功夫就能搞定,因此我们几个人也没有绝对的说谁领导谁。不过这样的项目,让我们任何一个人去开发都是很OK的,只是时间问题。
面试官问:你们用什么代码管理软件?
我(阳哥)答:SVN。
旁白:在黑马有专门的一节课是讲SVN和Git的,并且后面的项目也是用SVN跟大家进行代码共享的。
面试官问:你学习Android的途径都有哪些?
我(阳哥)答:现在是互联网时代了,不像我们大学时代主要通过书本学习。在大学的时候选修的Java课程,那时候还是诺基亚时代,图书馆的移动开发书架基本是被诺基亚的塞班占据的。自己大学毕业的时候Android已经开始风靡全国了,那时候自己从网络上看到的Android开发的各种视频,然后开始学习的Android。自己在Android的开发中遇到的各种问题一般都是靠百度解决的,说度娘是好老师真不为过,其实也用过Google,不过被屏蔽了,也懒得翻墙,百度现在做的也不差,百度出来的Android技术主要来自如下专业网站,比如:CSDN、51CTO、ITEye、AndroidBus、EOEAndroid等,对了还有一个国外的没有被屏蔽的网站是Github,我们项目中的很多控件其实都是从Github上学习过来的。
面试官问:那你从Github上都用到过什么控件?
我(阳哥)答:Github上的开源项目非常的多,基本上你想用的东西都有,比如xUtils、HelloCharts、Clander、SlideMenu、SeatTable、LDrawer、SmoothProgress、Touch Gallery、ViewPagerIndicator。
面试官问:你自己有做过自定义控件吗?
我(阳哥)答:自定义控件做过,比如我们项目中的SlideMenu,LazyViewPager,Pull2RefreshListView,VerticalSeekbar,RandomLayout等都是自定义控件。哦,对了,最近我刚给我女朋友还做了一个HideSlideBar控件,我可以让你看一看。里面主要由VerticalSeekBar+ProgressBar+NineOldAnimation完成的。
旁白:我把我自己做的自定义控件给他演示了一遍,这个是我女朋友项目中需要用的一个需求,她不会做,我帮她写了一个Demo,没想到正好用上了。
面试官问:哦,不错,你这个动画用的是属性动画吧?
我(阳哥)答:对的,这个属性动画,用了JakeWharton大神的开源框架。不过这个属性动画其实自己写也可以,内部原理比较简单,就是给控件设置一个开始位置,一个结束位置,设置一个延时时间,然后不停的更改控件的layout位置即可。
旁白:这个东西在黑马的项目中都有讲解,回答不难,在Android应用中我们会用到很多第三发的框架,我们不仅仅要会用别人的东西还必须知道别人写这个东西的内部原理。
面试官问:那好,现在我们有个项目遇到一个问题,你看如果让你做你应该怎么去解决?
旁白:这时候,阳哥已经感觉到自己已经PK成功了。不过面试官性格也不错,遇到问题善于寻求外界的任何帮助。
我(阳哥)答:可以的,什么需求您讲吧,我听听。
面试官问:我们的项目中有多个Fragment,Fragment A跳转到Fragment B,Fragment B跳转到FragmentC,那么这时候我多次按返回键,如何能让Fragment跟Activity的任务栈一样,依次从FragmentC跳转到FragmentB,再跳转到FragmentA?
旁白:这个确实是需要比较棘手的问题。其实面试官也知道你没有做过类似需求的开发,事实也是这样。这就比较考验临场发挥能力了。这种问题可以从模仿Activity任务栈考虑解决。任务栈是一种数据结构,我们可以自定义这种数据结构,然后管理这个数据结构,但是每个Fragment都是独立的,如何把这些独立的Fragment关联起来,这都是需要考虑的问题。
我(阳哥)答:这个需求应该很好实现。我们可以这样,首先定义一个BaseFragment,让FragmentA、FragmentB、FragmentC都继承BaseFragment,第二在BaseFragment中定义一个ArrayList,每打开一个Fragment,把这个Fragment对象添加到ArrayList中,这样这个ArrayList就可以当做一个栈结构,第三我们需要设置返回键监听,当监听到返回键的时候,查看当前ArrayList中倒数第二个Fragment有没有Fragment,如果有则取出该Fragment并把ArrayList中末尾Fragment删除,然后用FragmentManager的Replace方法,将当前Fragment替换成最新Fragment即可,如果ArrayList中只有一个Fragment,且监听到了返回键,那就不对Fragment做处理,同时也不拦截该事件,这样也不会影响其他Activity之间的切换。
旁白:回答了上面的问题后,面试官说他回去试试,然后就去叫他们的领导了。
## 3. 第二轮技术复试过程问答精选:
旁白:第二轮面试我的是个技术大拿,主要负责公司整个软件架构的设计,这家公司之前只有web端,全都是他干的,现在公司向移动端发展,因此最近一直在招Android和iOS开发人员,他不太懂Android,不然估计他一个人就能把一个Android项目搞定了。他问了我一些关于http、数据安全的知识,然后就开始跟我谈人生了,一直到他们快下班,他才把人事叫来跟我谈了谈薪资。
经理问:你做的Android的项目跟服务器交互都有哪些接口?
旁白:大家不要被接口这个词给迷惑了。这里的接口不是java中的接口类,也不是很高大上的东西,其实换成大白话就是你们的客户端跟服务端是如何实现数据的交互的。
我(阳哥)答:我们的接口有多种形式,第一种是http的形式,客户端跟服务器通过http协议传输数据,比如我们的新闻列表的请求都是给服务器发送的get请求,然后服务器把数据发给我们,我们上传给服务的图片是通过http的post请求方式完成的。第二种是socket完成的,服务端开启ServerSocket,客户端开启socket,然后客户端跟服务端建立长连接,这样实现了客户端跟服务端数据的即时通信,通信的协议是我们公司按照xmpp开放协议的基础上修改的,其实xmpp协议就是一个xml格式的数据。第三种是集成了第三方接口,比如分享功能用的是ShareSDK,消息推送用的是JPush,内置广告用的是万普世纪。
经理问:你们http传输数据的时候安全是怎么保证的?
我(阳哥)答:我们的数据有些是需要安全设置的有些不需要,我们的新闻类数据不需要特殊的添加安全设置,而用户注册,用户登录以及用户隐私数据保存是考虑安全性的。用户的密码等信息肯定不能进行明文传输的,我们将用户的密码在本地进行了MD5算法的加密,然后再传输。同时保存在本地的时候也是加密后的数据。还有需要安全性更高的数据需要通过我们自定义协议通过Socket传输。
经理问:那你知道MD5的原理吗?
旁白:老程序员就是喜欢刨根问底,如果技术功底不雄厚的话确实这个问题很难应付,因为对于大多数人只需要用一个技术就行了,不会去关注他的内部原理。
我(阳哥)答:MD5算以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了复杂处理后,输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。这个过程是不可逆的,我们也把他叫做数据指纹,但是我们依然对用户的输入进行安全校验,如果是纯数字类型密码,是不允许注册的,因此就算你MD5加密了,黑客也可以通过彩虹碰撞的形式进行暴力破解。
旁白:接下来,经理问了我几个问题可能能难住我,关键是他也不懂Android,只能问我javaSE和思想上的一些东西,之后就开始跟我聊人生了,说他们公司是国企背景,自己在公司发展多么好,公司未来要做一个什么什么样的产品,公司弹性工作制,每年至少14薪,又问我女朋友在哪,什么时候考虑结婚,在哪买房,老家是哪的,爸妈是干什么工作的,你是如何规划未来的等等。。。。。
## 4. 人事面试:
这家的人事面试与其说是人事面试还不如说成人事咨询,人事跟我介绍了公司背景,跟我谈了薪资,跟我谈了入职安排,又谈公司发展,公司的福利待遇等等。人事的最后一个问题都是出奇的相似,
人事:我该问你的问题都问完了,你还有什么要问我的吗?
PS:这些问题千万不要一个都不问,这样人事会认为你这个应聘者对我们公司不感兴趣。如果有其他人也去面试,那么你就可以能被PASS了。其实我们真的想去这家公司的话,肯定会有一大堆问题的,但是也不要问的太多,问的太多显得你很啰嗦,人事的耐心也是有限的,同时也不要问太低级的问题。对于我们程序员来说,应该最关注如下两大类问题,一是自己将要加入的开发团队的情况,二是公司的薪资待遇以及员工培训发展情况。第一类问题显得我们技术专业,技术屌丝的特性被发挥的淋淋尽致,第二类问题很现实,我们不仅要眼前的工资还要考虑未来的发展。
我(阳哥)答:咱们公司的技术团队目前有多少人,都做哪些项目?
人事:公司目前技术团队还在不停的扩建,目前总共有十几名,不过服务端人比较多。现在主要做p2p理财类产品,这也是很火的一个趋势。
我(阳哥)答:咱们公司给开发人员有定期的培训吗?
人事:有的,公司每年都有拓展培训,拓展培训是针对全体员工的,技术团队的话每周或者每个月可能有技术分享活动,每周一名技术人员进行分享,同时可以获100元/次的奖励。
## 面试吐槽:
阳哥在上海第一天竟然面试了3家,上海这么大,每个公司都在不同的区,回到家已经晚上7点多了,我的感受只有一个字儿累,躺在床上就起不来了,不过还好今天本来是抱着被面试官“虐”的心态去的,结果没有被“虐”,而且还能旗开得胜。这给了我很多自信,不仅仅是对自己技术的自信,更是对黑马Android课程的自信。
最后送大家一句话:没有企业给不了的薪资,只有自己掌握不了的技术。没有自己掌握不了的技术,只有不够努力的自己。
录用Offer!
# 4. 挑战公司No.4:上海游竞网络科技有限公司---PLU
公司地址:上海市闸北区广中西路777弄99号江裕大厦10层
面试时间:5月13日 14:00 PM.
面试结果:Android工程师,16K offer+500元住房补贴+490元交通和饭补+200元全勤奖=17.1k:victory:
面试过程:
16:00到公司,这家公司在闸北区,比较远,不过办公楼很高大上。
16:00~16:30 填写面试登记表和笔试题。
16:30~17:15 跟面试官进行技术PK(这家面试流程比较简洁,技术只考察一轮就让人事谈薪资了)。
17:20~17:40 跟人事谈人生谈薪资。
疯狂的笔试+面试记录(前方内容“高能”:funk:,请准备高度精神集中前行):
1. 笔试
PS:笔试是在公司前台旁白的桌子上做的。阳哥本来胆子就小,这一下搞的偷拍都没自信了,导致对焦不成功,拍出来的照片很模糊,大家凑合着看吧,我把图片上的试题以文本的形式列出来,如下。
Q:Activity的生命周期?
PS:我晕,跟复深蓝的笔试题如此的雷同,难道他们两家公司技术人员互相抄袭的吗?忍住,不笑!
A:onCreate、onStart、onResume、onPause、onStop、onDestroy、onRestart。
Q:Activity销毁前,如何保存Activity的状态?
A:可以使用onSaveInstanceState(Bundle)方法将Activity中需要的数据保存起来,当下次重新启动Activity的时候在onCreate(Bundle)中获取Bundle数据。
Q:请介绍下Android中常用的5种布局?
A:LinearLayout、RelativeLayout、FrameLayout、RelativeLayout、TableLagout。
Q:请介绍下Android的数据存储方式?
A:SharedPreference、XML、SQLite、文件系统、内存(如果算的话)。
Q:AIDL的全称是什么?如何工作?能处理哪些类型的数据?
A:
- Android Interface Definition Language
- AIDL一般用于远程服务,也就是进程间通信。我们可以分服务端和客户端,服务端声明AIDL文件,该文件命名为xxx.aidl,ADT会自动将xxx.aidl生成代码文件,代码文件提供了aidl中接口的实现。客户端如果要使用服务端提供的服务需要将xxx.aidl文件放到客户端源代码目录下,然后生成xxx.java类,客户端通过bindService的形参ServiceConnection的onServiceConnected获取到Service对象,这个对象通过Stub.asInterface(service)返回aidl的实现类。之后我们就可用调用这个aidl的实现类。
- 基本数据类型都可以,复杂对象也可以,只不过需要实现Parcelable接口。
Q:请介绍一下handler机制?
A:Android中handler多用于主线程和子线程之间的通信,比如在Android中子线程是不允许修改UI的,如果修改只能让子线程给主线程通过handler发送message,然后主线程进行修改。Handler整个机制的实现,还依赖Looper、Message两个核心内容。在主线程中Android默认给我们创建了Looper
Q:java如何调用c、c++语言?
A:java通过JNI调用C/C++代码,在使用的时候首先通过System.loadLibrary("xxx")将xxx.so文件加载到jvm中,同时在类中必须对so文件中的方法进行生命,格式:public native void test();
Q:Android分几层,分别是什么?
A:四层。Linux Core、Libraries(Android Runtime)、Application Framework、Applications。
Q:final、finally、finalize的区别?
A:第一个是关键字最终,用final修饰的类为最终类,不能被继承,修饰的方法不能被覆写,修饰的变量不能被改变。finally是异常体系中的关键字,当系统遇到异常是,在进行trycatch的时候,finally代码块里的代码是必须被执行的。finalize是Object类中的方法,当GC回收对象时回调的方法。
Q:heap和stack的区别?
A:堆和栈。栈存放对象的引用,堆存放对象实体。堆中的对象是有jvm的垃圾回收器负责回收。
## 2. 第一轮技术面试过程问答精选:
旁白:面试我的是85年出生的Android组组长(这是后来他们公司人事给我打电话让我入职的时候,跟我说的)。他们公司是做游戏视频直播平台的,因此对app的性能要求比较高,他用手机让我看了一段代码。代码(记得不是很清楚了)大概如下:
```java
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
SystemClock.sleep(1000);
}
}
}).start();
}
}
```
面试官问:上面的代码有问题吗?
我(阳哥)答:当然有问题呀,这个Activity在启动的时候开启了一个子线程,但是当Activity退出的时候该子线程还在运行,并没有停止。子线程运行在进程中的,Activity退出的时候进程并没有退出,而由前台进程变为后台进程。
面试官问:那应该怎么解决?
我(阳哥)答:我们可以这样,把while(true)改成while(flag),flag是一个boolean类型的变量,通过改变flag的true或者false来终止子线程的运行,当Activity退出时会调用onDestroy方法,因此在该方法中我们可以把flag设置为false。
旁白:面试官听了我的答案,从他的表情上来看好像他不是很满意。但是他也没说我说的对不对,而是给我说了他心中的答案,不过他给的答案我当时是虚心接受了,不过到现在我还没明白他说的道理在哪,我写了测试代码也没测试出来啥。
面试官问:这个代码有问题就出在这个Thread是一个匿名的,而且没有声明为静态成员变量?
我(阳哥)答:哦,这样子呀,这个我真不知道。
旁白:其实我内心是很想问他为什么呢?但是如果他答不上来就会让他很难堪,如果回答上来了倒没啥问题。从他也不自信的言语中我感觉还是不问他比较好?
面试官问:你对RTSP流媒体协议有了解吗?有没有做过手机播放器的应用?
我(阳哥)答:这个知道,自己做过流媒体播放器。我使用过开源的Vitamio开源库。
旁白:黑马课程中有一个项目是手机影音。因此这个东西自己是知道的。不懂的人可能以为RSTP、ffmpeg这些专业名词都多么的高大上,其实在黑马手机影音中,我们会做一个视频播放器,视频播放器分两种,一种是Android自带解码,第二种是万能播放器,所谓万能播放器就是绝大多数流媒体格式都支持。
面试官问:那你知道代码测试怎么测?
旁白:关于测试,阳哥真心不太懂,怎么办??尽量回答一些自己知道的,同时把测试方面的话题给关闭掉,省得面试官追问我。
我(阳哥)答:您说的是Monkey Test吗?。
面试官问:恩。。。也算吧?还有其他吗?
我(阳哥)答:我们程序员在写代码的时候都是有规范的,优良的代码规范是规避bug重要的一步,同时我们公司每周都有一个代码走读会议,所谓的代码走读,就是开发人员互相看对方的代码,检查代码是否规范以及是否存在bug。当然也有测试,不过我们的测试都是黑盒测试。
面试官问:哦,代码测试,就是可以通过测试一段代码来分析这段代码有没有问题,性能是否可靠。
我(阳哥)答:对的,Android自带了AndroidTest功能,可以对一个类一个方法进行测试。
面试官问:那好,图片你有处理过吧?
我(阳哥)答:这个肯定有呀,哪个Android应用没有图片。比如图片缓存呀,图片缩放呀,图片缓存呀。
旁白:其实自己对图片处理这块儿,还是比较了解的,可惜他也没怎么深问我,没有给我很大的发挥机会。
面试官问:我们现在要做一个视频在线播放的app,播放的都是游戏直播或者录像视频,iOS已经做好了的,Android还没有做好,你要是进来的话你就是做视频直播这一块儿。
我(阳哥)答:这个已经做好的能让我看一下吗?
旁白:面试官拿来水果机让我看了一下,主界面就是一个ListView,每个ListView的一行都有大概4个视频预览图,点击之后可以播放。
我(阳哥)问:这个切图,设计啥的都做好了吧,剩下的就是编码了其实?
面试官答:是的,后期我们Android团队还会不停的夸大,我们的发展重心已经偏向移动端。
旁白:接下来就是跟面试官侃大山了,从天文到地理,从BAT到初创型公司,阳哥也不能甘拜下风。
我(阳哥)答:恩,现在是移动互联网时代了,移动端肯定得做好,不管什么样的公司都特别重视移动端。咱们公司现在才开始研发移动端,其实已经稍微有点儿晚了,就得赶紧拼命追赶了。
## 3. 人事面试:
跟面试官聊完后,技术官对我的评价是,我挺喜欢你,你跟人事好好聊聊吧,哈哈,我肯定会跟人事MM好好聊天的。人事问的问题太老套路了,感觉全上海人事问的问题都一样,难道他们都是从一个地方培训出来的?人事也有培训吗?其实应付人事的问题不难,难的是如何回答人事的问题。答题的方式直接决定了我们在人事那里的印象。我把人事问的几个问题大概列一下。
人事:你为什么离职来上海?
PS:人事问这个问题的主要目的就是看你的动机纯不纯,有没有不良倾向。
我(阳哥)答:主要是两个方面吧,第一个是我的女朋友在这边工作,我年龄也不小了,也到了谈婚论嫁的时候了,我不着急,家里父母亲着急呀,来上海工作的话离女朋友比较近,结婚就比较好办,第二个主要还是。。怎么说呢。。。高大上的说就是为了自己事业更高的发展吧,说的直接点就是上海毕竟国际化都市,发展机会很多,自己也想来上海工作个3~5年挣钱买个房子首付啥的,如果在上海的这几年发展的好可以考虑再公司附近买房,如果自己发展的不好,在上海周边买个房也行。
人事:你女朋友一直在上海,还是刚回来上海?。
我(阳哥)答:她上一年来的这边,之前是我大学同学,主要是她家有亲戚帮她找了一份设计院的工作,而我只能靠自己找工作。
人事:你以后打算长期留在上海了吗?
旁白:上面的问题其实是人事在考察你的稳定性,公司可不想招到一个人刚培养出来就走掉了。但是如果你直接肯定的回答:我会一直留在上海,又显得很假。“装”的高境界就是让对方感觉你很不会“装”。
我(阳哥)答:这个有想过,自己其实蛮喜欢上海的,可是计划赶不上变化,来上海的前一年我也从来没想到我会来,因此不能说一辈子都在上海,不过目前这几年是打算在上海好好发展一下。上海的房价、户口政策都是问题,现在不是我选不选择上海,而是上海选择不选择我的问题,呵呵,其实谁都不傻,都想来好地方,关键就看自己有没有本事扎根于此了。
人事:你能承受加班吗?
旁白:其实互联网企业加班是很常见的现象,尤其是像上海这种生活节奏比较快的城市,加班肯定是避免不了的,但是我们也有我们的底线,不能无条件无休止的为公司加班,但是也不能一点儿班都不能加,毕竟有时候公司忙的话,比如新产品上线,新bug的解决都是需要加班的,这个时候我们还真的义不容辞的为公司付出,毕竟我们的薪水是公司给的。在公司工作一方面是我们为公司付出,另一方面我也要知道感恩公司。
我(阳哥)答:加班很正常,自己之前的公司也经常加班。不过公司加班一般都不会让员工平白无辜的加班的,我们加班的时候公司会发晚餐补助,打车补助等,如果加班超过半天会计入到我们的存休中,等活不忙的时候我们可以申请休息。因此只要不是高频度的天天加班到凌晨应该没啥问题的。
人事:你的五年规划是啥?
我(阳哥)答:自己还是想往技术方向发展,自己也比较喜欢代码,愿意去研究技术。人往高处走水往低处流,经过自己几年的积累后自己想当一名技术总监或者项目经理类的技术管理类岗位。不过这些都得靠自己的努力以及对机遇的把握情况了。
面试吐槽:
这家企业各个方面的条件真心不错,想拒绝都很难找到合适的理由!我要了15k的薪资,人家给了16k,还有各种诱人的福利。感觉还是游戏类的公司土豪。你以为你要15k,人家给你16k已经很高了吗?请让我把话说完,告诉你啥叫游戏公司。该入职的时候,当然我没有去入职(入职是上午10:00),上午10:20的公司人事给我打电话,问我迟到了还是怎么会儿事儿,我说对不起,感谢贵公司对我的认可,自己已经有了新的选择。把他们给拒绝了。下午1点多的时候,我正在吃饭,结果这家公司的技术官又给我打电话来了,在电话里跟我聊了很久,他说如果再给你多几k你会考虑过来上班呢?我哑巴了,自己从来就没有享受过这么好的待遇,受宠若惊的阳哥无言以对!自己的内心像打翻了五味瓶一样,这种感觉估计也没有几个人理解。后来还是被我给拒绝了,内心在流泪!
这篇文章阳哥已经写到尾声了,但是想给大家说的话却依然很多很多。
亲爱的黑马同学们:如果你还在撸着代码,看着视频,再苦再难,请你一定要坚持,今天你付出的一点一滴都将会在明天变成千千万万倍的回报。加油&坚持!
# 5. 挑战公司No.5:一号店旗下壹药网
公司地址:上海市浦东新区碧波路572弄115号10幢
(偷拍前台妹子~天热,穿的少其实是正常的,可惜桌子挡住了该看的,哦,不该看的:lol)
面试时间:5月14日 10:00 AM.
面试结果:Android工程师,15K offer&14个月薪资:victory:
面试过程:
10:10到公司,这就是传说中的一号店!,公司总共三栋独栋楼,两个在装修,一个在用,因此工位紧张,导致我面试都是在前台所在的大厅里进行的。
10:20~10:50 填写面试登记表和技术官面试。
10:50~11:10 跟研发部Leader面试。
11:10~11:30 跟人事谈薪资以及入职事宜。
疯狂的笔试+面试记录(前方内容“高能”:funk:,请准备高度精神集中前行):
PS:笔试跟面试是一起的,一个技术官拿着一张正反面都写满题的A4纸,从第一题到最后一题,他指一题我回答一题,我回答一题,他指下一题。配合的天意无缝,哈哈~~~
## 1. 笔试
### java基础部分
Q:Java面向对象有哪些特征?
A:封装、继承、多态。
Q:`short s1=1;s1=s1+1`有什么错?`short s1=1;s1+=1;`有什么错?
A:第一个是有错的,short在内存中占2个字节,而整数1默认为int型占4个字节,s1+1其实这个时候就向上转型为int类型了,因此第一行代码必须强转才行。第二个之所以可以是以为这句话翻译过来就是s1++,也就是short类型的数据自身加增1,因此不会有问题。
Q:静态成员类、非静态成员类有什么区别?什么是匿名内部类?
A:静态成员类相当于外部类的静态成员,是外部类在加载的时候进行初始化,非静态成员类相当于外部类的普通成员,当外部类创建对象的时候才会初始化。匿名内部一般都是在方法里面直接通过`new ClassName(){};`形式的类。比如我们`new Thread(new Runnable(){}).start();`就用到了匿名内部类。
Q:abstract class 和 interface有什么区别?
A:前者是抽象类,可以有抽象方法,也可以没有。后者是接口,只能有抽象方法。他们都不能创建对象,需要被继承。
Q:ArrayList是不是线程安全的?如果不是,如何是ArrayList成为线程安全的?
A:不安全的。可以使用Collections.synchronizedList(list)将list变为线程安全的。
Q:是否可以继承String类?
A:不可以,因为String类是final类。为啥不解释了吧。
Q:以下两条语句返回值为true的有:
A:`"yiyaowang"=="yiyaowang";`
B: `"yiyaowang".equals(new String("yiyaowang"));`
A:第一个返回true,都是字符串常量,存储在字符串常量池中,且只有一份。第二个返回true,用equals比较的是字符串内容。
Q:当一个对象被当做参数传递到一个方法后,此方法可以改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
A:java中只有值传递,没有引用传递。这里的引用本身就是值,传递的是引用这个值。
Q:定义类A和类B如下:
```java
class A{
int a =1;
double d = 2.0;
void show(){
System.out.println("Class A:a="+a+"\td="+d);
}
}
class B extends A{
float a = 3.0f;
String d = "Hello World!";
void show(){
super.show();
System.out.println("Class B:a="+a+"\td="+d);
}
}
```
(1)若在应用程序的main方法中有以下语句:
```java
A a = new A();
a.show();
```
则输出结果是?
(2)若在应用程序的main方法中定义类B的对象b:
```java
A b = new B();
b.show();
```
则输出结果是?
A:第一个是ClassA :a=1 d=2.0
第二个是ClassA :a =1 d=2.0
ClassB : a=3.0 d=Hello World!
Q:heap和stack有什么区别?
A:堆和栈。栈存放对象的引用,堆存放对象实体。堆中的对象是有jvm的垃圾回收器负责回收。
Q:请描述下JVM加载class文件的原理机制。
A:JVM加载class是动态性的,也就是当“需要”的时候才会加载,这是也是为节约JVM内存来考虑的。同时JVM的类加载是父类委托机制,这个机制简单来讲,就是“类装载器有载入类的需求时,会先请示其Parent使用其搜索路径帮忙载入,如果Parent 找不到,那么才由自己依照自己的搜索路径搜索类”。
### Android基础部分
Q:如何适配不同屏幕分辨率的机型?
A:屏幕适配方式就多了去了。Android系统本身提供了很多适配方法,比如存放图片资源的drawable目录根据不同分辨率的手机提供了drawable-hdpi、drawable-ldpi、drawable-mdpi、drawable-xhdpi等多中目录。我们只需把适应不同分辨率的多套图片分别放到对应的目录中即可。Android的layout、values目录也提供了类似drawable的适配功能。但是在开发中,不可能针对不同的手机分辨率提供多种图片资源,这太耗费资源了。我们一般在写控件宽高的时候都会用dp单位取代pix单位。因为dp是一个相对单位,pix是绝对单位,使用dp替代pix也可以解决很多适配问题。dp跟pix之间可以通过公式进行转换。
Q:View和ViewGroup的关系是什么?View的绘制过程(主要方法)有哪些?
A:ViewGroup继承了View。onMesure、onLayout、onDraw。
Q:Activity和Task的区别及启动模式有哪些?
A:Activity运行Task中。Activity有四种启动模式。standard、singleTop、singleTask、singleInstance。standard:默认的启动模式,多个Activity位于同一Task中。singleTop,顾名知义就是Task栈顶只能有一个相同的Activity,singleTask就是一个Task中只有一个Activity,singleInstance就是一个Activity独享一个Task。
PS:关于Activity的四种启动模式其实还有更详细的说法,我在上面就简单介绍一下了,如果面试官需要问的更详细再往深处介绍就行了。
Q:如何注册BroadCastReceiver和Service?Service有什么特征,哪些情况会用到Service?
A:都可以通过AndroidManifest.xml进行静态注册。不过BroadCastReceiver可以在代码中通过registReceiver方法来注册。Service运行在后天进程中,一般需要在后台一直运行的任务会让Service来完成。比如我们的telephoneService、locationService等等。
Q:Android有哪些安全机制?
A:权限机制。我们的应用只要涉及到了用户的隐私、网络都需要在AndroidManifest.xml中进行声明,这样用户在安装的时候可以根据你申请的权限进行判断是否允许应用的某些行为。
Q:Handler机制的原理,内部是如何实现的?
A:Android中handler多用于主线程和子线程之间的通信,比如在Android中子线程是不允许修改UI的,如果修改只能让子线程给主线程通过handler发送message,然后主线程进行修改。Handler整个机制的实现,还依赖Looper、Message两个核心内容。在主线程中Android默认给我们创建了Looper,当我们通过handler.sendMessage()后,该消息被添加到MessageQueue中,Looper.looper中有个while(true)的循环不停的从消息队列中取消息。取消息的过程是线程阻塞的,这样不至于在没有消息的时候过多的耗费CPU资源。
Q:Thread和AsyncTask的区别是什么?
A:AsyncTask是封装好的线程池,比起Thread+Handler的方式,AsyncTask在操作UI线程上更方便,因为onPreExecute()、onPostExecute()及更新UI方法onProgressUpdate()均运行在主线程中,这样就不用Handler发消息处理了;
Q:说说MVC模式的原理,在Android中的运用。
A:MVC是Model、View、Controller三部分组成的。其中View主要由xml布局文件,或者用代码编写动态布局来体现。Model是数据模型,其实类似javabean,不过这些JavaBean封装了对数据库、网络等的操作。Controller一般由Activity负责,它根据用户的输入,控制用户界面数据的显示及更新model对象的状态,它通过控制View和Model跟用户进行交互。
Q:如何加载ndk库?如何在jni中注册native函数,有几种注册方式?
A:通过System.loadLibrary("xxx")进行加载。其实native有几种注册方式,自己当时并不知道,自己只知道一种注册方法,就是首先根据native 方法名,生成Java_com_xxx_MethodName(xxx,xxx);当然这个c/c++源码文件中需要引入jni.h,然后把这个c/c++源码编译成so文件。
自己后来百度了一下,网上有人数还有一种注册方式是动态注册,我就把关于动态注册的东西直接拷贝过来:
JNI 允许你提供一个函数映射表,注册给Jave虚拟机,这样Jvm就可以用函数映射表来调用相应的函数,就可以不必通过函数名来查找需要调用的函数了。Java与JNI通过JNINativeMethod的结构来建立联系,它在jni.h中被定义,其结构内容如下:
```c
typedef struct {
const char* name; //Java中函数的名字
const char* signature; //用字符串描述的函数的参数和返回值
void* fnPtr; //指向C函数的函数指针
} JNINativeMethod;
```
第一个变量name是Java中函数的名字。
第二个变量signature,用字符串是描述了函数的参数和返回值
第三个变量fnPtr是函数指针,指向C函数。
当java通过System.loadLibrary加载完JNI动态库后,紧接着会查找一个JNI_OnLoad的函数,如果有,就调用它,
而动态注册的工作就是在这里完成的。
1)JNI_OnLoad()函数
JNI_OnLoad()函数在VM执行System.loadLibrary(xxx)函数时被调用,它有两个重要的作用:
指定JNI版本:告诉VM该组件使用那一个JNI版本(若未提供JNI_OnLoad()函数,VM会默认该使用最老的JNI 1.1版),如果要使用新版本的JNI,
例如JNI 1.4版,则必须由JNI_OnLoad()函数返回常量JNI_VERSION_1_4(该常量定义在jni.h中) 来告知VM。
初始化设定,当VM执行到System.loadLibrary()函数时,会立即先呼叫JNI_OnLoad()方法,因此在该方法中进行各种资源的初始化操作很恰当,
2)RegisterNatives
RegisterNatives在AndroidRunTime里定义
syntax:
jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,jint nMethods)
Q:App在什么情况下会出现内存泄露?如何避免这些情况?
A:造成内存泄露的可能性有很多,我说几种吧,1)资源未及时释放,比如引用的io流资源、网络资源、数据库游标Cursor等没有释放2)注册的监听器、广播等未及时取消3)集合对象没有及时清理4)不良代码
避免上述问题,主要还看程序员知识掌握的程度和编码经验的多少,但是从技术角度考虑我们需要注意一些细节,比如,重复使用的资源可以考虑使用缓存技术、池技术。使用的任何资源都记得关闭或者异常处理,保证在恶劣的情况下也能使资源得到释放。对于图片的操作要注意缓存的使用,同时要记住对图片对象进行及时的回收。使用ListView的时候,尽量让ConvertView得到复用。
3)逻辑思考
Q:你让工人为你工作7天,给你工人的回报是一根金条,金条评分成7段,你必须在每天结束时给他们一段金条,如果只许你两次把金条弄断,如何给你的工人付费?
PS:因为上面的问题自己回答的都比较溜,所有这个逻辑思考题,面试官直接说我想着你也会就不做吧。哈哈~面试官已经放弃继续考察我了,嗨皮。然后他去找老大去了,趁机我赶紧把笔试题给偷拍了下来(是不是阳哥胆子越来越大呀?!),这样才能大家看到真实的笔试题是什么样子滴。
哦,对了,上面的逻辑思考题我面试的时候是免试的,亲爱的黑马童鞋们你们知道答案吗?
## 2. 第二轮面试过程问答精选:
旁白:面试我的应该是开发组部门的老大。胖胖的,黑黑的,矮矮的,从开始面试到结束,一直面带微笑。因为之前那个技术官已经面试过我的技术了,因此他也没问我技术,就是跟我瞎聊了一些关于Android方面的东西。因此详细内容这里就省略了,请大家直接进入下一关~duang~
## 3. 人事面试:
人事面试的问题,其实我在V4版本中也说过,基本所有的人事问的问题都大同小异,跟这个人事聊的唯一有趣的就是,由于公司正在装修,找不到面试我的办公地点,然后她竟然把我带到公司旁边的凉亭子下面,我们两个并排坐着,就聊起来了,知道的知道我们是在面试,不知道的估计还以为我们在谈恋爱呢
面试吐槽:
在前台我填写面试登记表的时候写的期望薪资是15k,他们也没有压低我工资,我知道我要少了。不过,没办法,谁让阳哥不懂行情,在投递简历的时候都是写着期望15k呢!想写个16、17、18都不好意思了,因此大家以后找工作可别学阳哥这么傻,能多要一定多要。
跟大家分享一个励志语句以结束本篇文章吧:相信梦想是价值的源泉,相信眼光决定未来的一切,相信成功的信念比成功本身更重要,相信人生有挫折没有失败,相信生命的质量来自决不妥协的信念。
录用Offer!
笔试题(在前台眼皮底下偷拍~)
# 6. 挑战公司No.6:聚信租赁
公司地址:上海市徐汇区漕溪北路398号汇智大厦28楼
面试时间:5月14日 14:00 PM.
面试结果:Android工程师,16K +入职送iPhone 6+每年出国旅游一次+补充住房公积金+至少14薪:victory:
面试过程:
14:00到公司前台,领了一大堆资料,然后让我在一间办公室做题。
14:00~14:30 填写面试登记表和性格测试。
14:30~15:20 两个技术官坐在我对面,同时面试我。
15:20~15:30 人事妹子跟我单聊公司薪资福利以及入职事宜。
疯狂的笔试+面试记录(前方内容“高能”:funk:,请准备高度精神集中前行):
## 1. 笔试
这家比较奇怪,是给了6页的笔试题,打开一看全是性格测试题。性格测试题只拍了一张图片,在该篇文章的结果。估计大多数童鞋都想遇到阳哥这样的狗屎运吧;P~阳哥的性格绝对没问题的,这个我可以保证哈~:P
## 2. 技术面试
竟然同时来了两个技术官面我,一大一小,一高一矮,并排坐在一起,一对二,好吧,阳哥还是首次遇到1:2的阵容,这下可有好戏看了。PS:阳哥是个没有见过世面的人,面试的时候上个31层高的楼都兴奋的不得了,上去以后,发现上错楼了~糗事说多了都是泪:#,要不是阳哥有着过五关斩六将身经百战的成功经验,估计要吓尿:loveliness:。好吧开始吧,阳哥命中注定必有次劫,看来是躲不过了。
Q:你做一个自我介绍吧?
旁白:其实遇到好几家面试官都让我做自我介绍了,该如何自我介绍阳哥估计都会背了,好玩(恶心)的是在万达信息面试,面试了3个技术官,每个人都分别让我做了自我介绍,尼玛,他们3个就不会沟通一下要问我啥吗,一个问题至于问我3遍吗~:funk:阳哥是敢怒不敢言,毕竟在人家的地盘。
PS:自我介绍的内容就不说了,每个人都是独特的,我就跟大家说一下应该如何自我介绍吧。
一个优良的自我介绍会给面试官留下深刻的印象,大部分情况下,所谓的面试好坏其实看的就是你给面试官留下的印象怎么样了,我们用俗语叫感觉。
自我介绍应该分以下几个部分,按照一定的逻辑连贯起来。如果连贯不起来,或者不够熟练一定在台下多背几遍,多讲几遍,但是面试的时候不要说的跟背过似的,高境界就是让面试官感觉你是临场发挥的,却又比背的都好。
- 个人基本信息(姓名、年龄、老家、居住地等)
- 自己来自哪里(工作地点),是干什么的(给自己一个清晰的定位,比如:我是一名Android开发工程师),担任过什么职务、做过什么样的项目
- 自己为何来贵公司面试
- 最后祝愿(希望能得到贵公司的认可等等,不用太多,一两句话就ok)
Q:介绍一下你做过的项目吧?
PS:黑马那么多项目,随便准备3个就ok了。
介绍项目大概的思路如下:
1)这个项目是干什么的(比如是一个类似网易新闻的地方新闻客户端,或者类似美团的o2o,或者类似豌豆荚的一个应用市场,或者类似淘宝的购物平台)?解释就是拿一个市场上耳熟能详的应用跟自己的应用做类比,省的面试官听的云里雾里的。
2)自己负责了哪些模块(功能)的职责(比如负责系统的架构,核心代码的编写,xx功能模块的开发等等)
3)自己在这个项目中担当的责任(比如,这个项目是自己独立开发的,这个项目是和另外一个同事一起架构一起开发的,这个项目是自己负责了几个核心模块)
4)项目中都用到了哪些技术
5)从项目中学到了哪些东西(可以从技术方向和业务两个方向入手)
旁白:面试官问的很多技术性问题跟之前问的都大同小异,因此这里只给出有特色且技术含量高的。阳哥正在写面试宝典,该宝典核心内容针对的还是技术问题,阳哥会从javase基础到javase高级,从Android基础到Android高级以及到Android项目依次展开分析,其次也会写一些常见的非技术性问题,敬请期待~
Q:①在Listview的优化中,我们为何使用ConvertView?②为何使用ViewHolder?③你认为哪个更能解决问题?④你认为view.inflate和view.findviewById哪个更耗时,为什么?⑤如果这两个AP让你重新写,你怎么写?
PS:上面的问题,阳哥认为是面试以来遇到很难的一个,也是很有技术含量的一道题。前一半问题还好回答,最后一个问题真的需要发挥想象了。
A:①使用ConvertView可以实现对view的复用,这样大大节约了每次创建对象的时间,提升了ListView的显示效率。②使用ViewHolder作为内部类,可以将view的子控件封装在ViewHolder类中,然后通过View.setTag(ViewHolder)将view和ViewHolder进行绑定,这样我们就不用每次都调用view的findViewById(id)方法来查找控件。③使用ConvertView解决了一大部分问题,使用ViewHolder实现了控件换时间的问题,因为给View对象设置一个Tag本身就是占用内存的,因此ViewHolder的使用还是需要区分不同的应用场景的, 没有绝对的好与不好。如果内存足够需要高效则ViewHolder建议使用,否则不建议使用。④当然是view.inflate耗时,这个函数完成的功能是把xml布局文件通过pullParser的形式给解析到内存中,需要io,需要递归子节点。⑤我其实还不太相信我写出来的代码比Google官方写的好,如果让我写的话我可能会这样考虑,当用户在使用view.inflate的时候将多个id作为数组添加到形参中,这样在初始化view的使用我就可以给这个view直接调用setTag方法绑定需要的子控件。不过这个原生方法其实也应该保留共不同的需求使用。
PS:技术面试时间并不长,我回答了几个之后,他们两个大眼瞪小眼,A看看B问:你还有什么问的吗?B说我没有,你还有吗?A说我也没了。那行,接下来,他们就让我等人事了。
## 3. 人事面试:
人事问的问题都差不多,我在上一篇也说过,这里就不说人事的问题了。唯一要给大家爆料的就是人事给我讲的他们公司的福利待遇,可以用土豪不差钱形容:)
人事说:入职后转正即送iPhone 6一部。
我(阳哥)说:我是做Android开发的,给我iPhone 6干嘛
旁白:你认为阳哥真不想要iPhone 6吗?为了显示咱的高度敬业精神,毕竟咱是做Android开发的,更需要的是Android手机,决不能像iPhone低腰(ni dao shi gei wo ya)!
人事说:我们Android开发人员也会额外配Android机的,iPhone6可以生活用。
旁白:我去~这就是没见过世面的阳哥,当时的表情。
人事说:转正满一年,每年都有一次出国旅游。
我(阳哥)说:哦,咱们公司还挺不错的嘛!
旁白:不知说啥好了,只能用表情来形容了,阳哥至今没出过国,国外啥个样子嘛,
人事说:我们一般一年更少发14薪,都是介于14~16薪之间,具体发多少要看个人平时的一个KPI考核了。
我(阳哥)说:哦,这样呀,还行吧。
## 面试吐槽:
在家公司的人事跟我算了基本工资16k+各种补助1k=17k+。每年出国旅游,入职送iPhone,补充住房公积金,好吧,阳哥受宠若惊了。自己回来会百度了一下,终于搞明白这家公司为何这么奢侈!不多说,看图吧。
跟人事面试的时候,人事说他们在上海总部目前有大概100多名员工,阳哥不懂经济,不知道100多人的公司能融资13个亿是个什么样的概念?这再次验证了阳哥的那句千古流传的话语,只要技术好,公司不差钱!
================================================
FILE: docs/android/Android-Interview/经验分享/杭州找 Android 工作的点点滴滴.md
================================================
## 写在前面的话
我从 14 年毕业到现在一直待一个三线城市,就用 C 市 代替吧。地方很小,适合居住,但不适合 it 开发,城市很小、圈子很小,it 不发达,想要在 it 上面有出路的还是得去北上广深大城市。我在这个城市呆了三年左右由于自己的一些私事所以趁机就出来想找个大城市呆呆,原本打算去其他城市的,后来稀里糊涂的来到了杭州,在朋友这呆了半个月,直到找到工作。我是 17 年 3 月 25 号就辞职了,递交了辞职申请之后然后就跑去云南玩了一圈之后才想到要找工作的,然后就来杭州了,以上就是大概背景,接下来就写写关于在杭州找一份关于 Android 开发的工作中所遇到的人和事,不看不知道,原来世界真的很大各种人都有,果真印证了一句话:林子大了,什么鸟都有。
## 简历
面试之前,当然得准备一份简历啦,我的简历是当年刚毕业的时候写的一份简历,这里面用到的模板是 [乔布简历]() http://cv.qiaobutang.com/ 里面的简历模板不错(哈哈,这不是给它打广告的,我一直用这个,感觉不错就推荐了)。简历模板找到了,下面就是内容了,俗话说,要想找到好工作,一个好的简历必不可少的。因为公司越大的话,投递的人肯定越多,HR 筛选的时间就少了,所以简历有亮点就能打动HR,这样才能有面试资格,有了这个面试资格后才有可能得到这个工作机会,有的人写了简历投给公司后,就像石沉大海一样,毫无音讯,所以,如果有小伙伴,投了简历但是没有回应,不妨修改一下简历,但这里修改简历不是要你去造假,这里面有个梗,待会说~,写完了简历,接下来就是投简历了,有几个渠道可以找工作:
- 内推,内推的质量是最高的,但也是最难的。
- 第三方招聘网站,如 拉钩,51Job,智联招聘,猎聘同道等。
就以我而言,使用上面四种方式进行对比,拉勾网上面公司质量还是不错的,但是HR筛选简历这关有点问题,里面给出的筛选不通过理由都是一样的。51job 和智联招聘两者类似,都差不多,我就是在智联招聘上面找到工作的。猎聘同道里面猎头比较多,我第一次面试就是上面的猎头进行联系的。总的而言,前三个多投投简历,重点放在智联招聘和拉勾网上面,其他也可以稍微投投~
## 面试
经过上面简历这个步骤,相信我们能够接到一些公司的面试邀请的,在接受公司面试邀请之前,我们得复习面试中所遇到的一些基本知识,主要有 Java 和 Android 这两方面的面试知识。
- Java 基础知识,主要有面向对象三大特性及理解,接口与抽象类、泛型、线程池、集合框架、设计模式、常用算法等知识点。
- Android 知识,主要就是一些常用的知识,待会儿给出一些链接。
以上是专业知识准备,还得准备一些其他人文方面的知识,譬如自我介绍啊、兴趣爱好啊之类的。
有了上面的知识基础,我们就可以上面进行面对面接触啦,我总共大概用了 10 天左右时间,面试了大概 15 家公司,其中有三家是明确拒绝我的,还有四家是我明确拒绝他的,还有几家我对比了一下,然后选择了一个性价比比较高的公司的。在这些公司里面,花样百出,有的公司不知道怎么想的,想花一年工作经验的工资找一个三年工作经验的人,这是典型的想得美。还有的公司忽悠你,就是变相的让你加班,我问他工资能给多少,他说看你能力而定,能力多大,工资多高,我说具体个数,如果我面试通过了,你能不能给我准确的数,他就不说话了,而且是早上 10 点上班,晚上 9 点下班,呵呵,不评价,忽悠应届生呢吧~
印象最深的一家公司,地址是 https://www.lagou.com/gongsi/191783.html 没错,里面的评论就是我评论的,刚进去,给人的感觉,公司环境还不错,宽敞明亮的,然后 HR 给了我 A4 纸,正反面,填写个人的信息,详细程度令人咋舌。好不容易花了几分钟填完之后又给我整整三张面试题,没错,是整整三张,题目很多很多,让我做,哎,我也好忽悠,第一次碰到这种情况,所以就按部就班老老实实的做完了,花了 20 分钟,做之前还把我的手机给收了,娘的,当成学校考试呢啊???更奇葩的还在后面,做完面试题目之后,就开始了面试,那个面试官好像是子公司分责人吧,类似于总经理吧,看着我的简历,竟然问我有没有造假???WTF!!!还跟我说,他要想查的话很快就能查到了,我就无语了,我的简历竟然能让他怀疑我造假了,我的简历是有多雷人啊!!!接着就开始问我各种知识点,回答出来 95 以上吧,有几个平时没接触过,所以不知道怎么回答,最后面试结束了,没什么问题就开始讨论工资的问题,他看了我的期望薪水,问我,为什么翻了一倍?我跟他说,我以前呆的城市,非常小,基本连三线都不到,房价只有几千块,跟杭州能比吗???然后他就无语了,我就问他,为什么杭州房价比 C 房价高出 4~5 倍,你还想工资都差不多???面试简章上面的薪水范围跟实际给出的范围严重不符,我估计这家公司就是想把人先忽悠过去,然后开始各种压价,这太他么的可耻了,最后果断被我给拒绝了,而且是当面拒绝,没有留有情面,给再多也不会去的,这是情怀问题,感觉对程序员不尊重!!!以后大伙找公司,注意这家公司,过来人的经验~
上面就是我遇到的印象比较深刻的一家公司。接下来我们就来总结一下面试过程中提出的各种问题,如果有需要的小伙伴可以参考一下。
## 面试问题
### 关于人文方面的问题
- 先介绍一下你自己?
- 你有什么兴趣爱好?
- 你平常空闲时间会干什么,看哪些书,有什么心得体会?
- 你为什么要从上家公司离职?
- 如果面试过了的话,就会问你的期望薪资,然后就开始各种压榨你。
### 关于 Java 方面的问到的知识点
- 面向对象的三大特性,如何理解其中的多态?
- JVM 的内存模型?
- String、StringBuilder、StringBuffer 的区别,StringBuffer 是如何实现线程安全的?
- 了解过 HTTP 吗?说说它的特点,它里面有哪些方法,有了解过吗?知道 HTTPS 吗?这两者有什么区别?
- 你平常是怎么进行加密的?MD5 加密是可逆的吗?
- 接口与抽象类的区别?static 方法可以被覆盖吗?为什么?
- 创建线程的方式,他们有什么区别?知道线程池吗?说说对线程池的理解?
- 你了解过 Java 的四种引用吗?分别代表什么含义,他们有什么区别?
- Java 中关于 equals 和 hashcode 的理解?
- 关于 Java 中深拷贝和浅拷贝的区别?
- 简单的说下 Java 的垃圾回收?
- 了解过 Java 的集合吗?说说 HashMap 的底层实现原理?ArrayList 和 LinkedList 的区别?Java 集合中哪些是线程安全的?
- 如何实现对象的排序?
- 知道 ThreadLocal 吗?说说对它的理解?
- 在你写代码的过程中有使用过设计模式吗?你知道哪些?为什么要这样用,能解决什么问题?
- 了解注解吗?了解反射吗?为什么要使用反射?
- 数据结构中常用排序算法?
以上就是关于 Java 所问道的知识点,记得不是太清楚了,待补充。。。
### 关于 Android 方面的问到的知识点
- Activity 的生命周期是什么? onPause 和 onStop 有什么区别?
- Android 五种布局的性能对比?
- Android 四大组件是什么?分别说说对它们的理解?
- 关于 Service 的理解?它的启动方式有什么区别?
- 了解 fragment 吗?说说你对它的理解?
- 自定义过 view 吗?它的步骤是什么?说说你自定义 view 过程中出现的问题,以及是如何解决的?
- 刷新 view 的几种方式,他们有什么区别?
- Android 实现数据存储的几种方式?
- 如何实现 Android 中的缓存的,通过使用第三方库和自定义来分别说明一下缓存技术的实现?
- 如何实现 Activity 与 fragment 的通信?
- Android 5.0、6.0、7.0 新特性?
- Android 中的动画分类?
- 你以前是如何进行屏幕适配的?
- 说说 Activity 创建过程?
- Android 中如何与 JS 交互的?
- 了解 APP 的启动流程?
- 你知道哪些图片加载库?他们有什么区别?ImageLoader 的内部缓存机制是什么?是如何实现的?
- Android 中是如何实现异步通信的?
- 说说 Handler 内部实现原理?
- 使用过 AsyncTask 吗?说说它的内部实现原理?它有什么缺陷?如何改进?
- 知道 JNI、Binder 吗?说说你对它们的理解?
- 如何实现进程间的通信?
- 说说 Android view 和 viewGroup 的事件分发机制?
- 你开发过程中使用到了哪些第三方库?了解过他们的源码吗?
- 你了解广播吗?它与 EventBus 有什么区别?能互相实现吗?
- 你们网络请求是如何实现的?知道 Volley 吗?内部实现流程是什么?它与 OKHttp 有什么区别?
- 你了解哪些第三方功能?知道推送吗?它的原理是什么?
- 接触过 MVP 模式吗?说说看对它的认识?
- 知道 Android 中的多渠道打包吗?
- Android 签名机制的原理?反编译解压后的文件夹所包含的内容有哪些?
- 你了解过模块化、组件化开发吗?
- 开始开发 APP 如何进行架构?
- APP 工程模块是如何划分的?你是如何进行封装的?
- APP 是如何进行优化的?知道 OOM 吗?如何解决内存泄漏?
以上就是我这次面试过程中涉及到的一些关于 Android 方面的知识点,有点模糊了,全凭记忆,待补充....
经过上面的几个阶段,历时半个月,最终我找到了一家比较心仪的公司,整体的性价比个人感觉比较高,符合我的期望。以上便是我这次来杭州面试的点点滴滴,希望对有需求的小伙伴一些帮助~
请记住一点,薪水并不是唯一所要关注的重点,关键还得看看公司环境、领导、同事相处愉快不愉快?要不然给你再多的薪水,每天干的不爽,那不是很悲哀?
最后我会提供一些我面试准备阶段复习所用到的一些基础知识点链接,面试必问的一些基础原理一定得知道,不能含糊,要不然面试过程中必定会露马脚。有需要的小伙伴可以参考一下。
## 相关链接
- [Java面试题集](http://blog.csdn.net/dd864140130/article/details/55833087)
- [Android 名企面试题及涉及知识点整理](https://github.com/Mr-YangCheng/ForAndroidInterview)
- [40个 Android 面试题](http://www.devstore.cn/essay/essayInfo/7195.html)
================================================
FILE: docs/android/Android-Interview/经验分享/给培训班出来的一点不成熟的小建议.md
================================================
## 那些IT培训出来的Android工程师,希望你面试时涨点记性
这几天,公司在前程无忧上发布了招聘 Andriod 工程师广告。不到 3 个小时, hr 就抱怨说投递 Andriod 工程师的简历已经多达 300 份了。不得已将 Andriod 工程师招聘就下架,然后就去筛选简历了。
我也顺便看了看公司的要求,写的很简单,主要有:
> 经验:1 年以上。
>
> 有开发过蓝牙相关项目经验优先。
>
> 学历:大专及以上。
不知道 hr 和部门经理花费了多少时间挑选了 10 个人出来了。然后就预约了他们过来面试。
很荣幸,经理让我出一点面试题,还特意嘱咐,毕竟我们是软硬件的方案公司,已经有成熟的架构了。app 的难度不大,只要后面肯学是一样。就把第一轮面试的任务交给我。这里我并不是歧视培训机构出来的 Andriod 工程师,而是这几天面试下来,让我觉得很不可思议。如果有的人再用心一点,或许 offer 就是你的了。也希望不论你是正常毕业出来找工作,还是培训出来,自学的,或者中途转行的,都涨一点记性。
### 先说说笔试部分
有两道题基本上回答的很令人无语。
**1、写一写自定义 view 的思路。**
有几个人直接写了一个 onMeasure() 方法放那里了,就写了这几个单词,难道就不用多写一点解释。
我一看简历的工作经验,不是 2 年,就是 2 年半,还有 3 年的,怎么一个自定义 view 都没有遇到过?真的是让我怀疑你的工作经验是怎么来的。
重点是:有一个面试者就直接向我坦诚了自己是培训出来的。我瞬间就恍然了很多。我也是个打工的,没必要去指责他,只是给他讲了讲自定义 view,简历应该如何如何。这哥们居然临走时感谢我,要了我的微信。
**2、有没有访问过公司官网?如果有,谈谈你的意见。(这一题是 hr 要求加上去的。)**
结果很失望,只有 3 个人说访问过。
你去别人家公司面试,就不去访问别人一下官网,更何况,你投简历的时候,你就不用看公司简介,上上别人家公司官网。就算你是群投,收到面试通知后,都不用好好准备一下吗?去官网看看公司文化,团队,产品,特别是产品,大概就知道会用到哪些技术。
### 再说说口头问的部分
**1、搞清楚自己的开发工具**
1) 请问你现在开发使用的什么工具?
面试者:Android Studio
2) 那你现在主要使用哪个版本开发?
面试者:2.4
一瞬间,我直接懵了。Google 才放出正式的 2.3 版本。你就用起 2.4 呢? 后面还补充告诉我,自己去官网下载的,一直在使用
**2、不要刻意去讨好公司,技术的知识点不确定就不要随便回答。**
1) 你在简历上说自己做过蓝牙相关的项目,那你告诉我,一般使用蓝牙需要哪几个权限?
面试者:好像两个,两三个吧?
2) 那你能不能说一下?
面试者:我都是直接复制粘贴的
唉,你让我说什么好。你要是做过蓝牙相关开发,哪怕是你忘记了权限,你也可以说一下蓝牙连接的流程。就算以前没做过,招聘的岗位都告诉你了,有做过蓝牙项目 app 的优先,你就可以去补充一下 Andriod 关于蓝牙的知识点啊?
**3、别把别人上架的 app 当成自己的。**
1) 你有没有 app 上架过?
面试者:有
等他在应用市场找给我的时候,我一看就傻眼了,下载量破 500 万了,一看开发者就不是你。唉,我当时就想,兄弟啊,你没有可以告诉我,就算找一个别人的,能不能不要这么多下载量的?更何况,国内 Andriod 应用市场这么多,想自己的 app 上架都不是什么难事。
更可况,面试要求你,也没有说非要你上架 app。毕竟我们公司的 app 的难度还好。
**4、Andoid 6.0 权限的处理。**
1)在实际开发中,你说如何处理 6.0 以上手机权限问题的。
面试者:我们开发的 app 不需要适配 6.0 啊。
2)要是客户的手机是 6.0 的,客户要求你的 app 项目适配 6.0 的呢?
面试者:不会吧,都不用适配 6.0 的
你不是都有两三年开发经验了? 6.0 以上权限适配属于最基本的知识。随便说个思路,先申明权限,到用的时候,对高版本手机进行判断撒的……都是可以的,实际开发项目时,又不是不让你上网去学习研究。
唉……不知道该怎么说好了!
拒绝做面试题的!
有两个过来面试的,直接告诉我:
我写不好,能不能直接说啊!
我也只好同意了,毕竟从那么多简历里面,把你们筛选出来是多么地不容易。结果,好是令人失望。
如果你没有过硬的技术,请不要随便拒绝面试题。
## 后记
那个坦诚告诉我是培训出来的人,晚上发信息告诉我一些信息。
他们说 Andriod 面试,不用做题的?
现在企业喜欢经验多的,我们都是被要求写几年经验。这样才有面试机会。
你们招聘公司职位要求的技术不是随便写的吗?
大家都不容易,但是做技术这一行,还是需要硬实力。再怎么包装你有几年经验,拿到面试通知时,为什么不去好好准备面试,去背诵知识点。你连最起码的别人公司的官网都不上,你又有什么话语权?
哪怕你没有 app 上过架,确实是刚毕业,转行,或者刚培训出来的,如果临时抱佛脚,复习了公司要求的知识,这个 offer 就属于你的了。毕竟还有 3 个月试用期。
不论什么原因让你的简历如何完美,但是还请你的技术能够跟上。我所知道的,同事,朋友做 IT 的,有的是跨专业,有的是高中,有的是培训出来的,既然他们都行,请你也行!
================================================
FILE: docs/android/Android-Interview/经验分享/腾讯公司程序员面试题及答案详解.md
================================================
今天给大家带来的是腾讯的面试题,觉得有用的亲,赏个脸,轻点上面蓝色黑马程序员几个字关注我吧!
**1、腾讯笔试题:const的含义及实现机制const的含义及实现机制,比如:const int i,是怎么做到i只可读的?**
const用来说明所定义的变量是只读的。
这些在编译期间完成,编译器可能使用常数直接替换掉对此变量的引用。
**2、腾讯笔试题:买200返100优惠券,实际上折扣是多少?**
到商店里买200的商品返还100优惠券(可以在本商店代替现金)。请问实际上折扣是多少?
由于优惠券可以代替现金,所以可以使用200元优惠券买东西,然后还可以获得100元的优惠券。
假设开始时花了x元,那么可以买到 x + x/2 + x/4 + ...的东西。所以实际上折扣是50%.(当然,大部分时候很难一直兑换下去,所以50%是折扣的上限) 如果使用优惠券买东西不能获得新的优惠券,那么总过花去了200元,可以买到200+100元的商品,所以实际折扣为 200/300 = 67%.
**3、腾讯笔试题:tcp三次握手的过程,accept发生在三次握手哪个阶段?**
accept发生在三次握手之后。
第一次握手:客户端发送syn包(syn=j)到服务器。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个ASK包(ask=k)。
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1)。
三次握手完成后,客户端和服务器就建立了tcp连接。这时可以调用accept函数获得此连接。
**4、腾讯笔试题:用UDP协议通讯时怎样得知目标机是否获得了数据包用UDP协议通讯时怎样得知目标机是否获得了数据包?**
可以在每个数据包中插入一个唯一的ID,比如timestamp或者递增的int。
发送方在发送数据时将此ID和发送时间记录在本地。
接收方在收到数据后将ID再发给发送方作为回应。
发送方如果收到回应,则知道接收方已经收到相应的数据包;如果在指定时间内没有收到回应,则数据包可能丢失,需要重复上面的过程重新发送一次,直到确定对方收到。
**5、腾讯笔试题:统计论坛在线人数分布 求一个论坛的在线人数,假设有一个论坛,其注册ID有两亿个,每个ID从登陆到退出会向一个日志文件中记下登陆时间和退出时间,要求写一个算法统计一天中论坛的用户在线分布,取样粒度为秒。**
一天总共有 360024 = 86400秒。
定义一个长度为86400的整数数组int delta[86400],每个整数对应这一秒的人数变化值,可能为正也可能为负。开始时将数组元素都初始化为0。
然后依次读入每个用户的登录时间和退出时间,将与登录时间对应的整数值加1,将与退出时间对应的整数值减1。
这样处理一遍后数组中存储了每秒中的人数变化情况。
定义另外一个长度为86400的整数数组int online_num[86400],每个整数对应这一秒的论坛在线人数。
假设一天开始时论坛在线人数为0,则第1秒的人数online_num[0] = delta[0]。第n+1秒的人数online_num[n] = online_num[n-1] + delta[n]。
这样我们就获得了一天中任意时间的在线人数。
**6、腾讯笔试题:从10G个数中找到中数 在一个文件中有 10G 个整数,乱序排列,要求找出中位数。内存限制为 2G。**
不妨假设10G个整数是64bit的。
2G内存可以存放256M个64bit整数。
我们可以将64bit的整数空间平均分成256M个取值范围,用2G的内存对每个取值范围内出现整数个数进行统计。这样遍历一边10G整数后,我们便知道中数在那个范围内出现,以及这个范围内总共出现了多少个整数。
如果中数所在范围出现的整数比较少,我们就可以对这个范围内的整数进行排序,找到中数。如果这个范围内出现的整数比较多,我们还可以采用同样的方法将此范围再次分成多个更小的范围(256M=2^28,所以最多需要3次就可以将此范围缩小到1,也就找到了中数)。
**7、腾讯笔试题:两个整数集合A和B,求其交集两个整数集合A和B,求其交集。**
- 读取整数集合A中的整数,将读到的整数插入到map中,并将对应的值设为1。
- 读取整数集合B中的整数,如果该整数在map中并且值为1,则将此数加入到交集当中,并将在map中的对应值改为2。
通过更改map中的值,避免了将同样的值输出两次。
**8、腾讯笔试题:找出1到10w中没有出现的两个数字 有1到10w这10w个数,去除2个并打乱次序,如何找出那两个数?**
申请10w个bit的空间,每个bit代表一个数字是否出现过。
开始时将这10w个bit都初始化为0,表示所有数字都没有出现过。
然后依次读入已经打乱循序的数字,并将对应的bit设为1。
当处理完所有数字后,根据为0的bit得出没有出现的数字。
首先计算1到10w的和,平方和。
然后计算给定数字的和,平方和。
两次的到的数字相减,可以得到这两个数字的和,平方和。
所以我们有
x + y = n
x^2 + y^2 = m
解方程可以得到x和y的值。
**9、腾讯笔试题:需要多少只小白鼠才能在24小时内找到毒药有1000瓶水,其中有一瓶有毒,小白鼠只要尝一点带毒的水24小时后就会死亡,至少要多少只小白鼠才能在24小时时鉴别出那瓶水有毒?**
最容易想到的就是用1000只小白鼠,每只喝一瓶。但显然这不是最好答案。
既然每只小白鼠喝一瓶不是最好答案,那就应该每只小白鼠喝多瓶。那每只应该喝多少瓶呢?
首先让我们换种问法,如果有x只小白鼠,那么24小时内可以从多少瓶水中找出那瓶有毒的?
由于每只小白鼠都只有死或者活这两种结果,所以x只小白鼠最大可以表示2^x种结果。如果让每种结果都对应到某瓶水有毒,那么也就可以从2^x瓶水中找到有毒的那瓶水。那如何来实现这种对应关系呢?
第一只小白鼠喝第1到2^(x-1)瓶,第二只小白鼠喝第1到第2^(x-2)和第2^(x-1)+1到第2^(x-1) + 2^(x-2)瓶....以此类推。
回到此题,总过1000瓶水,所以需要最少10只小白鼠。
**10、腾讯笔试题:根据上排的数填写下排的数,并满足要求。**
根据上排给出十个数,在其下排填出对应的十个数, 要求下排每个数都是上排对应位置的数在下排出现的次数。上排的数:0,1,2,3,4,5,6,7,8,9。
**11、腾讯笔试题:判断数字是否出现在40亿个数中?**
给40亿个不重复的unsigned int的整数,没排过序的,然后再给几个数,如何快速判断这几个数是否在那40亿个数当中?
答案:unsigned int 的取值范围是0到2^32-1。我们可以申请连续的2^32/8=512M的内存,用每一个bit对应一个unsigned int数字。首先将512M内存都初始化为0,然后每处理一个数字就将其对应的bit设置为1。当需要查询时,直接找到对应bit,看其值是0还是1即可。
================================================
FILE: docs/android/Android-Interview/经验分享/阿里+百度+CVTE面经合集.md
================================================
早上11点,刚刚收到阿里的offer,也算是给自己三个月的春招画上了一个还算圆满的句号。
先介绍一下本人的基本情况:陕西普通一本非计算机专业大三学生,非985211。主要技能C/C++/Java/数据结构/算法。
这三个月的经历,首先确实在技术上确实通过不断的面试有了很大的提升,其次在各种面试经验上也有了一些心得。
眼看春招已经基本结束,所以将这段时间的经历写在牛客上,希望能够帮助大家,在秋招上斩获更满意的offer。
所以就拿我收到offer的三家重点说说。(按时间排序)
## 一、CVTE:
CVTE的实习生招聘非常早,笔试完了就收到通知,预约了面试时间就早早去了,两轮技术面试一轮HR面试,进行的很顺利,3月26号就已经发了offer。
一面:面试官非常亲切,其实我当时是第一次参加现场面试,楼主比较怂,其实现场紧张的不要不要的,自我介绍的时候说完了姓名年龄和专业之后,就卡住说不下去了。面试官看在眼里疼在心上,于是很关心的对我说,没事没事不要紧张,这样吧,我们先写两个算法放松一下(Excuse me?)不过好在面试官出的题很简单,第一个是二分查找,我用递归和非递归各写了一遍,重点就在于下标的控制;另一道是在N个数中求前M大个数,其实也很简单,思路就是使用快速排序的思想,每一次当把一个数字放在正确的位置上的时候跟M进行比较,其实在剑指offer上有原题。好在寒假的时候把剑指offer刷了很多遍,所以很快也写出来了。我个人觉得在写代码之前,有很多事情需要跟面试官进行交流,比如函数的参数、返回值、还有一些异常情况的处理,提前跟面试官约定好。比如我在写代码之前,就问面试官:假设参数是`(int *arr, int length, int m)`,在这种情况下,可能会有四种情况会导致程序出现异常情况
- arr ==NULL
- length <= 0
- m > length
- m <=0
询问他在这四种情况下我们该如何处理?”面试官听完之后一下就有兴趣了,及时跟面试官沟通,一方面是防止思路与面试官预期的差距太大,面试官出的题,因此他有责任让面试者明白他的意思,另一方面表现我们积极思考,向面试官展示我们的思考能力。可能之前的算法写的太顺利,所以给自己建立了蜜汁自信,并且面试官对我的第一印象也好,后面的问题回答的很轻松,有struts2和SpringMVC的区别、Spring中IoC和AOP的理解,不过在数据库方面被难住了,在MySQL中如何定为查询效率较慢的SQL语句,比如慢查询日志、EXPLAIN关键字还有PROFILES等。但是总得来说,一面进行的很顺利。
二面:CVTE的面试流程是,如果一面的面试官觉得通过了,就会示意现场接待的姐姐,姐姐会安排在场外休息一下,二面大概在十分钟之后进行;而如果觉得不符合要求,姐姐就会亲切地告诉面试者,今天的面试结束了,可以先回去等消息。等了十分钟之后,二面如约而至,二面是一个年纪稍大,但是很有风度的中年人,事后学长说那是他们部门的BOSS,面试官让我设计了一个场景,青蛙爬井,就是画画UML,两个类图,和他们的关系。最后扩展成面向接口的思维,不得不说BOSS确实功力深厚,纠正了我很多问题,最后才勉强满意。然后就是分析项目,挑了一个我比较熟悉的,问了很多问题,比如页面的跳转关系、我所做的功能模块,让我一边画图一边解释,我自认项目准备的还算充分,因为都是自己做的,所以这部分也算顺利。后面就没有什么技术问题,问了一下我什么时候能来实习,还有在校的经历,同学之间是如何评价我的,然后就结束了。
HR面:晚上回到宿舍就有短信通知,第二天参加终面,当时还在跟女朋友看电影啊,荒原猎人。正看到小李子跟熊搏斗,女朋友吓得不敢看,广州的电话来了,让我预约第二天的终面并且填一个单子。慌慌张张跑回去完成。印象里面那个问卷问的很全面,比如家庭状况、为什么选择去广州、什么情况下会放弃这份工作、小时候印象最深的一件事情、列举出近期让你伤心的事情以及你是如何处理不良情绪的。如果各位到了这一步,一定要谨慎作答,这些问题都会列入到综合评测中。后面的面试就是把这些问题现场问一遍,说是HR面,但我总感觉是高管面,一个高管面三个面试者。
面试出来之后,等做到地铁上,广州负责的CVTE校招的学长就已经告诉我通过了,效率非常高。3月26号拿到的offer,这是春招的第一个offer,当时的心情还是很激动的。
## 二、百度
百度是学长内推,技术面是两轮技术面试。
一面:简单的自我介绍,因为是电话面试,所以流畅了很多(你们懂的)。一个小时满满的技术问题,所以就不用向上面再赘述了,直接上干货
1.是否了解动态规划
动归,本质上是一种划分子问题的算法,站在任何一个子问题的处理上看,当前子问题的提出都要依据现有的类似结论,而当前问题的结论是后
面问题求解的铺垫。任何DP都是基于存储的算法,核心是状态转移方程。
2.JVM调优
其实我没有实际的调优经验,但是我主要介绍了一下JVM的分区、堆的分代以及回收算法还有OOM异常的处理思路
3.分别介绍一下Struts2和Spring
不用多说,这方面比我答得好的同学肯定大有人在,就不出丑了
4.职责链模式(设计模式)
GoF经典设计模式的一种
5.实践中如何优化MySQL
我当时是按以下四条依次回答的,他们四条从效果上第一条影响最大,后面越来越小。
- SQL语句及索引的优化
- 数据库表结构的优化
- 系统配置的优化
- 硬件的优化
6.什么情况下设置了索引但无法使用
- 以“%”开头的LIKE语句,模糊匹配
- OR语句前后没有同时使用索引
- 数据类型出现隐式转化(如varchar不加单引号的话可能会自动转换为int型)
7.SQL语句的优化
- order by要怎么处理
- alter尽量将多次合并为一次
- insert和delete也需要合并
8.索引的底层实现原理和优化
B+树,经过优化的B+树
主要是在所有的叶子结点中增加了指向下一个叶子节点的指针,因此InnoDB建议为大部分表使用默认自增的主键作为主索引。
9.HTTP和HTTPS的主要区别
10.Cookie和Session的区别
11.如何设计一个高并发的系统
- 数据库的优化,包括合理的事务隔离级别、SQL语句优化、索引的优化
- 使用缓存,尽量减少数据库 IO
- 分布式数据库、分布式缓存
- 服务器的负载均衡
12.linux中如何查看进程等命令
13.两条相交的单向链表,如何求他们的第一个公共节点
很简单的链表题目,博客上的做法一搜一大把,我记得当时答在兴头上,又给面试官解释了一下如何求单向局部循环链表的入口,链表中很经典的问题(其实链表也就那几个常用算法,比如逆制、求倒数第K个节点,判断是否有环等)
大概八十分钟吧,最后问面试官有没有对我的意见或者建议,面试官说觉得我今晚的面试表现比简历上写的更出色。。。对面试官的好感度瞬间飙升
二面:可能一面面试官对我的评价还算不错,二面面试官一口气考了我11个设计模式(手动微笑),对,是11个设计模式,有直接提问,也有在场景设计中引导我使用。总共加起来11个,分别是:单例模式、简单工厂模式、工厂模式、抽象工厂模式、策略模式、观察者模式、组合模式、适配器模式、装饰模式、代理模式、外观模式。然后就是设计一个公司下有部门、部门下有经理和员工,经理可以管理经理和员工这样的一个模型,组合模式一套用就行了。后面还问了几个非技术问题,比如和产品、测试发生矛盾了怎么处理,答应的任务发现完成不了该如何处理等,大家如果遇到请随意装逼。
百度给我最大的印象就是每次新的面试,面试官一定会问什么时候能来实习,能够实习多长时间,答案符合要求了才进行下面的面试。据说百度今年要求6个月的实习时间,回答两三个月的都再无下文。
机智的我不管哪家公司问都是说从即日起到大四毕业,中间出了期末考试和毕业设计,都能参与实习,近期就能参加实习。不是故意想骗人,只是目前还没有和HR谈条件的筹码,这样说了就算最后去不了,也算是一次面试机会,如果一开始就拒绝的话,连面试机会都没有。等到技术面试结束了,跟一开始比,就有了谈条件的筹码,这个时候大家再根据情况合理要价
三月的CVTE、四月的百度,现在该说五月的阿里了
## 三、阿里巴巴
阿里巴巴其实同样的简历,在内推阶段直接简历被刷,非常尴尬。但是有幸笔试蜜汁通过,所以收到了参加现场面试的通知。
一面:一面的面试官长得超级像张家辉,整个面试过程,我满脑子都是《激战》里面的老拳王,当他朝我提问的时候,我就想到激战里面的经典台词“怕输,你就会输一辈子”。不知道面试官老师有没有看出我表情的异样~闲话不多说,上干货。
## 1. 二叉树的遍历方式,前序、中序、后序和层序
二叉树本身就是一个递归的产物,那前序举例,访问根节点,然后左节点,再右节点,如果左节点是一棵子树,那么就先访问左子树的根节点,再访问左子树的左节点,依次递归;而层序,使用队列进行辅助,实现广度优先搜索
## 2. volatile关键字
给大家推荐两本书:《Java多线程实战》和《Java并发编程的艺术》,这会儿已经三点了,脑子有点乱书名可能未必无误。对Java实现多线程描述的非常详细。现场跟面试官老师扯了很多,我在这里挑主要的说
volatile关键字是Java并发的最轻量级实现,本质上有两个功能,在生成的汇编语句中加入LOCK关键字和内存屏障
作用就是保证每一次线程load和write两个操作,都会直接从主内存中进行读取和覆盖,而非普通变量从线程内的工作空间(默认各位已经熟悉Java多线程内存模型)
但它有一个很致命的缺点,导致它的使用范围不多,就是他只保证在读取和写入这两个过程是线程安全的。如果我们对一个volatile修饰的变量进行多线程下的自增操作,还是会出现线程安全问题。根本原因在于volatile关键字无法对自增进行安全性修饰,因为自增分为三步,读取-》+1-》写入。中间多个线程同时执行+1操作,还是会出现线程安全性问题。
## 3. synchronized
- 锁的优化:偏向锁、轻量级锁、自旋锁、重量级锁
- 锁的膨胀模型,以及锁的优化原理,为什么要这样设计
- 与Concurrent包下的Lock的区别和联系
Lock能够实现synchronized的所有功能,同时,能够实现长时间请求不到锁时自动放弃、通过构造方法实现公平锁、出现异常时synchronized会由JVM自动释放,而Lock必须手动释放,因此我们需要把unLock()方法放在finally{}语句块中
## 4. concurrentHashMap
两个hash过程,第一次找到所在的桶,并将桶锁定,第二次执行写操作。
而读操作不加锁,JDK1.8中ConcurrentHashMap从1600行激增到6000行,中间做了很多细粒度的优化,大家可以查一下。
## 5. 锁的优化策略
- 读写分离
- 分段加锁
- 减少锁持有的时间
- 多个线程尽量以相同的顺序去获取资源
等等,这些都不是绝对原则,都要根据情况,比如不能将锁的粒度过于细化,不然可能会出现线程的加锁和释放次数过多,反而效率不如一次加一把大锁。这部分跟面试官谈了很久
## 6. 操作系统
这部分基本是跪着跟面试官交流的,因为非计算机专业,对这个楼主确实比较欠缺
不过好在前面的表现还可以,顺利通过了。
二面:十分钟休息,二面面试官先问了一些无关紧要的问题,比如学校的专业课、平时如何学习新技术等等,然后切入正题,让我选一个熟悉的项目,三分钟画出大体架构图,我在项目部分的准备还算充分,但是面试官真的水平非常高。
在项目部分,可能是我整个阿里面试过程中最提心吊胆的,缓存的使用,如果现在需要实现一个简单的缓存,供搜索框中的ajax异步请求调用,使用什么结构?我回答ConcurrentHashMap,可是内存中的缓存不能一直存在,用什么算法定期将搜索权重较低的entry去掉?我说先按热度递减放进一个CopyOnWriteArrayList中,保留前多少个然后再存回ConcurrentHashMap中,面试官说效率过低,有没有更高效的算法,我假装冥思苦想(用假装其实是因为,确实想不到方法)
后来面试官说其实这个问题有点难了,换一个,又跟我扯到线程的问题,大体就跟一面面试官问的差不多,就不赘述了。这部分感觉面试官还比较满意,就问题TCP如何保证安全性,我说三次握手、四次回收、超时重传、保序性、奇偶校验、去重、拥塞控制。还讲了滑动窗口模型。
后面又考了一些红黑树的问题,问到B+数,还有JDK1.8中对HashMap的增强,如果一个桶上的节点数量过多,链表+数组的结构就会转换为红黑树。
面试官问我项目中使用的单机服务器,如果将它部署成分布式服务器?我当时心里一惊,这个问题确实没有准备过,眼看就要被问死了,临时抖了个机灵,说有一次跟一个师兄尝试这么做的时候,遇到了session共享问题,然后成功地把面试官引向了session共享的问题,跟他讨论了10分钟左右的分布式系统中如何做到session共享。后面面试官可能也觉得我这部分
手写一个线程安全的单例模式,经典的不能再经典,没什么好说的,懒汉饿汉随便选一个。
还有一些MySQL的常见优化方式、定为慢查询等,回答的七七八八,之前面试总结的问题还有印象,所以感谢自己有面试完及时总结的习惯。
最后问了问我平时都如何学习、最近都在看什么书,来实习的话学校的考试如何解决等等。
面试官告诉我他的问题已经问完了,我看没有让我提问的意思,所以我起身跟面试官握了个手(我在参加现场面试的时候有这样的习惯,握手的同时跟面试官强调,“我很珍惜这次面试机会”)
二面出来之后挺紧张的,感觉自己答的还是有很多漏洞,可能面试官虽然发现了,但是觉得我态度不错,虚心学习,所以还是很幸运到了HR面,HR面就不多说了,只要不跟HR乱提要求,比如不考虑某某城市之类的作死要求,再跟HR好好谈谈我们对知识的渴望、希望得到锻炼的决心,我觉得都没什么问题(网易除外,都是泪)
我还重点给HR讲了一下我对项目的反思,哪些地方可以做的更好。又把一次学习新技术时间又很紧的尽力夸大了一下,HR听完之后表示非常羡慕我们这样搞技术的,感觉每天做的事情都很有激情。
最后就是经过三天的等待,顺利拿到阿里巴巴的实习offer
楼主从三月初到现在,基本能叫的出来的公司都参加了各种面试,很惭愧拿到offer的只有这三家。但是经过大大小小二三十次的面试,我觉得对一个后台程序员来说,重要的不只是语言,还有数据结构算法、网络基础、并发、数据库、设计模式、操作系统、linux等等很多很多技术需要掌握。我就有很强烈的感觉,单论Java,在楼主的周围其实有很多比楼主强得多的人,可是他们有的人面试一直不顺利,原因就在于其他的知识点相对薄弱。这点在阿里巴巴面试中就体现的很深刻。最后HR问我作为非计算机专业学生,什么专业课没有学到最让我遗憾?我回答网络基础、操作系统、计算机组成原理和系统的数据库知识体系。虽然侥幸拿到了阿里巴巴的offer,但这一次的面试让我深深地看到了自己差距。跟二面面试官交流的时候,他考我项目,我就拼命想把他往框架上拉,想解释hibernate和Spring还有mybatis,结果面试官一次也没有上当。每当我说这些的时候,面试官就会打断我,说我不用解释框架,我们就建立在这些东西都双方都清楚的基础上。所以真心劝各位准备面试的朋友们,多重视基础。基础能够决定学习能力和思维方式,而学习能力和思维方式最终决定一个程序员能走多远。
以上是我对春招面试的部分总结,手上还有十份左右的手写面经,都是每次面试完当天晚上自己总结的,有需要的朋友可以私信我。
最后祝看完这篇文章额所有朋友,找到自己心仪的工作,程序员都不容易。
最后的最后,牛客在过年到现在这段时间对我的帮助非常大,有我寒假怒刷2000题,也有后面疯狂提交代码(疯狂报错),是金子总会发光,在我的带动下,整个实验室都在刷题,总之祝牛客网越办越好
================================================
FILE: docs/android/Android-Interview/经验分享/面试心得与总结:BAT、网易、蘑菇街 .md
================================================
之前实习的时候就想着写一篇面经,后来忙就给忘了,现在找完工作了,也是该静下心总结一下走过的路程了,我全盘托出,奉上这篇诚意之作,希望能给未来找工作的人一点指引和总结,也希望能使大家少走点弯路,如果能耐心读完,相信对你会找到你需要的东西。
先说一下LZ的基本情况,LZ是四川某985学校通信专业的研究生(非计算机),大学阶段也就学了C语言,根本没想过最后要成为码农。大四才开始学java,研一下开始学android,所以LZ觉得自己开始就是一个小白,慢慢成长起来的。
## 1. 心态
心态很重要!
心态很重要!
心态很重要!
重要的事情说三遍,这一点我觉得是必须放到前面来讲。
找工作之前,有一点你必须清楚,就是找工作是一件看缘分的事情,不是你很牛逼,你就一定能进你想进的公司,都是有一个概率在那。如果你基础好,项目经验足,同时准备充分,那么你拿到offer的概率就会比较高;相反,如果你准备不充分,基础也不好,那么你拿到offer的概率就会比较低,但是你可以多投几家公司,这样拿到offer的几率就要大一点,因为你总有运气好的时候。所以,不要惧怕面试,刚开始失败了没什么的,多投多尝试,面多了你就自然能成面霸了。得失心也不要太重,最后每个人都会有offer的。
还有一个对待工作的心态,有些人可能觉得自己没有动力去找一个好工作。其实你需要明白一件事情,你读了十几二十年的书,为的是什么,最后不就是为了找到一个好工作么。现在到了关键时刻,你为何不努力一把呢,为什么不给自己一个好的未来呢,去一个自己不满意的公司工作,你甘心吗?
想清楚这一点,我相信大多数人都会有一股干劲了,因为LZ刚刚准备开始找实习的时候,BAT这种公司想都不敢想,觉得能进个二线公司就很不错了,后来发现自己不逼自己一把,你真不知道自己有多大能耐,所以请对找工作保持积极与十二分的热情,也请认真对待每一次笔试面试。
## 2. 基础
基础这东西,各个公司都很看重,尤其是BAT这种大公司,他们看中人的潜力,他们舍得花精力去培养,所以基础是重中之重。之前很多人问我,项目经历少怎么办,那就去打牢基础,当你的基础好的发指的时候,你的其他东西都不重要了。
基础无外乎几部分:语言(C/C++或java),操作系统,TCP/IP,数据结构与算法,再加上你所熟悉的领域。这里面其实有很多东西,各大面试宝典都有列举。
在这只列举了Android客户端所需要的和我面试中所遇到的知识点,尽量做到全面,如果你掌握了以下知识点,去面android客户端应该得心应手。
### J2SE基础
1.九种基本数据类型的大小,以及他们的封装类。
2.Switch能否用string做参数?
3.equals与==的区别。
4.Object有哪些公用方法?
5.Java的四种引用,强弱软虚,用到的场景。
6.Hashcode的作用。
7.ArrayList、LinkedList、Vector的区别。
8.String、StringBuffer与StringBuilder的区别。
9.Map、Set、List、Queue、Stack的特点与用法。
10.HashMap和HashTable的区别。
11.HashMap和ConcurrentHashMap的区别,HashMap的底层源码。
12.TreeMap、HashMap、LindedHashMap的区别。
13.Collection包结构,与Collections的区别。
14.try catch finally,try里有return,finally还执行么?
15.Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。
16.Java面向对象的三个特征与含义。
17.Override和Overload的含义去区别。
18.Interface与abstract类的区别。
19.Static class 与non static class的区别。
20.java多态的实现原理。
21.实现多线程的两种方法:Thread与Runable。
22.线程同步的方法:sychronized、lock、reentrantLock等。
23.锁的等级:方法锁、对象锁、类锁。
24.写出生产者消费者模式。
25.ThreadLocal的设计理念与作用。
26.ThreadPool用法与优势。
27.Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。
28.wait()和sleep()的区别。
29.foreach与正常for循环效率对比。
30.Java IO与NIO。
31.反射的作用于原理。
32.泛型常用特点,List能否转为List |