安卓面试:java部分
1. 面向对象的三大特性,如何理解其中的多态?
* 三大特性:封装、继承、多态
* 多态是指允许不同的子类型的对象对同一消息作出不同的响应。多态分为编译时的多态和运行时的多态。方法重载实现是编译时的多态,也称为前绑定,而方法重写的实现称为运行时的多态,也称为后绑定。运行时的多态是面向对象的最重要的东西,要实现多态需要做两件事:1,方法重写,子类继承父类并重写父类中已有的或者抽象的方法。2,对象构造,用父类的引用引用子类型的对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为。
2. JVM 的内存模型?
3. String、StringBuilder、StringBuffer 的区别,StringBuffer 是如何实现线程安全的?
* String是字符串常量,是final类,对String的操作会产生中间对象,从而引起频繁的GC
* StringBuilder是线程不安全的字符串变量,对StringBuilder的操作都是对自身的操作,因此不会生成新中间对象
* StringBuffer是线程安全的字符串变量,与StringBuilder类似
* StringBuffer在每一个方法上加synchronized关键字来保证线程安全。
4. 了解过 HTTP 吗?说说它的特点,它里面有哪些方法,有了解过吗?知道 HTTPS 吗?这两者有什么区别?
* HTTP是一个基于TCP/IP来传递数据的网络协议。
* 特点:1、简单快速,客户向服务器请求服务时,秩序传递请求方法和路径;2、灵活,允许传输任何类型的数据对象;3、无连接,每一次连接只处理一个请求。客户收到服务器的响应后,即断开连接;4、无状态,对于事务处理没有任何记忆功能;5、支持B/S和C/S模式。
* 最基本的方法有四种,分别是GET、POST、PUT、DELETE,对应资源的差、该、增、删4个操作。其实最常用的只有GET和POST,GET用于获取或者查询数据,POST用于更新资源信息。
* HTTPS是在HTTP应用层的基础上使用安全套接字层做子层的网络协议
* 两者的区别:
1. HTTP的URL是http开头,HTTPS是以https开头
2. HTTP是不安全的,HTTPS是安全的
3. HTTP标准端口是80,HTTPS的是443
4. 在OSI网络模型中,HTTP工作于应用层,HTTPS工作于传输层
5. HTTP无需加密,HTTPS对传输的数据进行了加密
6. HTTP无需证书,HTTPS需要认证证书。
5. 你平常是怎么进行加密的?MD5 加密是可逆的吗?
* 一般对敏感的数据,比如用户的密码采用MD5加密。这种加密方式不可逆
* 其他的加密类型有:1、sha1,也是不可逆的加密,比md5长度要长,比较安全;2、还有可逆的加密,分为两种,对称加密:DES和AES,只有一把可自定义钥匙,加密速度快;非对称加密:RSA,程序会生成两把钥匙:公私和私匙,公私加密只能用私匙解密,私匙加密只能用公私解密,安全性比较高
* md5加密原理:md5会以512位分组处理输入的信息,且每一分组又被划分为16个32位的子分组,经过复杂的处理后,输出由4个32位分组组成,将这4个32位分组级联后将生成一个128位散列码。
6. 接口与抽象类的区别?static 方法可以被覆盖吗?为什么?
* 接口只能抽象方法,抽象类可以有抽象方法,两者都不能创建对象,需要被继承。
* 不能被覆盖。形式上可以重写,只要子类不添加override编译可以通过,但从本质上来说不是Java的重写,因为静态方法只与类有关,不与具体实现相关,声明的是什么类,则引用相应类的静态方法。
7. 创建线程的方式,他们有什么区别?知道线程池吗?说说对线程池的理解?
* 创建线程有四种方式
1. 继承Thread类创建
2. 现实Runnable接口创建
3. 使用Callable和Future创建
* 区别
1. 自定义类继承Thread类,并覆写run()方法,该方法就是线程要完成的任务,调用start()方法启动线程
2. 定义Runnable的实现类,一样覆写run()方法,并将这实现类作为Thread的target来创建Thread对象
3. Callable接口提供call()方法作为线程的执行体,call既可以有返回值,也可以声明抛出异常;java5提供了Future接口来控制与它关联的Callable任务
* 线程池的理解
1. 线程池就是事先将多个线程对象放到一个容器中,当使用的时候就不用new对象而是直接去容器中拿线程即可,节省了开辟线程的时间,提高了响应的速度。
2. Executors提供了四种生成线程池的静态方法,FixedThreadPool、CachedThreadPool、ScheduledThreadPool和SingleThreadExecutor。
3. ThreadPoolExecutor是线程池的真正实现,比较常用的构造方法的参数有corePoolSize核心线程数、maxinumPoolSize非核心线程数、keepAliveTime闲置线程的超时时长、Unit超时时长单位、workQueue任务队列和threadFactory线程工厂,提供创建线程的功能
8. 你了解过 Java 的四种引用吗?分别代表什么含义,他们有什么区别?
* 四种引用:强引用、软引用、弱引用和虚引用
* 强引用,直接new出来的对象,即使内存空间不足,垃圾回收器也不会回收它,java虚拟机宁愿抛出异常;软引用,当虚拟机内存不足时,将会回收它指定的对象;弱引用,随时可能被垃圾回收器回收,不一定等到虚拟机内存不足时才回收;虚引用,和没有引用几乎是一样的。
* 软引用和弱引用的区别:具有弱引用的对象拥有更短的生命周期。如果只是避免OOM异常的发生,则可以使用软引用;如果在意应用的性能,想尽快回收一些占有内存比较大的对象,则可以使用弱引用。
9. Java 中关于 equals 和 hashcode 的理解?
* equals的作用是用来判断两个对象是否相等。如果某个类没有覆写该方法,比较的是两个对象的地址是否相等,等价于两个=;如果覆写了该方法,比较的是两个对象的内容是否相等。
* hashCode的作用是获取哈希码,也称为散列码,哈希码的作用是确定该对象在哈希表中的索引位置,也就是说hashCode()在散列表中才有用,其他情况下用处不大。
10. 关于 Java 中深拷贝和浅拷贝的区别?
* 将一个对象的引用直接复制给另一个对象,有三种方式:直接赋值;浅拷贝;深拷贝
* 直接赋值,A a1=a2,a1和a2指向同一个对象,当其中一个变化时候,另一个也会随之变化。
* 浅拷贝,期望把a1赋值给a2后,a1和a2保持独立,互不影响。主要是覆写的是clone()函数。创建一个新对象,然后将当前的对象的非静态字段复制到该新对象,如果字段是值类型,那么对该对象执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此原始对象和副本引用同一个对象。
* 深拷贝,之所以有深拷贝,是因为浅拷贝是选择性的拷贝。如果是基本类型,则拷贝其值;如果是实例对象,则拷贝其地址引用;如果是String字符串,则拷贝其地址引用,但在修改时,会从字符串池中重新生成一个新的字符串,原有的保持不变。针对上面的情况,只需要在clone方法里面新建对象,然后返回该对象引用即可。但是如果存在大量的对象是通过拷贝生成的,每一个类都写一个clone方法,并将还需要进行深拷贝,这是很耗时耗力的。在这种情况下,通过序列化来完成对象的拷贝,在内存中通过字节流的拷贝是比较容易实现的。
11. 简单的说下 Java 的垃圾回收?
* java虚拟机将其管辖的内存分为三个部分:方法区、Java栈和Java堆。方法区是静态分配的,常量池、static变量等保存在方法区;Java栈是一个逻辑概念,特点是后进先出。最典型的应用是方法的调用。栈中储存的数据是运行时确定的。Java堆保存的是java的对象,由虚拟机的垃圾回收器负责回收。
* GC在回收对象前必须发现哪些是无用对象。常用的搜索算法有:
1. 引用计数器算法,如果有地方引用,计算器+1,引用失效-1,当计算器为0的时候,jvm就认为该对象不再被使用,可以垃圾回收了。但是这个算法有一个缺点,就是不能解决循环引用的问题,因此该算法不在被使用;
2. 根搜索算法,该算法是通过一些GC roots对象作为起点,从这个节点开始往下搜索,搜索通过的路径成为引用链,当一个对象没有被GC roots的引用链链接的时候,说明这个对象是不可用的。
* 当通过某种算法确定无用对象后,就是回收过程了,常用的回收算法如下:
1. 标记-清除算法。该算法分两个阶段:标记和清除。在标记阶段,确定所要回收的对象,并标记;清除阶段紧随标记阶段,将标记阶段无用的对象进行清除处理。该算法效率不高,清除后会产生大量不连续的空间,当需要分配大内存对象时,可能无法找到足够的连续空间
2. 复制算法。该算法将内存分成两块。每次使用其中一块,当垃圾回收的时候,将存活的对象复制到另一块上,如果清除这一块无用的对象。该算法实现简单,运行效率高。如果内存分配合理,比如*:1,则内存的利用率也是很高的。Jvm用复制算法收集新生代。
3. 标记--整理算法。标记--整理算法与标记--清除算法类似,标记整理算法把存活的对象往内存的一端移动,然后直接回收边界意外的内存。jvm用该算法收集存活时间较长的老年代
4. 分代收集。根据对象的存活时间把内存分为新生代和老年代,然后在各个代采用不同的垃圾回收算法。新生代采用复制算法,老年代采用标记--整理算法。
12. 了解过 Java 的集合吗?说说 HashMap 的底层实现原理?ArrayList 和 LinkedList 的区别?Java 集合中哪些是线程安全的?
* HashMap底层就是一个数组的数据结构,数组中的每一项又是一个链表。Entry就是数组中的元素,每一个Map.Entry其实就是一个key-value键值对,它持有一个指向下一个元素的引用,这就构成了元素。
* 当要存储一个Entry对象时,会根据hash算法来决定其在数组中的存储位置,在根据equals方法来决定其在该数组上的链表中的存储位置;当要取出一个Entry时,也会根据hash算法找到数组中的存储位置,再根据equals方法从该位置上的链表取出该Entry。
* 两者都实现了List接口,ArrayList是以数组的方式来实现的,数组的特性是可以使用索引的方式来快速定位对象的位置,因此查询块;LinkedList是以链表的方式来实现的,因此在增删时效率上要比ArrayList好得多。
* vector是ArrayList的多线程版本,HashTable是HashMap的多线程版本。并发集合:ConcurrentHashMap、CopyOnWriteArrayList、CopyOnWriteSet
13. 如何实现对象的排序?
* 两种方法
1. 将要排序的对象类实现Comparable接口,覆写compareTo方法,调用Collectons的sort函数
2. 使用Comparable匿名内部类实现。
14. 知道 ThreadLocal 吗?说说对它的理解?
* ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储后,只有指定的线程可以获得存储的数据,其他线程是无法访问该数据的。ThreadLocal会根据指定的线程来初始化内部类Value ,localValue内部有一个Object数据table,数据的存取就是对该table数组的操作。因此,在不同线程访问同一个ThreadLocal的set和get的操作仅限于各自的线程的内部,多个线程互不干扰的存储和修改数据。
15. 在你写代码的过程中有使用过设计模式吗?你知道哪些?为什么要这样用,能解决什么问题?
16. 了解注解吗?了解反射吗?为什么要使用反射?
17. 数据结构中常用排序算法?