这些面试题是我在去年换工做的时候整理,没有重点。包括java基础,数据结构,网络,Android相关等等。java
适合3-5年工做经验,打算跳槽面试的中高级工程师。因为内容过多,将会分为上下两部分。android
面试题目都是穿插的,没有单独分出来。由于有些事外面试过程当中遇到的,我就又加上去了。总之你弄懂了这些,基本是没有问题了。若是是bat那些企业,你还得准备算法,jvm这些知识。好了,废话很少说了。程序员
一、java中==和equals和hashCode的区别面试
基本数据类型的==比较的值相等.算法
类的==比较的内存的地址,便是否是同一个对象,在不覆盖equals的状况下,同比较内存地址,原实现也为 == ,如String等重写了equals方法.数组
hashCode也是Object类的一个方法。返回一个离散的int型整数。在集合类操做中使用,为了提升查询速度。(HashMap,HashSet等比较是否为同一个)缓存
若是两个对象equals,Java运行时环境会认为他们的hashcode必定相等。安全
若是两个对象不equals,他们的hashcode有可能相等。性能优化
若是两个对象hashcode相等,他们不必定equals。网络
若是两个对象hashcode不相等,他们必定不equals。
二、int与integer的区别
int 基本类型
integer 对象 int的封装类
三、String、StringBuffer、StringBuilder区别
String:字符串常量 不适用于常常要改变值得状况,每次改变至关于生成一个新的对象
StringBuffer:字符串变量 (线程安全)
StringBuilder:字符串变量(线程不安全) 确保单线程下可用,效率略高于StringBuffer
四、什么是内部类?内部类的做用
内部类可直接访问外部类的属性
Java中内部类主要分为成员内部类、局部内部类(嵌套在方法和做用域内)、匿名内部类(没构造方法)、静态内部类(static修饰的类,不能使用任何外围类的非static成员变量和方法, 不依赖外围类)
五、进程和线程的区别
进程是cpu资源分配的最小单位,线程是cpu调度的最小单位。
进程之间不能共享资源,而线程共享所在进程的地址空间和其它资源。
一个进程内可拥有多个线程,进程可开启进程,也可开启线程。
一个线程只能属于一个进程,线程可直接使用同进程的资源,线程依赖于进程而存在。
六、final,finally,finalize的区别
final:修饰类、成员变量和成员方法,类不可被继承,成员变量不可变,成员方法不可重写
finally:与try...catch...共同使用,确保不管是否出现异常都能被调用到
finalize:类的方法,垃圾回收以前会调用此方法,子类能够重写finalize()方法实现对资源的回收
七、Serializable 和Parcelable 的区别
Serializable Java 序列化接口 在硬盘上读写 读写过程当中有大量临时变量的生成,内部执行大量的i/o操做,效率很低。
Parcelable Android 序列化接口 效率高 使用麻烦 在内存中读写(AS有相关插件 一键生成所需方法) ,对象不能保存到磁盘中
八、静态属性和静态方法是否能够被继承?是否能够被重写?以及缘由?
可继承 不可重写 而是被隐藏
若是子类里面定义了静态方法和属性,那么这时候父类的静态方法或属性称之为"隐藏"。若是你想要调用父类的静态方法和属性,直接经过父类名.方法或变量名完成。
九、成员内部类、静态内部类、局部内部类和匿名内部类的理解,以及项目中的应用
ava中内部类主要分为成员内部类、局部内部类(嵌套在方法和做用域内)、匿名内部类(没构造方法)、静态内部类(static修饰的类,不能使用任何外围类的非static成员变量和方法, 不依赖外围类)
使用内部类最吸引人的缘由是:每一个内部类都能独立地继承一个(接口的)实现,因此不管外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
由于Java不支持多继承,支持实现多个接口。但有时候会存在一些使用接口很难解决的问题,这个时候咱们能够利用内部类提供的、能够继承多个具体的或者抽象的类的能力来解决这些程序设计问题。能够这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。
十、string 转换成 integer的方式及原理
String integer Intrger.parseInt(string);
Integerstring Integer.toString();
十一、哪些状况下的对象会被垃圾回收机制处理掉?
1.全部实例都没有活动线程访问。
2.没有被其余任何实例访问的循环引用实例。
3.Java 中有不一样的引用类型。判断实例是否符合垃圾收集的条件都依赖于它的引用类型。
要判断怎样的对象是没用的对象。这里有2种方法:
1.采用标记计数的方法:
给内存中的对象给打上标记,对象被引用一次,计数就加1,引用被释放了,计数就减一,当这个计数为0的时候,这个对象就能够被回收了。固然,这也就引起了一个问题:循环引用的对象是没法被识别出来而且被回收的。因此就有了第二种方法:
2.采用根搜索算法:
从一个根出发,搜索全部的可达对象,这样剩下的那些对象就是须要被回收的
十二、静态代理和动态代理的区别,什么场景使用?
静态代理类:
由程序员建立或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。动态代理类:在程序运行时,运用反射机制动态建立而成。
1四、Java中实现多态的机制是什么?
答:方法的重写Overriding和重载Overloading是Java多态性的不一样表现
重写Overriding是父类与子类之间多态性的一种表现
重载Overloading是一个类中多态性的一种表现.
1六、说说你对Java反射的理解
JAVA反射机制是在运行状态中, 对于任意一个类, 都可以知道这个类的全部属性和方法; 对于任意一个对象, 都可以调用它的任意一个方法和属性。 从对象出发,经过反射(Class类)能够取得取得类的完整信息(类名 Class类型,所在包、具备的全部方法 Method[]类型、某个方法的完整信息(包括修饰符、返回值类型、异常、参数类型)、全部属性 Field[]、某个属性的完整信息、构造器 Constructors),调用类的属性或方法本身的总结: 在运行过程当中得到类、对象、方法的全部信息。
1七、说说你对Java注解的理解
元注解
元注解的做用就是负责注解其余注解。java5.0的时候,定义了4个标准的meta-annotation类型,它们用来提供对其余注解的类型做说明。
1.@Target
2.@Retention
3.@Documented
4.@Inherited
1八、Java中String的了解
在源码中string是用final 进行修饰,它是不可更改,不可继承的常量。
1九、String为何要设计成不可变的?
一、字符串池的需求
字符串池是方法区(Method Area)中的一块特殊的存储区域。当一个字符串已经被建立而且该字符串在 池 中,该字符串的引用会当即返回给变量,而不是从新建立一个字符串再将引用返回给变量。若是字符串不是不可变的,那么改变一个引用(如: string2)的字符串将会致使另外一个引用(如: string1)出现脏数据。
二、容许字符串缓存哈希码
在java中经常会用到字符串的哈希码,例如: HashMap 。String的不变性保证哈希码始终一,所以,他能够不用担忧变化的出现。 这种方法意味着没必要每次使用时都从新计算一次哈希码——这样,效率会高不少。
三、安全
String普遍的用于java 类中的参数,如:网络链接(Network connetion),打开文件(opening files )等等。若是String不是不可变的,网络链接、文件将会被改变——这将会致使一系列的安全威胁。操做的方法本觉得链接上了一台机器,但实际上却不是。因为反射中的参数都是字符串,一样,也会引发一系列的安全问题。
20、Object类的equal和hashCode方法重写,为何?
首先equals与hashcode间的关系是这样的:
一、若是两个对象相同(即用equals比较返回true),那么它们的hashCode值必定要相同;
二、若是两个对象的hashCode相同,它们并不必定相同(即用equals比较返回false)
因为为了提升程序的效率才实现了hashcode方法,先进行hashcode的比较,若是不一样,那没就没必要在进行equals的比较了,这样就大大减小了equals比较的次数,这对比须要比较的数量很大的效率提升是很明显的
2一、List,Set,Map的区别
Set是最简单的一种集合。集合中的对象不按特定的方式排序,而且没有重复对象。 Set接口主要实现了两个实现类:HashSet: HashSet类按照哈希算法来存取集合中的对象,存取速度比较快
TreeSet :TreeSet类实现了SortedSet接口,可以对集合中的对象进行排序。
List的特征是其元素以线性方式存储,集合中能够存放重复对象。
ArrayList() : 表明长度能够改变得数组。能够对元素进行随机的访问,向ArrayList()中插入与删除元素的速度慢。
LinkedList(): 在实现中采用链表数据结构。插入和删除速度快,访问速度慢。
Map 是一种把键对象和值对象映射的集合,它的每个元素都包含一对键对象和值对象。 Map没有继承于Collection接口 从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。
HashMap:Map基于散列表的实现。插入和查询“键值对”的开销是固定的。能够经过构造器设置容量capacity和负载因子load factor,以调整容器的性能。
LinkedHashMap: 相似于HashMap,可是迭代遍历它时,取得“键值对”的顺序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一点。而在迭代访问时发而更快,由于它使用链表维护内部次序。
TreeMap : 基于红黑树数据结构的实现。查看“键”或“键值对”时,它们会被排序(次序由Comparabel或Comparator决定)。TreeMap的特色在 于,你获得的结果是通过排序的。TreeMap是惟一的带有subMap()方法的Map,它能够返回一个子树。
WeakHashMao :弱键(weak key)Map,Map中使用的对象也被容许释放: 这是为解决特殊问题设计的。若是没有map以外的引用指向某个“键”,则此“键”能够被垃圾收集器回收。
2六、ArrayMap和HashMap的对比
一、存储方式不一样
HashMap内部有一个HashMapEntry<K, V>[]对象,每个键值对都存储在这个对象里,当使用put方法添加键值对时,就会new一个HashMapEntry对象,
二、添加数据时扩容时的处理不同,进行了new操做,从新建立对象,开销很大。ArrayMap用的是copy数据,因此效率相对要高。
三、ArrayMap提供了数组收缩的功能,在clear或remove后,会从新收缩数组,是否空间
四、ArrayMap采用二分法查找;
2九、HashMap和HashTable的区别
1 HashMap不是线程安全的,效率高一点、方法不是Synchronize的要提供外同步,有containsvalue和containsKey方法。
hashtable是,线程安全,不容许有null的键和值,效率稍低,方法是是Synchronize的。有contains方法方法。Hashtable 继承于Dictionary 类
30、HashMap与HashSet的区别
hashMap:HashMap实现了Map接口,HashMap储存键值对,使用put()方法将元素放入map中,HashMap中使用键对象来计算hashcode值,HashMap比较快,由于是使用惟一的键来获取对象。
HashSet实现了Set接口,HashSet仅仅存储对象,使用add()方法将元素放入set中,HashSet使用成员对象来计算hashcode值,对于两个对象来讲hashcode可能相同,因此equals()方法用来判断对象的相等性,若是两个对象不一样的话,那么返回false。HashSet较HashMap来讲比较慢。
3一、HashSet与HashMap怎么判断集合元素重复?
HashSet不能添加剧复的元素,当调用add(Object)方法时候,
首先会调用Object的hashCode方法判hashCode是否已经存在,如不存在则直接插入元素;若是已存在则调用Object对象的equals方法判断是否返回true,若是为true则说明元素已经存在,如为false则插入元素。
3三、ArrayList和LinkedList的区别,以及应用场景
ArrayList是基于数组实现的,ArrayList线程不安全。
LinkedList是基于双链表实现的:
使用场景:
(1)若是应用程序对各个索引位置的元素进行大量的存取或删除操做,ArrayList对象要远优于LinkedList对象;
( 2 ) 若是应用程序主要是对列表进行循环,而且循环时候进行插入或者删除操做,LinkedList对象要远优于ArrayList对象;
3四、数组和链表的区别
数组:是将元素在内存中连续存储的;它的优势:由于数据是连续存储的,内存地址连续,因此在查找数据的时候效率比较高;它的缺点:在存储以前,咱们须要申请一块连续的内存空间,而且在编译的时候就必须肯定好它的空间的大小。在运行的时候空间的大小是没法随着你的须要进行增长和减小而改变的,当数据两比较大的时候,有可能会出现越界的状况,数据比较小的时候,又有可能会浪费掉内存空间。在改变数据个数时,增长、插入、删除数据效率比较低。
链表:是动态申请内存空间,不须要像数组须要提早申请好内存的大小,链表只需在用的时候申请就能够,根据须要来动态申请或者删除内存空间,对于数据增长和删除以及插入比数组灵活。还有就是链表中数据在内存中能够在任意的位置,经过应用来关联数据(就是经过存在元素的指针来联系)
3五、开启线程的三种方式?
ava有三种建立线程的方式,分别是继承Thread类、实现Runable接口和使用线程池
3六、线程和进程的区别?
线程是进程的子集,一个进程能够有不少线程,每条线程并行执行不一样的任务。不一样的进程使用不一样的内存空间,而全部的线程共享一片相同的内存空间。别把它和栈内存搞混,每一个线程都拥有单独的栈内存用来存储本地数据。
3八、run()和start()方法区别
这个问题常常被问到,但仍是能今后区分出面试者对Java线程模型的理解程度。start()方法被用来启动新建立的线程,并且start()内部调用了run()方法,这和直接调用run()方法的效果不同。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。
3九、如何控制某个方法容许并发访问线程的个数?
semaphore.acquire() 请求一个信号量,这时候的信号量个数-1(一旦没有可以使用的信号量,也即信号量个数变为负数时,再次请求的时候就会阻塞,直到其余线程释放了信号量)
semaphore.release() 释放一个信号量,此时信号量个数+1
40、在Java中wait和seelp方法的不一样;
Java程序中wait 和 sleep都会形成某种形式的暂停,它们能够知足不一样的须要。wait()方法用于线程间通讯,若是等待条件为真且其它线程被唤醒时它会释放锁,而sleep()方法仅仅释放CPU资源或者让当前线程中止执行一段时间,但不会释放锁。
4一、谈谈wait/notify关键字的理解
等待对象的同步锁,须要得到该对象的同步锁才能够调用这个方法,不然编译能够经过,但运行时会收到一个异常:IllegalMonitorStateException。
调用任意对象的 wait() 方法致使该线程阻塞,该线程不可继续执行,而且该对象上的锁被释放。
唤醒在等待该对象同步锁的线程(只唤醒一个,若是有多个在等待),注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM肯定唤醒哪一个线程,并且不是按优先级。
调用任意对象的notify()方法则致使因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到得到锁后才真正可执行)。
4二、什么致使线程阻塞?线程如何关闭?
阻塞式方法是指程序会一直等待该方法完成期间不作其余事情,ServerSocket的accept()方法就是一直等待客户端链接。这里的阻塞是指调用结果返回以前,当前线程会被挂起,直到获得结果以后才会返回。此外,还有异步和非阻塞式方法在任务完成前就返回。
一种是调用它里面的stop()方法
另外一种就是你本身设置一个中止线程的标记 (推荐这种)
4三、如何保证线程安全?
1.synchronized;
2.Object方法中的wait,notify;
3.ThreadLocal机制 来实现的。
4四、如何实现线程同步?
一、synchronized关键字修改的方法。二、synchronized关键字修饰的语句块三、使用特殊域变量(volatile)实现线程同步
4五、线程间操做List
List list = Collections.synchronizedList(new ArrayList());
4六、谈谈对Synchronized关键字,类锁,方法锁,重入锁的理解
java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,可是,两个锁实际是有很大的区别的,对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。咱们知道,类的对象实例能够有不少个,可是每一个类只有一个class对象,因此不一样对象实例的对象锁是互不干扰的,可是每一个类只有一个类锁。可是有一点必须注意的是,其实类锁只是一个概念上的东西,并非真实存在的,它只是用来帮助咱们理解锁定实例方法和静态方法的区别的
4九、synchronized 和volatile 关键字的区别
1.volatile本质是在告诉jvm当前变量在寄存器(工做内存)中的值是不肯定的,须要从主存中读取;synchronized则是锁定当前变量,只有当前线程能够访问该变量,其余线程被阻塞住。
2.volatile仅能使用在变量级别;synchronized则可使用在变量、方法、和类级别的
3.volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则能够保证变量的修改可见性和原子性
4.volatile不会形成线程的阻塞;synchronized可能会形成线程的阻塞。
5.volatile标记的变量不会被编译器优化;synchronized标记的变量能够被编译器优化
5一、ReentrantLock 、synchronized和volatile比较
ava在过去很长一段时间只能经过synchronized关键字来实现互斥,它有一些缺点。好比你不能扩展锁以外的方法或者块边界,尝试获取锁时不能中途取消等。Java 5 经过Lock接口提供了更复杂的控制来解决这些问题。 ReentrantLock 类实现了 Lock,它拥有与 synchronized 相同的并发性和内存语义且它还具备可扩展性。
5三、死锁的四个必要条件?
死锁产生的缘由
1. 系统资源的竞争
系统资源的竞争致使系统资源不足,以及资源分配不当,致使死锁。
2. 进程运行推动顺序不合适
互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。此时如有其余进程请求该资源,则请求进程只能等待。
请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其余进程占有,此时请求进程被阻塞,但对本身已得到的资源保持不放。
不可剥夺条件:进程所得到的资源在未使用完毕以前,不能被其余进程强行夺走,即只能 由得到该资源的进程本身来释放(只能是主动释放)。
循环等待条件: 若干进程间造成首尾相接循环等待资源的关系
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不知足,就不会发生死锁。
死锁的避免与预防:
死锁避免的基本思想:
系统对进程发出每个系统可以知足的资源申请进行动态检查,并根据检查结果决定是否分配资源,若是分配后系统可能发生死锁,则不予分配,不然予以分配。这是一种保证系统不进入死锁状态的动态策略。
理解了死锁的缘由,尤为是产生死锁的四个必要条件,就能够最大可能地避免、预防和解除死锁。因此,在系统设计、进程调度等方面注意如何让这四个必要条件不成立,如何肯定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的状况下占用资源。所以,对资源的分配要给予合理的规划。
死锁避免和死锁预防的区别:
死锁预防是设法至少破坏产生死锁的四个必要条件之一,严格的防止死锁的出现,而死锁避免则不那么严格的限制产生死锁的必要条件的存在,由于即便死锁的必要条件存在,也不必定发生死锁。死锁避免是在系统运行过程当中注意避免死锁的最终发生。
5六、什么是线程池,如何使用?
建立线程要花费昂贵的资源和时间,若是任务来了才建立线程那么响应时间会变长,并且一个进程能建立的线程数有限。为了不这些问题,在程序启动的时候就建立若干线程来响应处理,它们被称为线程池,里面的线程叫工做线程。从JDK1.5开始,Java API提供了Executor框架让你能够建立不一样的线程池。好比单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合不少生存期短的任务的程序的可扩展线程池)。
5七、Java中堆和栈有什么不一样?
为何把这个问题归类在多线程和并发面试题里?由于栈是一块和线程紧密相关的内存区域。每一个线程都有本身的栈内存,用于存储本地变量,方法参数和栈调用,一个线程中存储的变量对其它线程是不可见的。而堆是全部线程共享的一片公用内存区域。对象都在堆里建立,为了提高效率线程会从堆中弄一个缓存到本身的栈,若是多个线程使用该变量就可能引起问题,这时volatile 变量就能够发挥做用了,它要求线程从主存中读取变量的值。
5八、有三个线程T1,T2,T3,怎么确保它们按顺序执行?
在多线程中有多种方法让线程按特定顺序执行,你能够用线程类的join()方法在一个线程中启动另外一个线程,另一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3最后完成。
线程间通讯
咱们知道线程是CPU调度的最小单位。在Android中主线程是不可以作耗时操做的,子线程是不可以更新UI的。而线程间通讯的方式有不少,好比广播,Eventbus,接口回掉,在Android中主要是使用handler。handler经过调用sendmessage方法,将保存消息的Message发送到Messagequeue中,而looper对象不断的调用loop方法,从messageueue中取出message,交给handler处理,从而完成线程间通讯。
线程池
Android中常见的线程池有四种,FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingleThreadExecutor。
FixedThreadPool线程池是经过Executors的new FixedThreadPool方法来建立。它的特色是该线程池中的线程数量是固定的。即便线程处于闲置的状态,它们也不会被回收,除非线程池被关闭。当全部的线程都处于活跃状态的时候,新任务就处于队列中等待线程来处理。注意,FixedThreadPool只有核心线程,没有非核心线程。
CachedThreadPool线程池是经过Executors的newCachedThreadPool进行建立的。它是一种线程数目不固定的线程池,它没有核心线程,只有非核心线程,当线程池中的线程都处于活跃状态,就会建立新的线程来处理新的任务。不然就会利用闲置的线程来处理新的任务。线程池中的线程都有超时机制,这个超时机制时长是60s,超过这个时间,闲置的线程就会被回收。这种线程池适合处理大量而且耗时较少的任务。这里得说一下,CachedThreadPool的任务队列,基本都是空的。
ScheduledThreadPool线程池是经过Executors的newScheduledThreadPool进行建立的,它的核心线程是固定的,可是非核心线程数是不固定的,而且当非核心线程一处于空闲状态,就当即被回收。这种线程适合执行定时任务和具备固定周期的重复任务。
SingleThreadExecutor线程池是经过Executors的newSingleThreadExecutor方法来建立的,这类线程池中只有一个核心线程,也没有非核心线程,这就确保了全部任务可以在同一个线程而且按照顺序来执行,这样就不须要考虑线程同步的问题。
AsyncTask的工做原理
AsyncTask是Android自己提供的一种轻量级的异步任务类。它能够在线程池中执行后台任务,而后把执行的进度和最终的结果传递给主线程更新UI。实际上,AsyncTask内部是封装了Thread和Handler。虽然AsyncTask很方便的执行后台任务,以及在主线程上更新UI,可是,AsyncTask并不合适进行特别耗时的后台操做,对于特别耗时的任务,我的仍是建议使用线程池。
AsyncTask提供有4个核心方法:
一、onPreExecute():该方法在主线程中执行,在执行异步任务以前会被调用,通常用于一些准备工做。
二、doInBackground(String... params):这个方法是在线程池中执行,此方法用于执行异步任务。在这个方法中能够经过publishProgress方法来更新任务的进度,publishProgress方法会调用onProgressUpdate方法,另外,任务的结果返回给onPostExecute方法。
三、onProgressUpdate(Object... values):该方法在主线程中执行,主要用于任务进度更新的时候,该方法会被调用。
四、onPostExecute(Long aLong):在主线程中执行,在异步任务执行完毕以后,该方法会被调用,该方法的参数及为后台的返回结果。
除了这几个方法以外还有一些不太经常使用的方法,如onCancelled(),在异步任务取消的状况下,该方法会被调用。
源码能够知道从上面的execute方法内部调用的是executeOnExecutor()方法,即executeOnExecutor(sDefaultExecutor, params);而sDefaultExecutor其实是一个串行的线程池。而onPreExecute()方法在这里就会被调用了。接着看这个线程池。AsyncTask的执行是排队执行的,由于有关键字synchronized,而AsyncTask的Params参数就封装成为FutureTask类,FutureTask这个类是一个并发类,在这里它充当了Runnable的做用。接着FutureTask会交给SerialExecutor的execute方法去处理,而SerialExecutor的executor方法首先就会将FutureTask添加到mTasks队列中,若是这个时候没有任务,就会调用scheduleNext()方法,执行下一个任务。若是有任务的话,则执行完毕后最后在调用 scheduleNext();执行下一个任务。直到全部任务被执行完毕。而AsyncTask的构造方法中有一个call()方法,而这个方法因为会被FutureTask的run方法执行。因此最终这个call方法会在线程池中执行。而doInBackground这个方法就是在这里被调用的。咱们好好研究一下这个call()方法。mTaskInvoked.set(true);表示当前任务已经执行过了。接着执行doInBackground方法,最后将结果经过postResult(result);方法进行传递。postResult()方法中经过sHandler来发送消息,sHandler的中经过消息的类型来判断一个MESSAGE_POST_RESULT,这种状况就是调用onPostExecute(result)方法或者是onCancelled(result)。另外一种消息类型是MESSAGE_POST_PROGRESS则调用更新进度onProgressUpdate。
Binder的工做机制
直观来讲,Binder是Android中的一个类,它实现了IBinder接口,从IPC的角度来讲,Binder是Android中的一种跨进程通讯的一种方式,同时还能够理解为是一种虚拟的物理设备,它的设备驱动是/dev/binder/。从Framework角度来讲,Binder是ServiceManager的桥梁。从应用层来讲,Binder是客户端和服务端进行通讯的媒介。
咱们先来了解一下这个类中每一个方法的含义:
DESCRIPTOR:Binder的惟一标识,通常用于当前Binder的类名表示。
asInterface(android.os.IBinder obj):用于将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象,这种转化过程是区分进程的,若是客户端和服务端位于同一个进程,那么这个方法返回的是服务端的stub对象自己,不然返回的是系统封装后的Stub.proxy对象。
asBinder():用于返回当前Binder对象。
onTransact:该方法运行在服务端的Binder线程池中,当客户端发起跨进程通讯请求的时候,远程请求经过系统底层封装后交给该方法处理。注意这个方法public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags),服务端经过code能够肯定客户端所请求的目标方法是什么,接着从data中取出目标方法所需的参数,而后执行目标方法。当目标方法执行完毕后,就像reply中写入返回值。这个方法的执行过程就是这样的。若是这个方法返回false,客户端是会请求失败的,因此咱们能够在这个方法中作一些安全验证。
Binder的工做机制可是要注意一些问题:一、当客户端发起请求时,因为当前线程会被挂起,直到服务端返回数据,若是这个远程方法很耗时的话,那么是不可以在UI线程,也就是主线程中发起这个远程请求的。
二、因为Service的Binder方法运行在线程池中,因此Binder方法无论是耗时仍是不耗时都应该采用同步的方式,由于它已经运行在一个线程中了。
view的事件分发和view的工做原理
Android自定义view,咱们都知道实现有三部曲,onMeasure(),onLayout(),onDraw()。View的绘制流程是从viewRoot的perfromTraversal方法开始的。它通过measure,layout,draw方法才可以将view绘制出来。其中measure是测量宽高的,layout是肯定view在父容器上的摆布位置的,draw是将view绘制到屏幕上的。
Measure:
view的测量是须要MeasureSpc(测量规格),它表明一个32位int值,高2位表明SpecMode(测量模式),低(30)位的表明SpecSize(某种测量模式下的规格大小)。而一组SpecMode和SpeSize能够打包为一个MeasureSpec,反之,MeasureSpec能够解包获得SpecMode和SpeSize的值。SpecMode有三类:
unSpecified:父容器不对view有任何限制,要多大有多大。通常系统用这个多。
Exactly:父容器已经检测出view所须要的精确大小,这个时候,view的大小就是SpecSize所指定的值,它对应者layout布局中的math_parent或者是具体的数值
At_most:父容器指定了一个可用大小的SpecSize,view的大小不可以大于这个值,它对应这布局中的wrao_content.
对于普通的view,它的MeasureSpec是由父容器的MeasureSpec和自身的layoutParam共同决定的,一旦MeasureSpec肯定后,onMeasure就能够肯定view的宽高了。
View的measure过程:
onMeasure方法中有个setMeasureDimenSion方法来设置view的宽高测量值,而setMeasureDimenSion有个getDefaultSize()方法做为参数。通常状况下,咱们只须要关注at_most和exactly两种状况,getDefaultSize的返回值就是measureSpec中的SpecSize,而这个值基本就是view测量后的大小。而UnSpecified这种状况,通常是系统内部的测量过程,它是须要考虑view的背景这些因素的。
前面说的是view的测量过程,而viewGroup的measure过程:
对于viewGroup来讲,除了完成本身的measure过程之外,还要遍历去调用子类的measure方法,各个子元素在递归执行这个过程,viewGroup是一个抽象的类,没有提供有onMeasure方法,可是提供了一个measureChildren的方法。measureChild方法的思想就是取出子元素的layoutParams,而后经过getChildMeasureSpec来常见子元素的MeasureSpec,而后子元素在电泳measure方法进行测量。因为viewGroup子类有不一样的布局方式,致使他们的测量细节不同,因此viewGroup不能象view同样调用onMeasure方法进行测量。
注意:在activity的生命周期中是没有办法正确的获取view的宽高的,缘由就是view没有测量完。
在onWindowFocuschanged方法中获取 ----改方法含义是view已经初始化完毕
View.post()方法,将润那边了投递到消息队列的尾部。
使用viewTreeObserver的回调来完成。
经过view.measure方式手动测量。
onLayout
普通的view的话,能够经过setFrame方法来的到view四个顶点的位置,也就肯定了view在父容器的位置,接着就调用onLayout方法,该方法是父容器肯定子元素的位置。
onDraw
该方法就是将view绘制到屏幕上。分如下几步
绘制背景,
绘制本身,
绘制child,
绘制装饰。
Android中性能优化
因为手机硬件的限制,内存和CPU都没法像pc同样具备超大的内存,Android手机上,过多的使用内存,会容易致使oom,过多的使用CPU资源,会致使手机卡顿,甚至致使anr。我主要是从一下几部分进行优化:
布局优化,绘制优化,内存泄漏优化,响应速度优化,listview优化,bitmap优化,线程优化
布局优化:工具 hierarchyviewer,解决方式:
一、删除无用的空间和层级。
二、选择性能较低的viewgroup,如Relativelayout,若是能够选择Relativelayout也可使用LinearLayout,就优先使用LinearLayout,由于相对来讲Relativelayout功能较为复杂,会占用更多的CPU资源。
三、使用标签<include/>重用布局,<Merge/>减小层级,<viewStub/>进行预加载,使用的时候才加载。
绘制优化
绘制优化指view在ondraw方法中避免大量的耗时操做,因为ondraw方法可能会被频繁的调用。
一、ondraw方法中不要建立新的局部变量,ondraw方法被频繁的调用,很容易引发GC。
二、ondraw方法不要作耗时操做。
内存优化:参考内存泄漏。
响应优化
主线程不能作耗时操做,触摸事件5s,广播10s,service20s。
listview优化:
一、getview方法中避免耗时操做。
二、view的复用和viewholder的使用。
三、滑动不适合开启异步加载。
四、分页处理数据。
五、图片使用三级缓存。
Bitmap优化:
一、等比例压缩图片。
二、不用的图片,及时recycler掉
线程优化
线程优化的思想是使用线程池来管理和复用线程,避免程序中有大量的Thread,同时能够控制线程的并发数,避免相互抢占资源而致使线程阻塞。
其余优化
一、少用枚举,枚举占用空间大。
二、使用Android特有的数据结构,如SparseArray来代替hashMap。
三、适当的使用软引用和弱引用。
加密算法(base6四、MD五、对称加密和非对称加密)和使用场景。
什么是Rsa加密?
RSA算法是最流行的公钥密码算法,使用长度能够变化的密钥。RSA是第一个既能用于数据加密也能用于数字签名的算法。
RSA算法原理以下:
1.随机选择两个大质数p和q,p不等于q,计算N=pq;
2.选择一个大于1小于N的天然数e,e必须与(p-1)(q-1)互素。
3.用公式计算出d:d×e = 1 (mod (p-1)(q-1)) 。
4.销毁p和q。
最终获得的N和e就是“公钥”,d就是“私钥”,发送方使用N去加密数据,接收方只有使用d才能解开数据内容。
RSA的安全性依赖于大数分解,小于1024位的N已经被证实是不安全的,并且因为RSA算法进行的都是大数计算,使得RSA最快的状况也比DES慢上倍,这是RSA最大的缺陷,所以一般只能用于加密少许数据或者加密密钥,但RSA仍然不失为一种高强度的算法。
使用场景:项目中除了登录,支付等接口采用rsa非对称加密,以外的采用aes对称加密,今天咱们来认识一下aes加密。
什么是MD5加密?
MD5英文全称“Message-Digest Algorithm 5”,翻译过来是“消息摘要算法5”,由MD二、MD三、MD4演变过来的,是一种单向加密算法,是不可逆的一种的加密方式。
MD5加密有哪些特色?
压缩性:任意长度的数据,算出的MD5值长度都是固定的。
容易计算:从原数据计算出MD5值很容易。
抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所获得的MD5值都有很大区别。
强抗碰撞:已知原数据和其MD5值,想找到一个具备相同MD5值的数据(即伪造数据)是很是困难的。
MD5应用场景:
一致性验证
数字签名
安全访问认证
什么是aes加密?
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。
完整版面试题和学习笔记整理在石墨文档可见;《Android架构视频+BAT面试专题PDF+学习笔记》
文章太长分上下篇,下一篇;中高阶Android面试题总结 下