特别声明:转载,文章出处:https://github.com/GavinHwa/alibaba

无意中在网上看到一篇关于阿里面试的文章,感觉不错,特转载。涉及很多java底层实现原理,jvm相关知识,就算不面试,对于深入理解java也是不错的选择。

答案持续更新中…

  1. HashMap和Hashtable的区别

  2. 实现一个保证迭代顺序的HashMap

  3. 说一说排序算法,稳定性,复杂度

  4. 说一说GC

  5. 可以保证的实习时长

  6. 职业规划

(1)自我介绍。

(2)JVM如何加载一个类的过程,双亲委派模型中有哪些方法?

(3)HashMap如何实现的?

(4)HashMap和Concurrent HashMap区别, Concurrent HashMap 线程安全吗, Concurrent HashMap如何保证 线程安全?

(5)HashMap和HashTable 区别,HashTable线程安全吗?

(6)进程间通信有哪几种方式?

(7)JVM分为哪些区,每一个区干吗的?

(8)JVM如何GC,新生代,老年代,持久代,都存储哪些东西?

(9)GC用的引用可达性分析算法中,哪些对象可作为GC Roots对象?

(10)快速排序,过程,复杂度?

(11)什么是二叉平衡树,如何插入节点,删除节点,说出关键步骤。

(12)TCP如何保证可靠传输?三次握手过程?

(13)TCP和UDP区别?

(14)滑动窗口算法?

(15)Linux下如何进行进程调度的?

(16)Linux下你常用的命令有哪些?

(17)操作系统什么情况下会死锁?

(18)常用的hash算法有哪些?

(19)什么是一致性哈希?

(20)如何理解分布式锁?

(21)数据库中的范式有哪些?

(22)数据库中的索引的结构?什么情况下适合建索引?

(23)Java中的NIO,BIO,AIO分别是什么?

(24)用什么工具调试程序?JConsole,用过吗?

(25)现在JVM中有一个线程挂起了,如何用工具查出原因?

(26)线程同步与阻塞的关系?同步一定阻塞吗?阻塞一定同步吗?

(27)同步和异步有什么区别?

(28)线程池用过吗?

(29)如何创建单例模式?说了双重检查,他说不是线程安全的。如何高效的创建一个线程安全的单例?

(30)concurrent包下面,都用过什么?

(31)常用的数据库有哪些?redis用过吗?

(32)了解hadoop吗?说说hadoop的组件有哪些?hdfs,hive,hbase,zookeeper。说下mapreduce编程模型。

(33)你知道的开源协议有哪些?

(34)你知道的开源软件有哪些?

(35)你最近在看的书有哪些?

(36)你有什么问题要问我吗?

(37)了解哪些设计模式?说说都用过哪些设计模式

(38)如何判断一个单链表是否有环?

(39)操作系统如何进行分页调度?

(40)匿名内部类是什么?如何访问在其外面定义的变量?

1)自我介绍,做过什么项目。

(2)java虚拟机的区域如何划分,每一个区的动能,这一块自由发挥。

(3)双亲委派模型中,从顶层到底层,都是哪些类加载器,分别加载哪些类?

(4)有没有可能父类加载器和子类加载器,加载同一个类?如果加载同一个类,该使用哪一个类?

(5)HashMap的结构,get(),put()是如何实现的?HashMap有哪些问题?

(6)ConcurrentHashMap的get(),put(),又是如何实现的?ConcurrentHashMap有哪些问题? ConcurrentHashMap的锁是读锁还是写锁?

(7) HashMap与HashTable的区别

(8)sleep()和wait()分别是哪个类的方法,有什么区别?synchronized底层如何实现的?用在代码块和方法上有什么区别?

(9)什么是线程池?如果让你设计一个动态大小的线程池,如何设计,应该有哪些方法?

(10)什么是死锁?JVM线程死锁,你该如何判断是因为什么?如果用VisualVM,dump线程信息出来,会有哪些信息?这一块问的很多….问的我懵了. 因为并没有实际操作过 = =

(11)查看jvm虚拟机里面堆、线程的信息,你用过什么命令?我只用过图形界面VisualVM。。。

(12)垃圾回收算法有哪些?CMS知道吗?如何工作的?

(13)数据库中什么是事务?事务的隔离级别?事务的四个特性?什么是脏读,幻读,不可重复读?

(14)数据库索引的结构有哪些?我说B树和B+树,他说只有这两个吗。我又说全文倒排索引。然后介绍B+树的结构。

(15)数据库中的分页查询语句怎么写?

(16)什么是一致性哈希?用来解决什么问题?

(17)Redis的存储结构,或者说如何工作的,与mysql的区别?有哪些数据类型?

(18)项目中用到redis,为什么选用redis,了解其他NoSQL数据库吗?在你的项目中是如何运用redis的?key是什么,value是什么?

(19)归并排序的过程?时间复杂度?空间复杂度?

(20)你平常用什么排序?快速排序。说说在那些场景下适用,哪些场景下不适用。

(21)你在项目中做什么?因为我用到Solr,他就问我Solr是如何工作的?

四. 集合框架,list,map,set都有哪些具体的实现类,区别都是什么?

1.List,Set都是继承自 Collection 接口,Map 则不是;

2.List特点:元素有放入顺序,元素可重复;

Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉,(注 意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的 HashCode决定的,其位置其实是固定的,加入Set 的Object必须定 义equals()方法;

另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是 set只能用迭代,因为他无序,无法用下标来取得想要的值)。

3.Set和List对比:

Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元 素位置改变。

List:和数组类似,List可以动态增长,查找元素效率高,插入删除元 素效率低,因为会引起其他元素位置改变。

4.Map适合储存键值对的数据。

5.线程安全集合类与非线程安全集合类

LinkedList、ArrayList、HashSet是非线程安全的,Vector是线程安全的;

HashMap是非线程安全的,HashTable是线程安全的;

StringBuilder是非线程安全的,StringBuffer是线程安全的。

下面是这些类具体的使用介绍:

ArrayList与LinkedList的区别和适用场景

Arraylist:

优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。

缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。

LinkedList:

优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景。

缺点:因为LinkedList要移动指针,所以查询操作性能比较低。

适用场景分析:

当需要对数据进行对此访问的情况下选用 ArrayList,当需要对数据进行多次增加删除修改时采用 LinkedList。

ArrayList 与 Vector 的区别和适用场景

ArrayList有三个构造方法:

1
2
3
public ArrayList(int initialCapacity)//构造一个具有指定初始容量的空列表。
public ArrayList()//构造一个初始容量为10的空列表。
public ArrayList(Collection<? extends E> c)//构造一个包含指定 collection 的元素的列表

Vector有四个构造方法:

1
2
3
4
public Vector()//使用指定的初始容量和等于零的容量增量构造一个空向量。
public Vector(int initialCapacity)//构造一个空向量,使其内部数据数组的大小,其标准容量增量为零。
public Vector(Collection<? extends E> c)//构造一个包含指定 collection 中的元素的向量
public Vector(int initialCapacity,int capacityIncrement)//使用指定的初始容量和容量增量构造一个空的向量

ArrayList 和 Vector 都是用数组实现的,主要有这么三个区别:

1).Vector是多线程安全的,线程安全就是说多线程访问同一代码,不会产生不确定的结果。而ArrayList不是,这个可以从源码中看出,Vector类中的方法很多有synchronized进行修饰,这样就导致了Vector在效率上无法与ArrayList相比;

2).两个都是采用的线性连续空间存储元素,但是当空间不足的时候,两个类的增加方式是不同。

3).Vector可以设置增长因子,而ArrayList不可以。

4).Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。

适用场景:

1.Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。

2.如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。

HashSet与Treeset的适用场景

1.TreeSet 是二叉树(红黑树的树据结构)实现的,Treeset中的数据是自动排好序的,不允许放入null值。

2.HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束。

3.HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例。

适用场景分析:

HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。为快速查找而设计的Set,我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。

HashMap与TreeMap、HashTable的区别及适用场景

HashMap 非线程安全

HashMap:基于哈希表(散列表)实现。使用 HashMap 要求添加的键类明确定义了 hashCode() 和 equals()[可以重写 hashCode() 和equals()],为了优化 HashMap 空间的使用,您可以调优初始容量和负载因子。其中散列表的冲突处理主要分两种,一种是开放定址法,另一种是链表法。HashMap 的实现中采用的是链表法。

TreeMap:非线程安全基于红黑树实现。TreeMap 没有调优选项,因为该树总处于平衡状态。

适用场景分析:

HashMap和HashTable:HashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKey()方法。HashTable同步的,而HashMap是非同步的,效率上比HashTable要高。HashMap允许空键值,而HashTable不允许。

HashMap:适用于Map中插入、删除和定位元素。

Treemap:适用于按自然顺序或自定义顺序遍历键(key)。

(ps:其实我们工作的过程中对集合的使用是很频繁的,稍加注意并总结积累一下,在面试的时候应该会回答的很轻松)

五. concurrentHashmap原理,原子类。

ConcurrentHashMap 作为一种线程安全且高效的哈希表的解决方案,尤其其中的”分段锁”的方案,相比 HashTable 的全表锁在性能上的提升非常之大.

六. volatile原理

在《Java并发编程:核心理论》一文中,我们已经提到过可见性、有序性及原子性问题,通常情况下我们可以通过Synchronized关键字来解决这些个问题,不过如果对Synchronized原理有了解的话,应该知道Synchronized是一个比较重量级的操作,对系统的性能有比较大的影响,所以,如果有其他解决方案,我们通常都避免使用Synchronized来解决问题。而volatile关键字就是Java中提供的另一种解决可见性和有序性问题的方案。对于原子性,需要强调一点,也是大家容易误解的一点:对volatile变量的单次读/写操作可以保证原子性的,如long和double类型变量,但是并不能保证i++这种操作的原子性,因为本质上i++是读、写两次操作。

参考文章

https://link.jianshu.com/?t=https://www.cnblogs.com/paddix/p/5428507.html

七. 多线程的使用场景

使用多线程就一定效率高吗? 有时候使用多线程并不是为了提高效率,而是使得CPU能够同时处理多个事件。

1).为了不阻塞主线程,启动其他线程来做好事的事情,比如APP中耗时操作都不在UI中做.

2).实现更快的应用程序,即主线程专门监听用户请求,子线程用来处理用户请求,以获得大的吞吐量.感觉这种情况下,多线程的效率未必高。 这种情况下的多线程是为了不必等待, 可以并行处理多条数据。

比如JavaWeb的就是主线程专门监听用户的HTTP请求,然后启动子线程去处理用户的HTTP请求。

3).某种虽然优先级很低的服务,但是却要不定时去做。

比如Jvm的垃圾回收。

4.)某种任务,虽然耗时,但是不耗CPU的操作时,开启多个线程,效率会有显著提高。

比如读取文件,然后处理。 磁盘IO是个很耗费时间,但是不耗CPU计算的工作。 所以可以一个线程读取数据,一个线程处理数据。肯定比一个线程读取数据,然后处理效率高。 因为两个线程的时候充分利用了CPU等待磁盘IO的空闲时间。

八. JAVA常量池

Interger 中的128(-128~127)

a.当数值范围为-128~127时:如果两个 new 出来 Integer 对象,即使值相同,通过“==”比较结果为false,但两个对象直接赋值,则通过“==”比较结果为“true,这一点与String非常相似。

b.当数值不在-128~127时,无论通过哪种方式,即使两个对象的值相等,通过“==”比较,其结果为false;

c.当一个Integer对象直接与一个int基本数据类型通过“==”比较,其结果与第一点相同;

d.Integer对象的hash值为数值本身;

为什么是-128-127?

在 Integer 类中有一个静态内部类 IntegerCache,在 IntegerCache类中有一个 Integer 数组,用以缓存当数值范围为-128~127时的Integer 对象。

九. 简单介绍一下java中的泛型,泛型擦除以及相关的概念。

泛型是 Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。

在 Java SE 1.5 之前,没有泛型的情况的下,通过对类型 Object 的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。

泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。

2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。

3、泛型的类型参数可以有多个。

4、泛型的参数类型可以使用extends语句,例如。习惯上称为“有界类型”。

5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName(“java.lang.String”);

泛型擦除以及相关的概念

Java 中的泛型基本上都是在编译器这个层次来实现的。在生成的 Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。

类型擦除引起的问题及解决方法

1、先检查,在编译,以及检查编译的对象和引用传递的问题

2、自动类型转换

3、类型擦除与多态的冲突和解决方法

4、泛型类型变量不能是基本数据类型

5、运行时类型查询

6、异常中使用泛型的问题

7、数组(这个不属于类型擦除引起的问题)

9、类型擦除后的冲突

10、泛型在静态方法和静态类中的问题