2017安卓面试题-JAVA篇

来源:互联网 发布:芈月到底爱谁知乎 编辑:程序博客网 时间:2024/06/08 19:17

从零开始-JAVA

JAVA是安卓的应用和框架层的核心,面试也常常提及,是安卓的基础,地基建好后等待OFFER大楼的只差施工了

  • 基础语法
  • 集合框架
  • 线程相关
  • IO相关
  • 设计模式
  • JAVA虚拟机

基础语法

  • 1.switch能否用String类型做参数? 
    答:可以,在java7中添加了对String支持,之前不行.tips:不支持double,float,boolean

  • 2.重载和重写的区别? 
    答:重载体现了JAVA中的多态性,允许存在同名函数,只要满足参数类型不同 

    重写是子类对父类方法的一种覆盖,保留父类的方法,子类定义自己的方法实现

    • 3.java四个基本特性的面试题

      • ( 封装 多态 抽象 继承)

        • 抽象类和接口的区别?(抽象) 
          答:语法上: 
          抽象类可以有具体实现的方法而接口的方法全部抽象 
          一个类只能继承一个抽象类,但是可以实现多个接口 
          接口不能有静态的代码块和方法,抽象类可以有 
          设计上: 
          抽象类更像一种模板的设计,接口是一种行为的规范

        • JAVA多态实现原理 
          多态:同一消息根据发送目的的变换而采取多种不同的行为方式 
          原理:动态绑定,在运行期动态识别找到合适的方法

    • 4.equals与==的区别? 
      答:基本数据类型,都是比较值是否相等 
      引用数据类型,equals比较两个对象指向的内存空间的值是否相等,==比较指向的内存空间地址是否相同 
      tips:equals被String类重写所以判断的是字符串是否相等

    • 5.Hashcode方法的作用和equals的区别? 
      答:hashcode()返回的是对象内存地址通过哈希算法得到的整数值, 
      多出现于集合中判断其中是否有相同的元素,当往HashMap中添加元素时,会先用hashcode判断是否同一个元素,若不相同再用equals判断内容

    • 6.String、StringBuffer与StringBuilder的区别? 
      答: 
      String 不可变 适用场景:少数据量 
      StringBuffer可变 线程安全 适用场景:多线程大数据量 
      StringBuilder可变 线程不安全 适用场景:单线程大数据量 
      底层是Char[]数组实现的

    • 7.final, finally, finalize的区别? 
      答:final是修饰符 被修饰的成员无法被继承无法被覆盖无法被修改成员 
      finally语句块 多用于异常处理最后的收尾操作 
      finalize对象被垃圾回收期回收的时候会调用这个方法

    • 8.JAVA的四种引用类型,用到的场景 
      答: 
      1.强引用:不会被垃圾回收期回收,即使JVM内存不足会出现崩溃报错也不会被回收,我们经常new一个对象这个就是强引用,若要中断这种引用,可以显式的将对象赋值为null 
      2.软引用:当JVM内存不足时会回收,足够不回收 
      3.弱引用:被垃圾回收器发现就会被回收 通常可以用在图片的缓存上 
      4.虚引用:随时都有可能被回收

    • 9.说说java的反射机制原理以及应用场合? 
      答:反射机制即在运行过程中, 
      对于任意一个类,可以得到这个类的所有属性和方法 
      对于任意一个对象,可以调用它任意的方法和属性 

    • 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制

      出现场景:GSON的序列化和反序列化等,使用源码中一些被hide注解的方法(重要的基础:类对象: 封装了类的描述信息的对象,类加载的产物,由jvm创建java.lang.Class  获取类对象的方式:1.类名.class 2. 类的对象.getClass() 3. Class.forName("包名.类名"))

    集合框架集合框架概图

    • 1.Collection 和 Collections的区别? 
      答:Collection是集合的接口,实现它的主要有set和list 
      Collections是集合的一个帮助类,能帮助排序,搜索,线程安全化等操作

    • 2.ArrayList、LinkedList、Vector的区别? 
      答:ArrayList和Vector底层是由数组实现的,而LinkedList底层是由双向链表实现 
      Vector在线程安全性上高于ArrayList和LinkedList但代价是效率上变慢 

    • ArrayList因为在连续的空间中用序号标记位置,索引快,增删需要涉及元素移动, 
      LinkedList存在于独立的空间,对象间保存下一个的索引,增删只用记录本项的前后项即可,增删快,查询需要遍历,查询慢

    • 3.HashMap,HashTable的区别?(附加:ConcurrentHashMap) 
      答:HashMap实现的是Map接口而HashTable实现Map接口的同时继承Directory类 
      HashMap效率高但线程不安全,HashTable效率低但线程安全 
      HashMap的key和value都可以为null而HashTable不可以 
      ConcurrentHashMap是线程安全的hashmap并不是像HashTable一样每个方法加同步锁 
      他将map分成了几个类似于HashTable的有锁segment分段,put和get时根据hashcode值判断在哪个分段进行,安全性上高,性能也高

    • 4.HashMap,HashSet的区别? 
      答:HashMap实现是Map接口,HashSet实现Set接口 
      HashMap存储方式-键值对,HashSet存储对象 
      HashMap由键的HashCode来判断地址是否重复 
      HashSet存储对象也是通过HashMap的add键值对,但是键为对象,值为HashSet自身, 
      因为HashMap是允许重复值的所以我们需要重写HashCode和equals判断是否唯一,若相同返回false

    • 5.HashMap的底层源码实现 
      答:我们增加一组元素时,会根据输入的key值的hashcode计算hash值,根据哈希值得到元素所在数组下标 
      ,如果这个位置再数组上有其他元素,以链表形式加入到头部,最先进入的在尾部,如果下标位置没有其他元素就将元素放在这个位置上

    从上面的源代码中可以看出:当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。 
      
    - 6.Fail-Fast机制概述 

    答:在使用Iterator迭代器的时候,有其他线程修改了map,将会抛出ConcurrentModificationException(并发修改异常). 
    源码中:Iterator初始化时会将map的modCount修改次数赋值给expectedModCount, 
    在迭代中判断modCount和expectedModCount是否相等,若不相等就表名修改了map报错

    7.LinkedHashSet和HashTable的原理? 
    LinkedHashSet底层是用LinkedHashMap实现但又有HashSet(不重复)的特点 
    LinkedHashMap底层原理 是Entry[]数组,而Entry又是一个双向链表

    HashTable原理 是安全的HashMap HashMap底层原理 是Entry数组 而Entry是个单链表


    线程相关

    • 1.线程和进程的区别? 
      答: 
      进程是系统资源分配的基本单位 
      线程是CPU资源调度的基本单位 
      线程是进程内的一个执行单元,也是一个可调度的实体 
      进程内的多个线程共享这个进程内的所有资源 
      线程之间协同工作需要借助消息通信

    • 2.什么是线程池,线程池的作用是什么? 
      答: 
      线程池是对线程的一种封装,开辟一块内存区域,批量放入线程,由池管理器统一调度,当有线程任务,从池子取出,执行完再放回线程池中 
      作用:能提高线程的复用性,减少线程对象的创建,节约开销 
      能有效的控制并发线程,提高资源使用率,避免堵塞 
      提供了定期执行,定时执行,控制线程并发数等功能

    • 3.JAVA如何创建线程? 
      答: 
      1.继承Thread类 再new 
      2.实现Runnable接口再将其作为参数传入Thread类的构造方法中 再new 
      3.实现Callable接口

    • 4.用户线程和守护线程有什么区别? 
      答:用户线程是我们开发者创建的线程,守护线程是服务于用户线程的且与JVM一同关闭退出的的线程 例如:GC线程

    • 5.wait()和sleep()的区别? 
      答:wait方法属于Object类 而Sleep方法属于Thread类 
      JAVA中每个对象都有对象锁,当调用wait方法时会将这个锁释放其他线程有机会争抢这个锁,系统会将这个对象的资源空间让出,等待调用notify或notifyall方法后再得到这个锁执行任务 
      而sleep方法并没有释放掉对象锁,其他线程无法获得,一直保持这个对象的监控,当时间到时再执行任务

    • 6.JAVA多线程同步的方法? 
      答:1.同步代码块 
      2.同步方法 
      3.使用volatile修饰 
      4.使用重入锁(ReenreantLock)是对synchronized的扩展 
      5.使用ThreadLocal类管理共享变量,这样每个访问得线程都有这个变量副本可以随意修改

    • 7.什么是线程调度器和时间分片? 
      答:线程调度器是为Runnable状态的线程分配CPU时间,线程的启动依赖于线程调度器 
      时间分片是指将cpu时间分配给线程的过程,可以基于线程优先级和等待时间分配

    • 8.Synchronzied和Lock的区别? 
      答:Synchronized是隐式锁 Lock是显式锁 

    • Synchronized是托管给JVM,Lock是代码控制需要自己开启和关闭 
      JAVA6之后Synchronized被又优化了导致与lock性能上相差不大 
      Synchronized采用悲观锁机制,独占锁而Lock是乐观锁的机制,假设没有冲突出现错误重试,直到成功


    IO相关

    集合框架概图
    • 1.JAVA序列化,如何实现序列化和反序列化? 
      答:序列化:实现Seralizable接口 
      反序列化:实现Externalizable接口

    Java虚拟机

    • 1.JVM内存模型以及分区,需要详细到每个区放什么 
      答:JVM首先分为两个部分线程私有内存区,线程共享内存区 
      线程共享内存区:方法区(里面有常量池),堆 
      线程私有内存区:PC程序寄存器,本地方法栈,虚拟机栈

    方法区:涉及到类加载的时候,加载进来的类的信息,常量,字段,方法代码等的信息 
    常量池:方法区的一部分,其中存储的是,字面常量,符号引用等 
    堆:为对象分配内存 
    PC程序寄存器:记录正在运行虚拟机字节码的地址 
    本地方法栈:虚拟机原生方法执行的内存区域 
    虚拟机栈:方法执行的区域,每个方法执行时会创建栈帧,其中记录着局部变量表,方法返回地址等信息

    • 2.JAVA中堆和栈的区别? 
      答:都是数据结构

    堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质: 
    堆中某个节点的值总是不大于或不小于其父节点的值; 
    堆总是一棵完全树。 
    将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。

    堆用来存储对象,栈用来存储局部变量,执行方法 

    堆是线程共享的,栈是线程私有的

    • 3.介绍下Java GC机制 
      答:GC即垃圾收集,负责回收所有不可达的对象的内存空间 
      原理:采用有向图的方式记录和管理堆中的所有对象,判断是否可达

    • 4.GC怎么确定某个对象是垃圾?

    (1)引用计数法:将一个对象的引用关联计数保存,当引用次数为0则释放 
    缺陷:无法解决循环引用问题 A-B相互引用永远不为0,无法回收

    (2)对象引用遍历(现在大多数 jvm 使用的方法): 
    从一组对象开始,沿着整个对象图上的每条链接,递归确定可到达(reachable)的对象。如果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集

    • 5.java GC是在什么时候,对什么东西,做了什么事情(精华)?

    什么时候: 
    堆内存分为新生代,老年代 
    新生代分为Eden,Survival from,Survival to 当Eden内存满了发生Minor GC 
    当升到老年代的对象大于老年代的剩余内存会发生FullGC将清理整个堆空间

    对什么东西:对象引用遍历中,通过遍历对象图从根对象开始,不可达的对象

    什么事情:垃圾回收器根据不同的算法进行对象的回收

    在年轻代中Survival from,Survival to 使用了复制清理算法 
    具体实现:将Eden和Survival from中的存活的对象赋值到Survival to 
    然后将前面两个区域对象全部清除,不会产生碎片

    在老年代中GC使用标记清理算法 

    具体实现:先进行一次遍历将可达的标记,第二次遍历不可达的清理 
    会产生碎片-内存空间不连续 
    碎片整理:

    • 6.GC的种类? 
      1.基于引用计数算法的GC 有对象引用+1,引用完毕-1 
      2.基于跟踪收集的GC 从根对象开始遍历对象图,记录可达和不可达的 
      3.基于对象跟踪分代收集的GC 将JVM堆中根据对象存活时间分段-年轻代,老年代,永久代 
      在不同的分段采取不同的垃圾回收算法

    Java有四种类型的垃圾回收器:

    串行垃圾回收器(Serial Garbage Collector) 
    并行垃圾回收器(Parallel Garbage Collector) 
    并发标记扫描垃圾回收器(CMS Garbage Collector) 
    G1垃圾回收器(G1 Garbage Collector)


    设计模式

    设计模式即代码的写法,如何才能写出高质量的代码的总结 
    - 1.单例模式:一个类只有一个实例,并将其向全局提供 
    懒汉式:将实例放入静态方法中

    private static MyClass myClass=null;    private MyClass() {}    public static MyClass getInstance(){        if(myClass==null){            myClass=new MyClass();        }        return myClass;    }
    饿汉式 将实例放在成员中
  • private static final MyClass myClass=new MyClass();    private MyClass() {}    public static MyClass getInstance(){        return myClass;    }


    登记式:通过map实现(仅了解)

    优化安全问题的单例-双重检查锁定






  • private static volatile MyClass myClass=null;//第一重锁定    private MyClass() {}    public static  MyClass getInstance(){        if(myClass==null){//第一重检查            synchronized (MyClass.class){//第二重锁定              if(myClass==null){//第二重检查                  myClass=new MyClass();              }            }        }        return myClass;    }

    • 2.工厂模式:实例化对象的模式,用自己的工厂方法代替new,批量生产对象的模式

    简单工厂模式(Simple Factory) 缺点:增加产品需要修改工厂代码,违背开闭原则

    public class Factory {      public BMW createBMW(int type) {          switch (type) {          case 320:              return new BMW320();          case 523:              return new BMW523();          default:              break;          }          return null;      }  } 
    工厂方法模式(Factory Method) 改进:只需生成无需修改
  • interface BMWFactory {//创建工厂接口    BMW createBMW();}class  BMW320Factory implements BMWFactory{//创建不同的工厂    @Override    public BMW createBMW() {        return new BMW320();    }}class  BMW523Factory implements BMWFactory{    @Override    public BMW createBMW() {        return new BMW523();    }}

    抽象工厂模式(Abstract Factory) 更加抽象

    产品抽象

    public interface Engine {//创建发动机}class EngineA implements Engine {    public EngineA(){        System.out.println("制造-->EngineA");    }}class EngineB implements Engine {    public EngineB(){        System.out.println("制造-->EngineB");    }}//空调以及型号interface Aircondition {}class AirconditionA implements Aircondition{    public AirconditionA(){        System.out.println("制造-->AirconditionA");    }}class AirconditionB implements Aircondition{    public AirconditionB(){        System.out.println("制造-->AirconditionB");    }}
    工厂抽象
  • //创建工厂的接口    public interface AbstractFactory {        //制造发动机      public Engine createEngine();      //制造空调       public Aircondition createAircondition();   }    //为宝马320系列生产配件    public class FactoryBMW320 implements AbstractFactory{        @Override        public Engine createEngine() {              return new EngineA();        }        @Override        public Aircondition createAircondition() {            return new AirconditionA();        }    }    //宝马523系列  public class FactoryBMW523 implements AbstractFactory {         @Override        public Engine createEngine() {              return new EngineB();        }        @Override        public Aircondition createAircondition() {            return new AirconditionB();        }    }

    • 3.适配器模式 
      类适配器:创建adapter类继承需要实现特殊功能的类并实现规范接口,即可转型调用
    public interface Target {    public void request();//标准接口}// 具体目标类,只提供普通功能class ConcreteTarget implements Target {    public void request() {        System.out.println("putong");    }}// 用户需要的类具有特殊功能class Adaptee {    public void specificRequest() {        System.out.println("teshu");    }}class Adapter extends Adaptee implements Target{    @Override    public void request() {        specificRequest();    }}  class Client {        public static void main(String[] args) {            // 使用普通功能类            Target concreteTarget = new ConcreteTarget();            concreteTarget.request();            // 使用特殊功能类,即适配类            Target adapter = new Adapter();            adapter.request();        }}
    对象适配器 在适配器中关联类

  • // 适配器类,直接关联被适配类,同时实现标准接口  class Adapter implements Target{      // 直接关联被适配类      private Adaptee adaptee;      // 可以通过构造函数传入具体需要适配的被适配类对象      public Adapter (Adaptee adaptee) {          this.adaptee = adaptee;      }      public void request() {          // 这里是使用委托的方式完成特殊功能          this.adaptee.specificRequest();      }  }  // 测试类  public class Client {      public static void main(String[] args) {          // 使用普通功能类          Target concreteTarget = new ConcreteTarget();          concreteTarget.request();          // 使用特殊功能类,即适配类,          // 需要先创建一个被适配类的对象作为参数          Target adapter = new Adapter(new Adaptee());          adapter.request();      }  } 









2 0