2017年阿里内推一面面经(不断更新)

13,535 阅读10分钟

在3月1号投完简历,做好测评以后,我是一直等啊等,始终期待着一面的到来。

好不容易在3月8号这天中午12点10左右接到了来自阿里的面试电话。

刚开始,我是一脸的懵逼啊,面试官问我:“你是不是面过了???”我是一脸黑脸问号.jpg。Excuse me?在我一番解释后,终于进入了正题。


首先还是自我介绍。然后下面是问题清单:

1、平时在项目中主要负责哪块技术啊?(我回答数据库方面的代码)好,那么请问,你所知道的数据库方面所需要注意的地方有什么?怎么优化数据库?

引申出来以后,他又我问了我关于left join与right join的区别,(我回答了出来),然后,他又问我那inner join呢?(我当时是忘记了,一脸懵逼啊,绝望放弃回答)?用很多join好吗,有什么 缺点?(效率降低)

这里写图片描述
这里写图片描述

  • 关于索引:

    • 应该建索引的字段:
      1.经常作为查询条件的字段
      2.外键
      3.经常需要排序的字段
      4.分组排序的字段

    • 应该少建或者不建索引的字段有:
      1.表记录太少
      2.经常需要插入,删除,修改的表,
      3.表中数据重复且分布平均的字段


2、HTTP的特点,TCP/UDP特点以及区别?

1.支持客户/服务器模式。

2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。

3.灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。

4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。


3、HashMap、HashTable、ConCurrentHasgMap的区别以及实现原理?
ConCurrentHasgMap调用get()方法的时候有锁吗?

对于put和remove操作,是使用锁同步来进行的,不过是用的ReentrantLock而不是synchronized,性能上要更高一些。它们的实现前文都已经提到过,就没什么可分析的了。

友情链接:ConCurrentHasgMap源码分析

我们还需要知道一点,ConcurrentHashMap的迭代器不是Fast-Fail的方式,所以在迭代的过程中别其他线程添加/删除了元素,不会抛出异常,也不能体现出元素的改动。但也没有关系,因为每个entry的成员除了value都是final修饰的,暴漏出去也不会对其他元素造成影响。

  • 为什么hashmap扩容是是扩大成原来的2倍,而不是3倍?

友情链接:深入理解HashMap(及hash函数的真正巧妙之处)


4、怎么实现并发编程?请详细描述?

锁机制(Lock)、CAS无锁算法、Synchronized区别


5、类加载机制(如果自己写几个Jar包,应该放哪里?)


6、String、StringBuffer、StringBuilder的区别?

如果StringBuilder后增加一个字符串常量,并且这时候是多线程运行,那这时候StringBuilder是线程安全的吗?

字符串常量就是不能改变该对象,而后者是可是改变的字符串对象,他不像String一样,需要每次创建,后两者是在原有的字符串对象进行操作的。


7、JDK7、8的区别?

在JMM方面的区别:

永久代
在JDK8之前的HotSpot实现中,类的元数据如方法数据、方法信息(字节码,栈和变量大小)、运行时常量池、已确定的符号引用和虚方法表等被保存在永久代中,32位默认永久代的大小为64M,64位默认为85M,可以通过参数-XX:MaxPermSize进行设置,一旦类的元数据超过了永久代大小,就会抛出OOM异常。

虚拟机团队在JDK8的HotSpot中,把永久代从Java堆中移除了,并把类的元数据直接保存在本地内存区域(堆外内存),称之为元空间。

这样做有什么好处?
有经验的同学会发现,对永久代的调优过程非常困难,永久代的大小很难确定,其中涉及到太多因素,如类的总数、常量池大小和方法数量等,而且永久代的数据可能会随着每一次Full GC而发生移动。

而在JDK8中,类的元数据保存在本地内存中,元空间的最大可分配空间就是系统可用内存空间,可以避免永久代的内存溢出问题,不过需要监控内存的消耗情况,一旦发生内存泄漏,会占用大量的本地内存。

ps:JDK7之前的HotSpot,字符串常量池的字符串被存储在永久代中,因此可能导致一系列的性能问题和内存溢出错误。在JDK8中,字符串常量池中只保存字符串的引用。


8、JMM在初始化堆内存时,新生代与老年代的默认比例是多少?

永久代不属于堆内存,堆内存只包含新生代和老年代。

默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 ),即:新生代 ( Young ) = 1/3 的堆空间大小。
老年代 ( Old ) = 2/3 的堆空间大小。其中,新生代 ( Young ) 被细分为 Eden 和 两个 Survivor 区域,这两个 Survivor 区域分别被命名为 from 和 to,以示区分。
默认的,Edem : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定 ),即: Eden = 8/10 的新生代空间大小,from = to = 1/10 的新生代空间大小。
‍JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor 区域是空闲着的。
因此,新生代实际可用的内存空间为 9/10 ( 即90% )的新生代空间。

  • Java内存模型的描述?

9、Spring中控制反转定义?相比于创建对象的好处?AOP编程的优点?

友情链接:三大框架的原理及优缺点

原来我们的程序我们控制的是具体的实现,写程序直接写实现,现在我们控制的是它的接口它的抽象,原来我们依赖的是它的实现,现在我们依赖的是它的抽象。从具体的实现反转到抽象的概念上,我们针对的是接口编程。

1)降低组件之间的耦合度,实现软件各层之间的解耦。
Controller——>Service——>DAO
2)可以使用容器提供的众多服务,如:事务管理服务、消息服务等等。当我们使用容器管理事务时,开发人员就不再需要手工控制事务.也不需处理复杂的事务传播。
3)容器提供单例模式支持,开发人员不再需要自己编写实现代码。
4)容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能。
5)容器提供的众多辅作类,使用这些类能够加快应用的开发,如: JdbcTemplate、 HibernateTemplate。
6)Spring对于主流的应用框架提供了集成支持,如:集成Hibernate、JPA、Struts等,这样更便于应用的开发。
7) 使用spring容器可以提供的服务:事务管理服务,JMS服务,Spring Core核心服务,持久化服务等。
8)如果使用Spring, 我们就不再需要手工控制事务,例如在Hibernate中控制事务的语句 session.beginTransaction();session.getTransaction().commit();
9)使用Spring,不再需要我们处理复杂的事务传播行为。


10、SpringMVC中动态代理的实现机制,源码?

友情链接:Spring AOP动态代理原理与实现方式 (转)

友情链接:Java的动态代理机制和Spring的实现方式

友情链接:Java中动态代理实现机制


11、读过哪些源码,请详细描述一个你最熟悉的?(我回答ArrayList)

12、JVM虚拟机?请详细描述?

13、Java GC回收机制?请详细描述?

14、问了两道智力题!!!!!

(1)有8个产品,其中有一个次品(有可能偏重,有可能偏轻),那么如何用天平秤三次找出那个次品?

(2)忘记了。。。。关于买卖问题

15、看过GitHub上的开放源码吗(比如阿里,腾讯优秀团队的)?

16、使用过哪些代码管理工具?(Git,Maven)熟练使用吗?会不会使用GitHub上传代码?

17、使用过哪些写代码的工具?(Myeclipse和IDE),列出你常用的快捷键?

18、学习编程的方法、渠道?(看博客,网站)?上哪些网站?

19、说说自己的优缺点?学习时间的分配?

20、漏了一个问题,怎么实现让两个线程交替执行?(用代码实现?)

一般来说线程锁可以用:Synchronized、Lock。
这个题目的难点不在于同步块,而在于怎么样设计这个两个线程的交替实现。由于线程争用cpu的随机性,就需要A线,B线程执行,在B执行完一次进入等待之前唤醒A,如此往复,那么这里就要用上notify和wait了。

public class Thread1 {  
    public static void main(String args[]) {  
        final Bussiness business = new Bussiness();  
        Thread a=new Thread(new Runnable(){  
            @Override  
            public void run(){  
                business.SubThread();  
            }  
        });  
        Thread b=new Thread((new Runnable() {  
            @Override  
            public void run() {  
                business.MainThread();  
            }  
        }));  
        a.start();  
        b.start();  
    }  
}  



class Bussiness {  
    private static Object LOCK = new Object();  
    volatile boolean bShouldSub = true;//这里相当于定义了控制该谁执行的一个信号灯  

    public void MainThread() {  
        for (int i = 0; i < 50; i++) {  
            synchronized (LOCK) {//notify和wait的对象一定要和synchronized的对象保持一致  
                for (int j = 0; j < 10; j++) {  
                    System.out.println(Thread.currentThread().getName() + "+MainThread:i=" + i + ",j=" + j);  
                }  
                if (bShouldSub) {  
                    bShouldSub = false;  
                    LOCK.notify();  
                    if(i<49){  
                        try {  
                            LOCK.wait();  
                        }catch (InterruptedException e) {  
                            // TODO Auto-generatedcatch block  
                            e.printStackTrace();  
                        }  
                    }  
                }  
            }  
        }  
    }  


    public void SubThread() {  
        for (int i = 0; i < 50; i++) {  
            synchronized (LOCK){  
                for (int j = 0; j < 5; j++) {  
                    System.out.println(Thread.currentThread().getName() + "+SubThread:i=" + i + ",j=" + j);  
                }  
                if (!bShouldSub) {  
                    bShouldSub = true;  
                    LOCK.notify();  
                    if(i<49){  
                        try {  
                            LOCK.wait();  
                        } catch (InterruptedException e) {  
                            // TODO Auto-generatedcatch block  
                            e.printStackTrace();  
                        }  
                    }  

                }  
            }  
        }  
    }  

}

各种容器的初始化长度是多少?

使用ArrayList初始化时注意事项?(自动扩充机制方面,原理实现)?

好了,一面到此结束,历时一个半小时,泪崩,懵逼!(关键下午还有课!!!迟到了!!!)

总结一点,阅读源码很重要!(Spring+SpringMVC+Mybatis)


上面题目的部分答案,欢迎前往历年阿里面试题汇总(2017年不断更新中)各大公司Java后端开发面试题总结查阅



更多内容,可关注我的个人公众号