状态:未完成
Android面试常见Java相关问题。
原文链接:http://www.nowcoder.com/discuss/3244
Switch能否用string做参数?
在 Java 7 之前, switch 只能支持byte,short,char,int 或者其对应的封装类以及 Enum 类型。在JAVA 7中,String 支持被加上了。
equals与==的区别:
- ==是判断两个变量或实例是不是指向同一个内存空间
- equals是判断两个变量或实例所指向的内存空间的值是不是相同
Object有哪些公用方法?
- 方法equals测试的是两个对象是否相等
- 方法clone进行对象拷贝
- 方法getClass返回和当前对象相关的Class对象
- 方法notify,notifyall,wait都是用来对给定对象进行线程同步的
Java的四种引用,强弱软虚,用到的场景
- 强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM 也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象
- 软引用:在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。
- 弱引用:具有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象
- 虚引用:顾名思义,就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。
使用场景: - 利用软引用和弱引用解决OOM问题:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题
- 通过软引用对象重获方法实现Java对象的高速缓存:比如我们创建了一Employee的类,如果每次需要查询一个雇员的信息。哪怕是几秒中之前刚刚查询过的,都要重新构建一个实例,这是需要消耗很多时间的。我们可以通过软引用和 HashMap 的结合,先是保存引用方面:以软引用的方式对一个Employee对象的实例进行引用并保存该引用到HashMap 上,key 为此雇员的 id,value为这个对象的软引用,另一方面是取出引用,缓存中是否有该Employee实例的软引用,如果有,从软引用中取得。如果没有软引用,或者从软引用中得到的实例是null,重新构建一个实例,并保存对这个新建实例的软引用
Hashcode的作用,与 equal 有什么区别
同样用于鉴定2个对象是否相等的,java集合中有 list 和 set 两类,前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?如果用 equal 去比较的话,如果存在1000个元素,你 new 一个新的元素出来,需要去调用1000次 equal 去逐个和他们比较是否是同一个对象,这样会大大降低效率。hashcode实际上是返回对象的存储地址,如果这个位置上没有元素,就把元素直接存储在上面,如果这个位置上已经存在元素,这个时候才去调用equal方法与新元素进行比较,相同的话就不存了。不相同,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashcode的对象放到这个单链表上去,串在一起。所以这里存在一个冲突解决的问题(很少出现)。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。
所以,Java对于eqauls方法和hashCode方法是这样规定的:
上面说的对象相等指的是用eqauls方法比较。1、如果两个对象相等,那么它们的hashCode值一定要相等; 2、如果两个对象的hashCode相等,它们并不一定相等。
String、StringBuffer与StringBuilder的区别
- String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象
- StringBuffer和StringBuilder底层是 char[]数组实现的
- StringBuffer是线程安全的,而StringBuilder是线程不安全的
Override和Overload的含义去区别
- Overload顾名思义是重新加载,它可以表现类的多态性,可以是函数里面可以有相同的函数名但是参数名、返回值、类型不能相同;或者说可以改变参数、类型、返回值但是函数名字依然不变。
- 就是ride(重写)的意思,在子类继承父类的时候子类中可以定义某方法与其父类有相同的名称和参数,当子类在调用这一函数时自动调用子类的方法,而父类相当于被覆盖(重写)了。
Fail-Fast机制
在使用迭代器的过程中有其他线程修改了map,那么将抛出ConcurrentModificationException,这就是所谓fail-fast机制。这一机制在源码中的实现是通过modCount域,modCount顾名思义就是修改次数,对HashMap内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的expectedModCount。在迭代过程中,判断modCount跟expectedModCount是否相等,如果不相等就表示已经有其他线程修改了Map.
wait()和sleep()的区别
- sleep来自Thread类,和wait来自Object类
调用sleep()方法的过程中,线程不会释放对象锁。而 调用 wait 方法线程会释放对象锁 - sleep睡眠后不出让系统资源,wait让出系统资源其他线程可以占用CPU
- sleep(milliseconds)需要指定一个睡眠时间,时间一到会自动唤醒
JAVA 中堆和栈的区别,说下java 的内存机制
- 基本数据类型比变量和对象的引用都是在栈分配的
- 堆内存用来存放由new创建的对象和数组
- 类变量(static修饰的变量),程序在一加载的时候就在堆中为类变量分配内存,堆中的内存地址存放在栈中
- 实例变量:当你使用java关键字new的时候,系统在堆中开辟并不一定是连续的空间分配给变量,是根据零散的堆内存地址,通过哈希算法换算为一长串数字以表征这个变量在堆中的”物理位置”,实例变量的生命周期–当实例变量的引用丢失后,将被GC(垃圾回收器)列入可回收“名单”中,但并不是马上就释放堆中内存
- 局部变量: 由声明在某方法,或某代码段里(比如for循环),执行到它的时候在栈中开辟内存,当局部变量一但脱离作用域,内存立即释放
JAVA多态的实现原理
抽象的来讲,多态的意思就是同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
实现的原理是动态绑定,程序调用的方法在运行期才动态绑定,追溯源码可以发现,JVM 通过参数的自动转型来找到合适的办法。JAVA 垃圾回收机制
- 什么是垃圾回收机:释放那些不再持有引用的对象的内存
怎么判断一个对象是否需要收集? - 引用计数(最简单古老的方法):指将资源(可以是对象、内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的过程
- 对象引用遍历(现在大多数 jvm 使用的方法):对象引用遍历从一组对象开始,沿着整个对象图上的每条链接,递归确定可到达(reachable)的对象。如果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集
几种垃圾回收机制 - 标记回收法:遍历对象图并且记录可到达的对象,以便删除不可到达的对象,一般使用单线程工作并且可能产生内存碎片
标记-压缩回收法:前期与第一种方法相同,只是多了一步,将所有的存活对象压缩到内存的一端,这样内存碎片就可以合成一大块可再利用的内存区域,提高了内存利用率 - 复制回收法:把现有内存空间分成两部分,gc运行时,它把可到达对象复制到另一半空间,再清空正在使用的空间的全部对象。这种方法适用于短生存期的对象,持续复制长生存期的对象则导致效率降低。
- 分代回收发:把内存空间分为两个或者多个域,如年轻代和老年代,年轻代的特点是对象会很快被回收,因此在年轻代使用效率比较高的算法。当一个对象经过几次回收后依然存活,对象就会被放入称为老年的内存空间,老年代则采取标记-压缩算法
Error与Exception的区别
错误和异常的区别是:Error不是程序需要捕获和进行处理的,例如,OutOfMemoryError(当java虚拟机在为对象分配内存空间时,剩余的空间不够,同时也没有可以释放的内容时,将会发生这样的错误)不由程序进行捕获或处理,当Error发生时,程序将会停止。
volatile修饰符
在JVM 1.2之前,Java总是从主存读取变量,但随着JVM的优化,线程可以把变量保存在机器的寄存器中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值。而另外一个线程还继续使用它在寄存器中变量值的副本,造成数据的不一致。要解决这个问题,就需要把该变量声明为volatile(不稳定的),它指示JVM这个变量是不稳定的,每次使用它都到主存中进行读取,因此多线程环境下volatile关键字的使用变得非常重要。一般来说,多线程环境下各线程间共享的变量都应该加volatile修饰。
抽象类和接口的区别
- 相同点:都有抽象方法,不能实例化,有声明,能引用
- 面向抽象类和接口编程,不要面向具体类编程,这也是各种设计模式的核心思想
- 一个类只能继承单个类,但是可以实现多个接口
- 抽象类有域变量,可能有具体方法可调用抽象方法,必须有子类继承,扩展性弱
- 接口不能有域变量,只有静态常量,只有抽象方法,必须有具体类实现,扩展性强
- 接口还有标识(里面没有任何方法,如Remote接口)和数据共享(里面的变量全是常量)的作用.
Get和Post的区别
- GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连
- POST把提交的数据则放置在是HTTP包的包体中。
- GET方式提交的数据最多只能是1024字节,理论上POST没有限制,可传较大量的数据
- 服务器端获取GET和POST请求参数的方式不一样
- POST的安全性要比GET的安全性高。
fastjson和GSON的区别
- fastjson 是阿里出的json解析工具
- gson 是谷歌推荐的解析工具
- fastjson在解析的时候,字段不能大写。
- fastjson必须使用get和set方法
解析XML的几种方式的原理与特点:DOM、SAX、PULL
- DOM:消耗内存:先把xml文档都读到内存中,然后再用DOM API来访问树形结构,并获取数据。这个写起来很简单,但是很消耗内存。要是数据过大,手机不够牛逼,可能手机直接死机
- SAX:解析效率高,占用内存少,基于事件驱动的:更加简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。
- PULL:与 SAX 类似,也是基于事件驱动,我们可以调用它的next()方法,来获取下一个解析事件(就是开始文档,结束文档,开始标签,结束标签),当处于某个元素时可以调用XmlPullParser的getAttributte()方法来获取属性的值,也可调用它的nextText()获取本节点的值。
HTTP Status Code
- 1字头:消息
- 2字头:成功
- 3字头:重定向
- 4字头:请求错误
- 5、6字头:服务器错误
反射
调用隐藏API
异常 OutOfMemaryError
RuntimeException
空指针异常
算术(除零)异常
数组溢出异常
类转换异常
类没找到异常
- 单例模式
- 工厂模式
- Adapter适配器模式
- 观察者模式(Observer)
- 代理模式(AIDL) Binder
- 建造者(AlertDialog.Builder)
模板方法模式
模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。