面试总结之-美团面试总结(一)

一面

1、自我介绍

2、项目介绍及其亮点

3、Java的8种数据类型有哪些?

答:int,short,long,float,double,byte,boolean,char;

3、问了Integer缓存数据的范围?

答:-128-127 Java 5 中引入的一个有助于节省内存、提高性能的特性

Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
int e = 127;
int f = 128;
System.out.println(a==b);// true
System.out.println(a==e);// true
System.out.println(a.equals(b));// true
System.out.println(c==d);// false
System.out.println(c==f);// true
System.out.println(c.equals(d));// true

4、紧接着问了(java里所有类的父类)Object类有哪些方法,详细解释一下这些方法。?

  • clone:复制一个新的对象;
  • getClass:返回实体的Class对象;
  • toString:实现对象的字符串形式;
  • finalize:垃圾回收前执行,通过该方法重置资源防止内存泄漏(不推荐重写);
  • equals:用来判断两个对象是否相等,重写之后需要重新hashCode方法;
  • hashCode:每个对象对应的JVM哈希码;
  • wait:当前线程失去资源操作权限并释放锁,进入等待序列;
  • notify:随机通知一个获取对象锁的线程获取操作权限;
  • notifyALL:通知所有获取对象锁的线程获取操作权限;

5、String A = "123"; String B = new String("123");,问我生成了几个String对象?

答:我说如果常量池中,原来没有“123”那么就是生成了2个对象,如果常量池中有“123”那么只要1个对象生成。

6、由于提到了wait,顺带问了wait和sleep有什么区别?

答:都是暂停对资源进行操作,但是wait 的话会释放对象锁从新进入等待序列,sleep 的话不会释放的对象锁。

7、由于还提及了hashcode,面试官接着问我,hashcode用在哪里?

答:这个我不假思索地说,hashmap和ConcurrentMap;

8、果不其然,面试官说,讲一讲hashmap?

答:hashmap我讲了hashmap的数据结构数组链表结构,讲了hashmap的put,get,扩容的底层原理,同时讲了hashmap在1.7与1.8中的区别,put中引入了红黑树,以及扩容的时候不同,这些就讲了挺长时间,最后我说了一句hashmap不是线程安全的。

9、这里提及了hashMap是非线程安全的,面试问我为啥不是线程安全的,举几个例子?

答:我说了,在扩容的时候hashmap会可能产生环,造成死循环;

hashmap在插入新的阶段的时候,多个线程同时插入,会把除了最后的那个线程的其它线程插入的结点丢失;

对于修改的时候,多个线程修改,对只保留最后的一个线程的修改结果;扩容的时候,会只保留最后一个线程的扩容后的那个数组;从扩容修改增加说了一遍;

11、让我说意思JVM的分为哪几块?

答:方法区,虚拟机栈,本地方法栈,堆,程序计数器,然后我就自己没等面试官问新的问题,继续接着说,方法区和堆是线程共享的,虚拟机栈本地方法栈和程序计数器是线程私有的,除了程序计数器不会发生内存溢出,其它都有可能发生内存溢出,并说了哪些会发生堆溢出哪些会发生栈溢出;这里就是大家要学会自己吧啦吧啦地说一堆,因为据我观察每个面试官面试每个是有一个固定时间的,超过这个时间段就结束了,所以只要面试官不打断你,你就一顿说;

12、由于提及到了内存溢出,面试官问我内存溢出和内存泄漏的区别?

答:内存泄露我说就是一块申请了一块内存以后,无法去释放掉这块内存,丢失了这段内存的引用;内存溢出就是申请的内存不够,撑不起我们需要的内存;

13、这里问完我就去问了数据库,4大特性是啥,举个例子?

答:原子性,我说就是一个事务要么全部完成,要么全部失败,要么做要么不做;一致性,比如a+b=100,一个事务改变了a比如增加了a的值,那么必须同时改变b,保证在事务结束以后a+b=100依然成立,这就是一致性;持久性,额就是修改完以后,在数据库中生效是永久的;隔离性,我就是说对于A对B进行转账,A没把这个交易完成的时候,B是不知道A要给他转钱。

14、数据的隔离级别有啥,每个隔离级别举个例子?

答:1.未提交读,事务中发生了修改,即使没有提交,其它事务也是可见的,举例子我就说对于一个数A原来50修改为100,但是我还没有提交修改,另一个事务看到这个修改,而这个时候原事务发生了回滚,这时候A还是50,但是另一个事务看到的A是100,这就是未提交读;2.提交读,就是说,对于一个事务从开始直到提交之前,所做的任何修改是其它事务不可见的,举例就是对于一个数A原来是50,然后提交修改成100,这个时候另一个事务在A提交修改之前,读取到了A是50,刚读取完,A就被修改成100了,这个时候另一个事务再进行读取发现A就突然变成100了;3.可重复读;可重复读,就是对于一个记录读取多次的记录是相同的,举例就是对于一个数A读取的话一直是A,前后两次读取到的A是一致的;可串行化读,就是说在并发情况下,和串行化的读取的结果是一致的,没有什么不同,这个举例我就说,不会发生脏读和幻读;然后数据库这一块就过去了。

15、接着问我计算机网络,问了我7层有哪7层?

答:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层;

16、接着问了我TCP在哪层,UDP在哪层,HTTP在哪层?

答:TPC和UDP在传输层,然后HTTP问我在哪个层,在应用层。

18、java的异常分类,哪些可以不捕获(error,RuntimeException,CheckedException)为什么,不捕获会出现什么问题?

所有异常的根是Throwable,分为Error(是虚拟机产生并抛出) 和 Exception, Exception又分为CheckedException 和 RuntimeException; CheckedException 可显示的预见可以try{}catch{}进行捕获处理

19、合并两个有序链表

public static TestNode mergeList(TestNode n1, TestNode n2){

    if (n1 == null ){return n2;}
    if (n2 == null ){return n1;}
    TestNode n = new TestNode(-1);
    TestNode end = n;

    while(n1 != null && n2 != null){

        if (n1.getData() > n2.getData()){

            end.setNext(n2);
            end = n2;
            n2 = n2.getNext();
         }else{
            end.setNext(n1);
            end = n1;
            n1 = n1.getNext();
        }
    }

    if (n1 == null){
       end.setNext(n2);
    }else{
        end.setNext(n1);
    }

    return n.getNext();
}

// 反转链表

public static TestNode reverseBetween(TestNode head, int m, int n) {

    TestNode temp = new TestNode(0);
    temp.setNext(head);
    TestNode pre = temp;
    for(int i = 1; i < m; i++){
        pre = pre.getNext();
    }

    head = pre.getNext();
    for(int i = m; i < n; i++){
        TestNode nex = head.getNext();
        head.setNext(nex.getNext());
        nex.setNext(pre.getNext());
        pre.setNext(nex);
    }
    return temp.getNext();
}

public static TestNode converseChain(TestNode node){

     if (null == node){

        return null;
    }
    TestNode preNode = node;
    TestNode currentNode = node.getNext();
    while (null != currentNode.getNext()){
        TestNode tempNode = currentNode.getNext();
        currentNode.setNext(preNode);
        preNode = currentNode;
        currentNode = tempNode;
    }
    currentNode.setNext(preNode);
    node.setNext(null);
    int length = getLength(currentNode);
    System.out.println("====="+length);
    return currentNode;
}



private static int getLength(TestNode node){

    if (null == node){
        return -1;
    }
    int len = 0;
    TestNode temp = node;
    while (null != temp.getNext()){
        temp = temp.getNext();
        len++;
    }
    return len;
}

//  股票最佳卖出

private static int getBest(int [] arr){

    if(arr.length <= 1)
        return 0;
    int min = arr[0], max = 0;
    for(int i = 1; i < arr.length; i++) {
        max = Math.max(max, arr[i] - min);
        min = Math.min(min, arr[i]);
    }
    return max;
}

20、求一个数的平方根(二分法和牛顿法)

21、你们的网站关于高并发做了哪些?

22、java抽象类和接口的区别

  • 1).抽象类可以有构造方法,接口中不能有构造方法。
  • 2).抽象类中可以有普通成员变量,接口中没有普通成员变量
  • 3).抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
  • 4).抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然
  • eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
  • 5).抽象类中可以包含静态方法,接口中不能包含静态方法
  • 6).抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
  • 7).一个类可以实现多个接口,但只能继承一个抽象类

23、Java IO相关

在Java IO中读取数据和写入数据是面向流(Stream)的,这表示当我们从流中读取数据,写入数据时也将其写入流,流的含义在于没有缓存 ,就好像我们站在流水线前,所有的数据沿着流水线依次到达我们的面前,我们只能读取当前的数据(相当于我们拥有一个数据流的切面)。如果需要获取某个数据的前一项或后一项数据那就必须自己缓存数据,而不能直接从流中获取(因为面向流就意味着我们只有一个数据流的切面)

而在Java NIO中数据的读写是面向缓冲区(Buffer)的,读取时可以将整块的数据读取到缓冲区中,在写入时则可以将整个缓冲区中的数据一起写入。这就好像是将流水线传输变成了卡车运送,面向流的数据读写只提供了一个数据流切面,而面向缓冲区的IO则使我们能够看到数据的上下文,也就是说在缓冲区中获取某项数据的前一项数据或者是后一项数据十分方便。这种便利是有代价的,因为我们必须管理好缓冲区,这包括不能让新的数据覆盖了缓冲区中还没有被处理的有用数据;将缓冲区中的数据正确的分块,分清哪些被处理过哪些还没有等等。

 

   

 

  • BIO(一个连接一个线程)方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
  • NIO(一个请求一个线程)方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
  • AIO(一个有效请求一个线程)方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
  • 同步阻塞IO:在此种方式下,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行。JAVA传统的IO模型属于此种方式!
  • 同步非阻塞IO:在此种方式下,用户进程发起一个IO操作以后边可返回做其它事情,但是用户进程需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费。其中目前JAVA的NIO就属于同步非阻塞IO。
  • 异步阻塞IO:此种方式下是指应用发起一个IO操作以后,不等待内核IO操作的完成,等内核完成IO操作以后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问IO是否完成,那么为什么说是阻塞的呢?因为此时是通过select系统调用来完成的,而select函数本身的实现方式是阻塞的,而采用select函数有个好处就是它可以同时监听多个文件句柄,从而提高系统的并发性!
  • 异步非阻塞IO:在此种模式下,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。目前Java中还没有支持此种IO模型。

24、TCP握手挥手

三次握手

 

  • ①TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态;
  • ②TCP客户进程也是先创建传输控制块TCB,然后向服务器发出连接请求报文,这是报文首部中的同部位SYN=1,同时选择一个初始序列号 seq=x ,此时,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号;
  • ③TCP服务器收到请求报文后,如果同意连接,则发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己初始化一个序列号 seq=y,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号;
  • ④TCP客户进程收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号;
  • ⑤当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就可以开始通信了;

客户端最后一次确认的目的:主要防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误。

四次挥手

 

  • ①客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
  • ②服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
  • ③客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
  • 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
  • ④客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
  • ⑤服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

为什么建立连接是三次握手,关闭连接确是四次挥手呢?

建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。

而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

 

如有披露或问题欢迎留言或者入群探讨

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值