1.true or false?
Integer a=4;
Integer b=4;
a==b;
false。这个问题是关于装箱与拆箱。
装箱:把基本数据类型用对应的引用类型包装起来,使具有对象的性质。
int –>Integer float –>Float doble–> Double
拆箱:将引用类型的对象简化成基本数据类型。
Integer a=4;(自动装箱)
a==b false,是由于==比较的是它们的地址,而a 和 b是两个对象,地址不同。
2.oom异常,怎么解决的?
oom异常原因:
一个进程的内存由两部分组成,一个是java使用得内存,一个是c使用的内存,当这两部分之和超过16m就会出现oom。 一旦内存分配给java后,以后这块内存都是java的,c不能使用。c可使用的内存等于16m-某一瞬间java所占用的最大内存。 bitmap的生成过程是经过过程函数malloc进行分配的,占用的是c的内存。
根据这个原理可以有效避免oom的出现机率。
可能会出现oom的情况:
数据库cursor没有关闭;
使用数据库查询小量数据时,不会出现oom,查询数据量比较大时,就会报oom。使用完cursor后,应及时调用close方法关闭资源。context泄露;
如果在activity中使用了线程内部类,那么在该线程中会有一个activity的引用。当activity被销毁时,如果该线程还在执行,就会报oom。因为该activity的引用还没被释放,仍然没有从内存中被垃圾回收器回收。static关键字;
使用static关键字可以将成员变量和方法变成类变量和方法,延长变量的生命周期。当程序中存在大量的static关键字引用的话,就容易造成oom。
开发过程中,应尽量避免使用static引用消耗资源过多的实例,比如context;context可以尽量使用ApplicationContext代替,后者生命周期较长;使用weakReference代替强引用,比如:WeakReference mContextRef使用adapter没有使用缓存contentview;
遇到类似listview加载上百条数据的情况,如果没有复用contentview,在每次getview时都会创建一个新的view,这个方法调用迅速,如果来不及回收就会报oom。除了在getview里复用contextview外,还要用viewholer 保存通过findviewById子控件的地址值。inputStrem或outputStream没有关闭;
输入输出流如果不及时关闭,就会一直占用连接资源,当其他操作需要资源时就会报oom。注册receiver后没有反注册;
activity中注册了广播,在activity退出时没有反注册就可能造成oom。
3.ArrayList与linkedList区别?哪个在尾部插入数据快?哪个效率高,为什么?
ArrayList是实现了动态数组的数据结构,LinkedList是实现了链表的数据结构。插入大量数据的话,linkedList比较快,因为ArrayList需要大量移动数据。插入单个数据的话,比如尾部这种情况,ArrayList比较快。查询的话,ArrayList比较快,因为LinkedList需要移动指针。批量删除的话LinkedList比较快。对于随机查找,理论上,ArrayList比较快。
4.Handler中的Runnable是线程吗?
不是。Runnable只是一个接口,实现Runnble需要重写Run方法。没有任何对线程的支持。
5.开启子线程有几种方式?
继承Thread;
继承Thread,重写run方法,调用thread.start()执行。实现Runnable;
实现Runnable,重写run方法,调用new Thread(ruannable).start()执行HandlerThread
创建HandlerThread对象,调用start()方法执行。使用Handler启动;
实现Runnable,重写Run方法,调用handler.post方法启动线程。handler.post(runnable)
注意,使用这种方式不一定是运行在子线程中的:
public final boolean post (Runnable r)
Added in API level 1
Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached.
API中指出,使用这种方式,runnable所处的线程依赖于Handler 所在的线程,也就是说,Handler是在主线程创建的,那么Runnable就是在主线程,否则就是在子线程中执行的。这是特别要注意的,否则,若不确保在子线程又做了耗时操作,很可能ANR!
一个线程对应一个消息队列。
Each Handler
* instance is associated with a single thread and that thread's message
* queue. When you create a new Handler, it is bound to the thread /
* message queue of the thread that is creating it
6.java基本数据类型
int float double char boolean byte short long
引用类型 string
7.java编译过程,编译与运行区别,如何完成跨平台执行的?
java是面向对象编程语言,它继承了c++面向对象编程的核心,舍弃了c++中的指针、运算符重载、多重继承、增加了gc功能以便回收不再被引用的对象占用的内存空间。java SE1.5以后又引入了泛型、类型安全的枚举、不定长参数、自动装箱/拆箱等语言特性。
java首先将源代码编译成二进制字节码,依赖于不同平台上的虚拟机执行,从而实现一次编译,随处运行。
关于类型安全的枚举:
c++中的枚举只能是int short long的常量。c++中,枚举是一种数据结构,java的枚举类是继承与Enum的自定义类,可以任意扩展类属性和方法。java中枚举最终会被编译成public static final class 类型。
java枚举参数类型不必只是数值型
java程序编译和运行的过程:
从源文件创建到程序运行大致两步:
1.源文件由编译器编译成字节码文件
2.字节码文件由java虚拟机(jvm)解释执行。
具体来说,
第一步,编译
创建完源文件后,程序会被编译成.class文件。java编译一个类时,如果依赖的类还没被编译,会先编译依赖的类,然后引用。如果找不到依赖的.class文件和.java源文件就会报cant find symbol 错误。
编译后的字节码格式分为两部分:常量池和方法字节码。
常量池记录所有出现过的token(类名、成员变量名)以及符号引用(方法引用、成员变量引用);
方法字节码里存放的是类中各个方法的字节码。
第二步,运行
分两个步骤,类的加载,类的执行。JVM在第一次主动使用该类时才会去加载该类。不是一开始就把所有的类都加载到内存中,而且只加载一次。
8.关于include与ViewStub
include 复用已存在的布局,缺点,xml中属性修改起作用的只有width,heiht等,其他需要代码动态修改;
ViewStub 延迟加载 默认属性invisible。使用visible或inflate()才加载,节省内存;
当view与ViewStub同时设置为invisible?
view会被inflate。ViewStub不会。
同时设为gone?
view不会被加载,viewStub 不一定。
viewStub原理:设置布局gone,并且不绘制(onMeasure 设置width height 为0)
ViewStub构造:
private void initialize(Context context) {
mContext = context;
setVisibility(GONE);
setWillNotDraw(true);
}
对于ViewStub只有设置Gone并且setWillNotDraw(true);才能保证不被加载。
附:
ViewStub属性id与inflatedId
id ViewStub
inflatedId 重命名延迟加载的view ,可通过此inflatedId找到延迟加载view的子view。
参考:
1.Java枚举类和c++枚举类比较
2.Java程序编译和运行的过程
3.java 动态绑定 以及 内部实现机制
4.Java动态绑定机制的内幕
5.类型安全枚举
6.Handler - Android SDK | Android Developers