我经历的一些Android面试题及答案

最近在考虑换工作,连续面试了几家公司,这里整理一些比较有意思的面试题(普通面试题和算法题,本人算法基础比较薄,算法题不是强项)。

面试题

  1. Java中static静态代码块的调用时机。

    Java中的静态变量和静态代码块是在类加载的时候就执行的,实例化对象时,先声明并实例化变量再执行构造函数。如果子类继承父类,则先执行父类的静态变量和静态代码块,再执行子类的静态变量和静态代码块。同样,接着在执行父类和子类非静态代码块和构造函数。

    注意:(静态)变量和(静态)代码块的也是有执行顺序的,与代码书写的顺序一致。在(静态)代码块中可以使用(静态)变量,但是被使用的(静态)变量必须在(静态)代码块前面声明。

    最后给出执行步骤:

    1、父类静态变量和静态代码块(先声明的先执行);

    2、子类静态变量和静态代码块(先声明的先执行);

    3、父类的变量和代码块(先声明的先执行);

    4、父类的构造函数;

    5、子类的变量和代码块(先声明的先执行);

    6、子类的构造函数。

  1. Android数据库结构升级容易遇到哪些问题,如何解决?

    Android 数据库升级完整解决方案

  2. Android运行时权限。

    Android6.0权限机制(一):介绍

    Android6.0权限机制(一):封装

    Android6.0权限机制(三):6.0以前国产手机权限处理

  3. Android进程保活手段。

    实现传言中的黑科技-1像素保活

  4. AMS、WMS它们之间的关系以及协作状态。

    Android系统服务-AMS和WMS

  5. Android内存问题,造成内存泄漏的原因,如何避免内存泄漏。

    内存泄漏与排查流程——安卓性能优化

  6. ThreadLocal是什么,有什么作用。

    Android的消息机制之ThreadLocal的工作原理

  7. String,StringBuffer与StringBuilder的区别?

    String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全)

    区别详解

  8. 是否可以使用Application中开辟子线程来代替Service开启子线程?

    理论上可以在Application中开启子线程,但是会有弊端:

    Application中逻辑过多会拖慢APP启动速度

    Application生命周期过长,后天任务不一定需要这么长的生命周期,使用IntentService可以实现任务结束自动关闭

    Application生命周期无法延续,在被强杀后,后台任务会关闭;而服务可以指定新进程进行保活。考虑音乐播放器的功能,有些音乐播放器,即使应用退出后依然可以进行前台服务的保留以便于随时恢复

    唯一好处是在Application中开启线程较之Service启动新线程,开销较小

算法题

  1. 简述几种排序算法和它们的时间复杂度。

    我回答了冒泡、快速、选择和堆排,这里索性把几种排序的Java实现也写一下,查漏补缺。

    冒泡排序

    /**
        * 冒泡排序
        * @param array 目标数组
        */
    public static void bubbleSort(int []array) {
       for(int i =0;i<array.length-1;i++) {
           for(int j=0;j<array.length-i-1;j++) {//-1为了防止溢出
               //数组内元素两两比较,顺序不一致就交换位置
               if(array[j]>array[j+1]) {
                   int temp = array[j];
    
                   array[j]=array[j+1];
    
                   array[j+1]=temp;
               }
           }
       }
    }

    快速排序

    /**
        * 快速排序
        * @param array 目标数组
        * @param low 快排起始坐标
        * @param high 快排终止坐标
        */
    private static void quickSort(int[] array,int low,int high) {
       if(low > high) {
           return;
       }
       //进行第一次快排,将目标区间一分为2
       int i = low;
       int j = high;
       int key = array[low];
       while(i < j) {
           //从右往左找到第一个比目标值小的数值位置,标记为j
           while(i < j && array[j] >= key) {
               j--;
           }
           //从左往右找到第一个比目标数值大的数值位置,标记为i
           while(i < j && array[i] <= key) {
               i++;
           }
           //互换位置
           if(i < j) {
               int temp = array[i];
               array[i] = array[j];
               array[j] = temp;
           }
       }
       //调整目标基准值的位置
       array[low] = array[i];
       array[i] = key;
       quickSort(array,low,i-1);
       quickSort(array,i+1,high);
    }

    选择排序

    /**
        * 选择排序
        * @param array 目标数组
        */
    public static void selectSort(int[] array) {
       for(int i = 0;i < array.length;i++) {
           int min = array[i];//假定起始位置的数值为最小数值
           int pivotPosition = i;//记录起始位置坐标
           for(int j = i;j < array.length;j++) {
               //找出剩余数组中最小的值,记录其坐标
               if(array[j] < min) {
                   pivotPosition = j;
                   min = array[pivotPosition];
               }
           }
           //将最小值放入起始位置
           if(i != pivotPosition) {
               array[pivotPosition] = array[i];
               array[i] = min;
           }
       }
    }

    插入排序

    /**
        * 插入排序
        * @param array 目标数组
        */
    public static void insertSort(int[] array) {
       //从第二个数据开始做循环,我们假定第一条数据已经在它应在的位置了
       for(int i = 1;i < array.length;i++) {
           //取出目标位置的数值
           int j = i;
           int target = array[i];
    
           //对比目标位置的数值,与左侧排好序的数组比较,若发现有比目标值大的数,将比目标值大的数位置的数值往前提,游标后移
           while(j > 0 && target < array[j - 1]) {
               array[j] = array[j - 1];
               j--;
           }
           //跳出循环后将当前target插入游标位置
           if(j != i) {
               array[j] = target;
           }
       }
    }
  2. 实现一个链表的反转。

    public class Node {
       private int index;
       private Node next;
    
       public Node(int index, Node next) {
           this.index = index;
           this.next = next;
       }
    
       public int getIndex() {
           return index;
       }
    
       public void setIndex(int index) {
           this.index = index;
       }
    
       public Node getNext() {
           return next;
       }
    
       public void setNext(Node next) {
           this.next = next;
       }
    
       //非递归
       public static  Node reverseList(Node head) {
           Node prev = null;
           while(head!=null){
               Node tmp = head.next;
               head.next = prev;
               prev = head;
               head = tmp;
           }
           return prev;
       }
    
       //递归
       public static Node reverseList2(Node head) {
           if(head==null || head.next ==null) {
               return head;
           }
           Node prev = reverseList2(head.next);
           head.next.next = head;
           head.next = null;
           return prev;
       }
    
    }
  3. 实现排序数组的二分查找。

    public class SearchUtils {
    
       /**
        * 二分查找,递归
        * @param array 目标数组
        * @param target 查找内容
        * @param low 查找起始位置
        * @param high 查找结束位置
        * @return 内容所在位置,-1代表不存在
        */
       public static int recursionBinarySearch(int[] array,int target,int low,int high) {
           if(low > high) {
               //起始位置大于结束位置,未找到,返回-1
               return -1;
           }
           if(low == high) {
               //起始位置等于结束位置,判断是否等于目标值
               if(array[low] == target) {
                   return low;
               } else {
                   return -1;
               }
           }
           int middle = (high + low)/2;//初始化中间位置
           if(array[middle] > target) {
               return recursionBinarySearch(array,target,low,middle-1);
           } else if(array[middle] < target) {
               return recursionBinarySearch(array,target,middle+1,high);
           } else {
               return middle;
           }
       }
    
       /**
        * 二分查找,非递归
        * @param array 目标数组
        * @param target 查找内容
        * @return 内容所在位置,-1代表不存在
        */
       public static int binarySearch(int[] array,int target) {
           int low = 0;
           int high = array.length - 1;
           int middle = 0;
    
           while(high > low) {
               middle = (high + low)/2;//获取中间位置
               if(array[middle] > target) {
                   high = middle - 1;
               } else if(array[middle] < target) {
                   low = middle + 1;
               } else {
                   return middle;
               }
           }
           if(array[low] == target) {
               return low;
           } else {
               return -1;
           }
       }
    }
  4. 实现二叉树的按层遍历。

    /**
        * 按层遍历二叉树
        * @param root 需要遍历的二叉树
        */
    public static void levelTree(TreeNode root)
    {
       if(root == null) return;
       Queue<TreeNode> queue = new LinkedList<TreeNode>() ;
       queue.add(root);
       while(queue.size() != 0)
       {
           int len = queue.size();
           for(int i=0;i <len; i++)
           {
               TreeNode temp = queue.poll();
               System.out.print(temp.data+" ");
               if(temp.left != null)  queue.add(temp.left);
               if(temp.right != null) queue.add(temp.right);
           }
       }
    }


    我的个人博客

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值