乐趣区

关于java:双非小伙暑期实习斩获腾讯WXG-offer这不比博人传燃

前言

也是来自一位粉丝分享的面试教训

这位同学大三暑期实习,经验三个技术面加一个 hr 面上岸腾讯,面试官问的题也是蛮有代表性的,比拟考验原理和思维逻辑,整理出来给大伙看一下,近期有面试的同学倡议珍藏,很有帮忙。

面试通过

  • 历经 3 技术 +1hr,4 轮面试
  • 技术一面 —–6.16
  • 技术二面 —–6.18
  • 技术三面 —–6.23
  • hr 面 —–6.30
  • oc——-7.1
  • offer—-7.2

面试题

所有的题这一篇文章必定是讲不完的,这里就挑一些比拟经典的题目跟大伙聊聊。

残缺的面试题能够看看我整顿的这份《2021 腾讯 Java 岗面试真题》

当然了,你对腾讯不感冒的话其余互联网 top 公司的真题我也有整顿,关注公众号:北游学 Java,回复“面试”即可支付我整顿好的所有面试材料。

好了,不废话了,开始注释。

依照常规,我先把题贴出来,再提答案,能够本人先思考一下,不会的能够往下翻看答案。

  • 深克隆、浅克隆,以及实现办法
  • Java 对象拜访
  • 解决 Hash 抵触的办法,Hash 抵触数据化
  • equals 和 hashcode 的关系
  • Innodb 为什么抉择 B + 树
  • 思维题,天平称小球,在一堆轻的中找到一个重的,总结通用公式
  • topk 问题的场景题
  • 算法局部:
    ①宰割回文串
    ②手写 LRU,并讲述原理讲的底层一些,为什么应用双向链表
    ③ rand5()->rand7()

面试题解

1、深克隆、浅克隆,以及实现办法

浅克隆:对象的援用类型变量复制的是对象的援用值

深克隆:将援用类型变量所指向的对象内存空间也复制一份给新对象

如何实现对象的克隆?分三步:

  1. 对象的类实现 Cloneable 接口;
  2. 笼罩 Object 类的 clone()办法;
  3. 在 clone()办法中调用 super.clone();
public class ShallowClone implements Cloneable{

    public int id;
    public String name;

    public ShallowClone(int id, String name){
        this.id = id;
        this.name = name;
    }

    public Object clone(){
        Object sc = null;
        try {sc = super.clone();
        } catch (Exception e) {System.out.println(e.toString());
        }
        return sc;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ShallowClone sc1 = new ShallowClone(1, "sc1Name");
        ShallowClone sc2 = (ShallowClone)sc1.clone();
        System.out.println("sc1's id: "+ sc1.id +"\tsc2's id:" + sc2.id);
        System.out.println("sc1's name: "+ sc1.name +"\tsc2's name:" + sc2.name);
        System.out.println(sc1.name == sc2.name);
        System.out.println(sc1.name.equals(sc2.name));
    }
}

输入后果:

sc1's id: 1    sc2's id: 1
sc1's name: sc1Name    sc2's name: sc1Name
true
true

2、Java 对象拜访

句柄拜访形式:java 堆中将划分出一块内存来作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中蕴含了对象实例数据和类型数据各自的具体地址信息。

指针拜访形式:reference 变量中间接存储的就是对象的地址,而 java 堆对象一部分存储了对象实例数据,另外一部分存储了对象类型数据。

[图片上传失败 …(image-68dcf6-1625474897121)]

这两种拜访对象的形式各有劣势,应用句柄拜访形式最大益处就是 reference 中存储的是稳固的句柄地址,在对象挪动时只须要扭转句柄中的实例数据指针,而 reference 不须要扭转。

应用指针拜访形式最大益处就是速度快,它节俭了一次指针定位的工夫开销,就虚拟机而言,它应用的是第二种形式(间接指针拜访)

3、解决 Hash 抵触的办法

尽管咱们不心愿发生冲突,但实际上发生冲突的可能性仍是存在的。当关键字值域远大于哈希表的长度,而且当时并不知道关键字的具体取值时。抵触就难免会发 生。

另外,当关键字的理论取值大于哈希表的长度时,而且表中已装满了记录,如果插入一个新记录,不仅发生冲突,而且还会产生溢出。解决抵触和溢出罕用的办法有两种

  • 凋谢定址法
  • 拉链法

具体就不开展讲了,不是一两句话能够讲完的,感兴趣的话能够本人找找相干的材料跟博客

4、equals 和 hashcode 的关系

  • 两个对象 equals 为 true 的话,hashcode 也应该雷同
  • 两个对象 equals 为 false 的话,hashcode 最好也要不同, 不然影响效率, 话中有话就是重写 equals 的话举荐也重写 hashcode

5、Innodb 为什么抉择 B + 树

这题的话我提一下 B + 树的特点应该就好了解了

B+ 树特点:

  1. B+ 树每个节点能够蕴含更多的节点,这样做有两个起因, 一个是升高树的高度。另外一个是将数据范畴变为多个区间,区间越多,数据检索越快。占用空间十分小,因而每一层的节点能索引到的数据范畴更加的广。换句话说,每次 IO 操作能够搜寻更多的数据。
  2. 每个节点不再只是存储一个 key 了,能够存储多个 key。
  3. 非叶子节点存储 key,叶子节点存储 key 和数据。
  4. 叶子节点两两指针互相链接,程序查问性能更高。叶子节点两两相连,合乎磁盘的预读个性。

6、思维题:天平称小球,在一堆轻的中找到一个重的,总结通用公式

这题也简略,用三分法很快就能够得出答案

  1. 每次将球分成三份(如果能平均分的话就平均分)。
  2. 将雷同数量的两份放天平上,如果两份一样重,则较轻的球必定在第三份中,接下来对第三份进行同 1 的操作;
  3. 否则,则对分量较轻的那一份进行同 1 操作。

所以,y<=3^x

7、topk 问题的场景题

这个应该也算是面试中比拟常见的场景题了,网上的解答博客有很多,这里提一下,就不赘述了

8、算法局部:

①宰割回文串

这道题也算是力扣比拟经典的了,这里给大伙贴张图,应该就很好了解了

②手写 LRU

package algorithm.Interview;

import java.util.HashMap;

public class LRUCache {
    private Node firstNode;
    private Node lastNode;
    private int initialCapacity;

    private HashMap<String, Node> hashMap;

    public LRUCache(int initialCapacity) {if (initialCapacity <= 0) {throw new IllegalArgumentException("initialCapacity must > 0");
        }
        this.initialCapacity = initialCapacity;
        hashMap = new HashMap<>();}

    public String get(String key) {Node node = hashMap.get(key);
        if (node == null) {return null;}
        // 元素被查问,则挪动元素到链表尾部
        removeNodeToTail(node);
        return node.value;
    }

    public void put(String key, String value) {Node node = hashMap.get(key);
        if (node == null) {
            // 大于内存容量,须要删除最不罕用节点
            if (hashMap.size() >= initialCapacity) {
                // 删除最不罕用的
                String oldKey = removeNode(firstNode);
                hashMap.remove(oldKey);
            }
            Node newNode = new Node(key, value);
            addNode(newNode);
            hashMap.put(key, newNode);
        } else {
            node.value = value;
            // 再次被赋值,挪动到链表尾部
            removeNodeToTail(node);
        }
    }

    /**
     * 挪动元素到链表尾部
     * @param node
     */
    private void removeNodeToTail(Node node) {if (node == lastNode) {return;}
        // 先删除
        removeNode(node);
        // 再增加到尾部
        addNode(node);
    }

    /**
     * 尾插法,链表元素越靠前越旧
     * @param node
     */
    private void addNode(Node node) {if (lastNode != null) {
            lastNode.next = node;
            node.prev = lastNode;
        }
        // 尾结点指向新插入的 node
        lastNode = node;
        // 链表为空,则同时为首节点
        if (firstNode == null) {firstNode = node;}
        node.next = null;
    }

    /**
     * 移除指定元素,并返回移除元素的 key
     * @param node
     * @return
     */
    private String removeNode(Node node) {if (node == lastNode) {
        lastNode = lastNode.prev;// 尾结点指向原尾结点的前驱节点
        lastNode.next =null;
    } else if (node == firstNode) {
        firstNode = firstNode.next;// 首结点指向原首结点的后继节点
        firstNode.prev = null;
    } else {
            node.prev.next = node.next;// 以后节点的前驱节点的后继节点指向以后节点的后继节点
            node.next.prev = node.prev;// 以后节点的后继节点的前驱节点指向以后节点的前驱节点
        }
        return node.key;
    }

    private class Node {
        Node prev; // 前驱节点
        Node next; // 后继节点
        String key;
        String value;

        Node(String key, String value) {
            this.key = key;
            this.value = value;
        }
    }

    @Override
    public String toString() {StringBuilder ret = new StringBuilder();
        Node p = firstNode;
        while (p!=null){ret.append("key:").append(p.key).append(",value:").append(p.value).append(";");
            p = p.next;
        }
        return ret.toString();}
}

③ rand5()->rand7()

算法代码:

    public static int random5() {return (int) (1+Math.random()*5);
    }
    public static int random7() {int a=random5();
        int b=random5();
        int rand=10*a+b;
        if(rand<14) {return 1;//11 12 13}else if(rand<22) {return 2;//14 15 21}else if(rand<25) {return 3;//22 23 24}else if(rand<33) {return 4;//25 31 32}else if(rand<36) {return 5;//33 34 35}else if(rand<44) {return 6;//41 42 43}else if(rand<52) {return 7;//44 45 51} else
            return random7();//52 53 54 55}

测试代码:

    public static void main(String[] args) {HashMap<Integer,Integer> map5=new HashMap<Integer,Integer>();

        for(int i=0;i<10000000;i++) {int key = random5();
            if(map5.get(key)==null) {map5.put(key, 1);
            }else
                map5.put(key, map5.get(key)+1);

        }
        System.out.println("random5:");
        map5.entrySet().forEach(e->{System.out.println(e+"\t"+1.0*e.getValue()/10000000);
        });

        System.out.println();

        HashMap<Integer,Integer> map7=new HashMap<Integer,Integer>();

        for(int i=0;i<10000000;i++) {int key = random7();
            if(map7.get(key)==null) {map7.put(key, 1);
            }else
                map7.put(key, map7.get(key)+1);
        }

        System.out.println("random7:");
        map7.entrySet().forEach(e->{System.out.println(e+"\t"+1.0*e.getValue()/10000000);
        });

    }

好了,这篇文章就写到这把,除了下面说的这些题,还有一些对于 TCP、线程池等题,问的挺宽的,毕竟面试造火箭嘛,篇幅所限这里就不贴出来了。

不过也别悲观,所有的题我都整顿成一本《2021 腾讯 Java 岗面试真题》PDF 了,前面也会继续收录最新面试题,间接点击就能够支付

除了腾讯之外其余大厂的真题我也在收集整理,都能够收费分享给大家,

须要的同学 关注公众号:北游学 Java,回复“面试”即可支付我整顿好的所有面试材料,还有海量的 Java 零碎学习材料哦!

退出移动版