面试

面试经历 | 快手Java开发 2021.09

2021-09-20  本文已影响0人  闭门造折

面试岗位

Java开发工程师(校招)

一面(2021.0914)

快手不知道为啥没有统一笔试,直接发起的面试。问的八股文很全面,算法题出的也让我感觉很好。

基础题

  1. Java基础数据类型有哪些,占多少位?
    答:共有8种,分别是:

    1. boolean 布尔:1位
    2. byte 字节:8位
    3. short 短整数:16位,2字节
    4. char 字符:16位,2字节
    5. int 整型:32位,4字节
    6. float 单精度:32位,4字节
    7. long 长整数:64位,8字节
    8. double 双精度:64位,8字节
  2. double运算时需要注意什么?为什么
    答:精度丢失,比方说当比较时,可以用差的绝对值小于一个极小值 \epsilon 来说明两个变量相等。原因是做计算时十进制会先转换成二进制,但是有的十进制转换成二进制是无限小数,必然会有精度舍弃。

  3. 你知道 float 是怎么存储小数的吗?
    答:以 6.5432 为例,整数部分用模二取余法:
    6 / 2 = 3 …… 0
    3 / 2 = 1 …… 1
    1 / 2 = 0 …… 1
    得到 6 的二进制表示 110。小数部分用乘二取整法:
    0.5432 * 2 = 1 + 0.0864
    0.0864 * 2 = 0 + 0.1728
    0.1728 * 2 = 0 + 0.3456
    0.3456 * 2 = 0 + 0.6912
    0.6912 * 2 = 1 + 0.3824
    0.3824 * 2 = 0 + 0.7648
    0.7648 * 2 = 1 + 0.5296
    可以得到 0.5432_{(10)} ≈ 0.1000101_{(2)}
    组合得到二进制为 110.1000101_{(2)}
    左移两位,使小数点前只有一位 1,即1.101000101_{(2)} * 2^2,则存储时指数为 2+127=129
    则最终 6.5432 存储结果为 0(符号位) 10000001(指数) 1010001 01000000 00000000

  4. volatile关键字作用
    参考资料《【Java线程】volatile的适用场景》
    答:volatile具有可见性和有序性,但是没有原子性。他可以使得它修饰的变量,每次修改时先同步到主存,每次使用前都从主存直接获取。这个操作保证了它的可见性。同时他的引入将避免指令重排的现象,保证了有序性。
    适用场景:

    • 用来标记某一个一次性状态已发生
    • 单例模式取消指令重排
    • 独立观察
    • volatile bean
    • 开销较低的读-写锁策略
  5. 泛型了解吗,他有什么用处?
    答:在集合类实现的时候,如果想实现一个通用的可以处理不同类型的类,需要使用Object作为属性和方法参数。然后具体操作时再去做强制转换,一来是使用时不方便,二来是只有运行时才能知道传入集合的值类型是否正确。因此在JDK 1.5之后,引入了泛型的概念。
    泛型的本质是参数化类型,把要操作的数据类型当做一个参数传入,这样在编译时就可以对存放的内容的类型做安全判断。

  6. private关键字作用
    答:加了之后的变量和方法,只有在类内部才能使用,外部不能直接调用,子类也不会继承。想调用的话可以配套写一对get,set。

  7. 反射了解吗?他是在编译阶段还是运行阶段。
    答:运行阶段,反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
    比如正常的调用应该是先 new 一个对象,然后使用对象的一些属性和方法做一些操作。但是反射中可能是先获得类,然后通过 getConstructor 方法和 newInstance 方法来创建一个对象以供使用。

  8. 反射可以获得 private 属性吗?他们俩是不是冲突的。
    答:确实可以用 getDeclaredField 获得包含私有变量在内的所有成员变量。
    private 最主要的目的实际上是为了实现封装性,为类内的 public 方法提供一些支持,同时不希望被外部直接调用,或是继承。
    反射如果单独的使用某个 private 方法或属性,大概率是没有什么作用的,因为本身 private 变量可能就已经配套有 getset;而单独调用 private 方法可能导致程序异常;同时原本继承该类的子类依然不能继承得到 private 成员变量。因此我们可以认为反射对我们希望实现的封装性(及一个父类的一些内部使用方法不影响外部环境),基本没有影响。

  9. 线程池了解吗?
    答:由于每次创建、销毁、或是管理线程都有一定的资源消耗,因此使用线程池,对线程做统一管理,当程序需要线程时,只需要向线程池申请,如果某个线程异常挂掉,那线程池还可以及时补充。

  10. ThreadPoolExecutor 知道哪些?
    答:SingleThreadExecutor :返回一个只有一个线程的线程池,多余的任务会被放到消息队列里慢慢执行。
    FixedThreadPoolExecutor :返回一个固定线程数的线程池,任务来时,如果有空闲线程就立刻执行,否则同样存放在消息队列中;如果线程挂掉,及时重新创建线程。
    CachedThreadPoolExecutor:可以动态调整线程池线程数,只要 JVM 能支持,可以无限开线程,同时如果没有任务需要也会自动回收。
    ScheduledThreadPoolExecutor:周期性执行任务

  11. ThreadPoolExecutor 有哪些参数?
    答:(当时并没有答出来)
    corePoolSize:核心线程数,及最小同时运行线程数量。
    workQueue:当新任务来时先判断线程数是否到核心线程数,若达到,则放进任务队列中。
    maximumPoolSize:当队列达到容量上限时,将同时运行线程数变为最大线程数。
    keepAliveTime:若当前实际任务数不超过核心线程数,但运行中的线程数超过了时,等待keepAliveTime 时间后,才进行销毁。
    unitkeepAliveTime参数的实践单位
    threadFactory:创建新线程的工厂类
    handler:饱和策略:线程容量和队列容量同时饱和时执行策略。包括①拒绝新任务 ②增加队列容量 ③ 直接丢弃 ④ 丢弃最早任务。默认使用第一种。

  12. GC 了解吗,怎么判断某个对象应该被回收?
    答:两种方法:引用计数法和可达性分析。
    引用计数:对于某个对象,每有一个地方引用他,计数器加 1,引用时效,计数器减 1。当计数值为 0 时说明对象应该被回收。
    可达性分析:从 GC root 出发,所有不可达的对象会被标记。 GC root 有以下几种: ①虚拟机栈:栈帧中的本地变量表引用的对象 ②native方法引用的对象 ③方法去中的静态变量和常量引用的对象

  13. G1 怎么做的标记和清除,过程是什么?
    答:G1 会将内存划分成若干个小块,且标记为老年代、EdenSurvivor,然后执行Young GC,如果对象存活就会被转移到Survivor 上,如果存活时间多于阈值,就会晋升老年代。而 G1 的老年代垃圾回收,就或用到标记清理过程:

    • 初始标记:Stop the World,标记可能有引用指向老年代对象的 Survivor 区,此操作与一次 Young GC 同时。
    • 扫描根区域:扫描 Survivor 区中引用到老年代的引用。
    • 并发标记:在堆上找活着的对象,并标记
    • 再次标记:Stop the World,完成堆内存中存活对象标记,使用 SATB 算法
    • 清理:Stop the World,统计+擦写+重置空 heap
    • 拷贝:Stop the World,转移或拷贝存活对象到未使用的 heap
  14. 三次握手四次挥手
    答:握手时:甲说嘿我要和你聊天了,乙回复我知道了,甲回复乙我知道你知道了。此时双方确认对方可以接收消息,因此开始建立连接发送消息。
    挥手时:甲说我说完了,乙说好的我知道了,但此时乙可能还有消息没有发送完毕。等了一会之后乙也发送完毕了,通知甲自己要中断连接了,甲收到之后回信知道了,并中断连接,乙收到后也中断连接。
    在两个过程中,都是通过比方说一个发送信号 x,另一个发送 x+1 这样的形式,验证对方确实收到自己发出的信号。

  15. TCP是什么?
    答:TCP是面向连接的,全双工的,可以提供可靠地连接服务。连接时使用三次握手,断连时使用四次挥手。TCP可以通过确认、重传、窗口、拥塞控制等机制保证数据正确性,但效率较低,且开销比UDP要大。

  16. MYSQL 索引的数据结构什么样?
    答:B+ 树,B 树是在中间节点及叶子节点都可以存放信息的一棵树,而 B+ 树则是所有信息均被存放在叶子节点,且在所有叶子节点间,从左至右存在一条链表,这样的好处是比方说我们想查一段区间中的索引值,那我们只需要找到两端,然后通过那条链表就可以很快的获取到我们想要的所有数据信息。而且B+树查询更稳定。

算法题

很喜欢这个算法题,不难但是考察有没有刷过题非常好。

  1. 给一个链表 1,2,3,4,5,...,n,把他变成1,n,2,n-1,...这种形式的链表返回
    答:先快慢指针找到中间点,然后把右半段链表逆序,然后双指针两头向中间靠近。
上一篇下一篇

猜你喜欢

热点阅读