参加了2017年校招,面试了阿里、百度、腾讯、滴滴、美团、网易、去哪儿等公司,个人是客户端 Android 方向,总结了面试过程中频率出现较高的题目,希望对大家有所帮助。 Object 有哪些方法
registerNatives(); } } 自动装箱Integer j = new Integer(0); System.out.println(j == i); System.out.println(j.equals(i)); } 上述代码的输出是 Java 虚拟机 GC 根节点的选择Java通过可达性分析来判断对象是否存活。基本思想是通过一系列称为”GC roots”的对象作为起始点,可以作为根节点的是:
笔者这么理解,作为GC Roots的节点主要在全局性的引用(例如常量或类静态属性)与执行上下文(例如栈帧中的本地变量表)中。 虚拟机栈、本地方法栈这都是局部变量,某个方法执行完,某些局部使用的对象可以被回收。 类加载机制
从 java 虚拟机的角度而降, 只存在两种不同的类加载器:
加载类的寻找范围就是 JVM 默认路径加上Classpath, 类具体是使用哪个类加载器不确定。 类加载主要步骤
双亲委派模型除了顶层的启动类加载器之外, 其余的类加载器都应当有自己的父类加载器, 父子关系这儿一般都是以组合来实现。 工作过程:如果一个类加载器收到了类加载的请求, 它首先不会自己去尝试加载这个类, 而是把这个请求委派给父类加载器去完成, 最终所有的加载请求都会传送到顶层的启动类加载器中, 只有当父类加载器反馈自己无法完成这个请求时候, 才由子加载器来加载。 例如类 Object,它放在 rt.jar 中,无论哪一个类加载器要加载这个类,最终都是委派给启动类加载器进行加载,因此 Object 类在程序的各种类加载器环境中都是同一个类。 对于任何一个类, 都需要由加载它的类加载器和这个类本身一同确定其在 java 虚拟机中的唯一性。 ClassLoader.loadClass() 的代码如下,先检查是否已经被加载过,如果没有则 parent.loadClass() 调用父加载器的 loadClass() 方法,如果父加载器为空则默认使用启动类加载器作为父加载器。如果父类加载器加载失败,抛出 ClassNotFoundException,再调用自己的 findClass() 方法进行加载。 另外,如果我们自己实现类加载器,一般是 Override 复写 findClass 方法,而不是 loadClass 方法。 throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); }} catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader} if (c == null) { // If still not found, then invoke findClass in order // to find the class.long t1 = System.nanoTime(); c = findClass(name); //可以Override该方法 }} if (resolve) { resolveClass(c);} return c; }} JSP 与 Servlet 的关系
Servlet 生命周期主要是 java.servlet.Servlet 接口中的init() 、service() 、和 destroy() 3个方法。
GET 请求 vs POST 请求
HTTP 请求的基本格式
索引的分类主要分为聚集索引和非聚集索引:
ResultSet 统计记录数目Java 中使用 JDBC 连接数据库,最后都会得到一个 ResultSet,比如如下的代码 Connection con = DriverManager.getConnection(url, username, password); Statement sta = con.createStatement(); String sql = 'select * from student'; ResultSet resultSet = sta.executeQuery(sql); 那么如何根据得到的 ResultSet 统计一共有多少条记录呢?注意:ResultSet 没有提供类似 size()、length 的 API 来直接获取总记录数。 方法1:利用循环 while(resultSet.next()){ sum++; } 方法2:利用ResultSet的getRow方法来获得ResultSet的总行数 resultSet.last(); //移到最后一行 int rowCount = resultSet.getRow(); //得到当前行号,也就是记录数 单例模式单例模式中必须保证只有一个实例存在。有时候单例是为了避免重复创建多个实例造成资源浪费,有时候也是为了避免多个不同的实例导致系统不一致的行为。 Android 中,App启动时系统会创建一个 Application 对象,用来存储系统的一些信息,这儿的 Application 就是是单例模式的应用。可以通过 Context.getApplicationContext() 获取唯一的 Application 实例。 private volatile static Singleton instance; private Singleton() { } public static Singleton getInstance() { //第一重判断 if (instance == null) { //锁定代码块 synchronized (Singleton.class) { //第二重判断 if (instance == null) { instance = new Singleton(); //创建单例实例 } } } return instance; } } 为什么 synchronized 里面需要加一次判断 if (instance == null),是考虑这样的特殊情形:比如线程A、B都到达第一个 if (instance == null),线程A进入 synchronized 代码中创建实例,线程B排队等待。但当A执行完毕时,线程B进入 synchronized 锁定代码,它并不知道实例已经创建,将继续创建新的实例,导致产生多个单例对象。 也可以用内部类的方式创建, public class Singleton(){ private static class Inner { private static Singleton instance = new Singleton(); } private Singleton() { } public static Singleton getInstance(){ return Inner.instance; }} 模板方法模式在父类中实现一个算法不变的部分,并将可变的行为留给子类来实现。 比如 AsyncTask 里面的四个方法 onPreExecute、doInBackground、onProgressUpdate、onPostExecute 还有 Activity 也应用了模板方法模式 适配器模式 分为两种:类的适配器模式、对象的适配器模式 Android 里的 ListView 和 RecyclerView的 setAdapter() 方法就是使用了适配器模式。 观察者模式在 GUI 中,不管是 Windows 桌面应用、或者 Android、IOS,都会给某个按钮 Button 设置监听事件,这儿就是使用了观察者模式。Android 中设置 Button 的监听事件代码如下: button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { // Perform action on click }}); 线程 VS 进程关于线程和进程,不正确的描述是__。(选 D 栈是线程私有, 保存其运行状态和局部变量 )
找出未打卡的员工 题目:输入两行数据,第一行为全部员工的 id,第二行为某一天打卡的员工 id,已知只有一个员工没有打卡,求出未打卡员工的 id。(员工 id 不重复,每行输入的 id 未排序) 输入: 分析:可以用两个 List,第一个 List 保存所有员工的 id,第二个 List 保存打卡员工的 id,从第一个List 中把第二个 List 的数据都删除,最终剩下的就是未打卡员工的 id。 更好的方法:异或,两行数据中未打卡员工的 id 出现了一次,其余员工的 id 都出现了2次,两个相同的数异或为0。 Scanner scan = new Scanner(System.in); while (scan.hasNext()) { String[] ids = scan.nextLine().split(' '); String[] marks = scan.nextLine().split(' '); int result = 0; for (int i = 0; i < ids.length;="" i++)=""> result ^= Integer.parseInt(ids[i]);} for (int i = 0; i < marks.length;="" i++)=""> result ^= Integer.parseInt(marks[i]); } System.out.println(result); } } 快速排序排序是经典面试题,公司也希望通过手写快排来考察面试者的编程习惯和基本功。 // 排序范围 [start, end], 包含 end public void sort(int[] arr, int start, int end) { if (start < end)=""> int p = partition(arr, start, end); quickSort(arr, start, p - 1); quickSort(arr, p + 1, end); }} // 一次划分代码,返回被划分后的基准位置 public static int partition(int[] arr, int left, int right) { int pivot = arr[left];while (left <>{ while (left < right="" &&="" arr[right]="">= pivot) right--; if (left <> arr[left++] = arr[right]; while (left < right="" &&="" arr[left]=""><=>=> left++; if (left <> arr[right--] = arr[left];} arr[left] = pivot; return left; }Note:快排是不稳定的,常见的稳定排序是:冒泡、插入、归并 括号字符串是否合法某个字符串只包括 ( 和),判断其中的括号是否匹配正确,比如 (()()) 正确,((())() 错误,不允许使用栈。 这种类似题的常见思路是栈,对于左括号入栈,如果遇到右括号,判断此时栈顶是不是左括号,是则将其出栈,不是则该括号序列不合法。 面试官要求不能使用栈,可以使用计数器,利用 int count 字段。 public static boolean checkBrackets(String str) { char[] cs = str.toCharArray(); int count = 0; for (int i = 0; i < cs.length;="" i++)=""> if (cs[i] == '(') count++; else { count--; if (count < 0)=""> return false; }} } return count == 0; }扑克牌随机发牌对于52张牌,实现一个随机打算扑克牌顺序的程序。52张牌使用 int 数组模拟。 该算法的难点是如何保证随机性?有个经典算法 shuffle,思路就是遍历数组,在剩下的元素里再随机取一个元素,然后再在剩下的元素里再随机取一个元素。每次取完元素后,我们就不会让这个元素参与下一次的选取。 To shuffle an array a of n elements (indices 0..n-1): for i from n ? 1 downto 1 do j ← random integer with 0 ≤ j ≤ iexchange a[j] and a[i] 注意这儿是 0 ≤ j ≤ i,包括 j=i 的情况,因为可能洗牌后某个牌未发生交换,比如第51张牌还是原来的第51张牌。 public void randomCards() { int[] data = new int[52]; Random random= new Random(); for (int i = 0; i < data.length;=""> data[i] = i; for (int i = data.length - 1; i > 0; i--) { int temp = random.nextInt(i+1); //产生 [0,i] 之间的随机数 swap(data,i,temp);} } 金条付费你让工人为你工作7天,回报是一根金条,这个金条平分成相连的7段,你必须在每天结束的时候给他们一段金条,如果只允许你两次把金条弄断,你如何给你的工人付费? 答案:切成一段,两段,和四段。 第1天:给出1 赛马25匹马,速度都不同,但每匹马的速度都是定值。现在只有5条赛道,无法计时,即每赛一场最多只能知道5匹马的相对快慢。问最少赛几场可以找出25匹马中速度最快的前3名? 答案:
本文作者:码农网 – 陈小波
|
|