互联网面试总结(二) : 概述题
概述题本人对网上的一些面试题做了一些整理,希望对大家面试有帮助JAVA 基础1.如何在JVM虚拟机挂掉的时候,做一些操作,例如发邮件通知?个人总结可以使用Runtime里面的addShutdownHook(Thread hook)方法,把JVM挂掉的时候所需要启动的线程注册到runtime中,就可以帮你完成这个动作2.HashSet 和HashMap的关系(深入源码
·
概述题
本人对网上的一些面试题做了一些整理,希望对大家面试有帮助
JAVA 基础
1.如何在JVM虚拟机挂掉的时候,做一些操作,例如发邮件通知?个人总结
可以使用Runtime里面的addShutdownHook(Thread hook)方法,把JVM挂掉的时候所需要启动的线程注册到runtime中,就可以帮你完成这个动作
2.HashSet 和HashMap的关系(深入源码) 个人总结
通过以下HashSet源码可以得知,HashSet 内部其实就是一个HashMap,但HashSet只是用到HashMap的key,而没有用倒HashMap的value
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
3.String类为什么是final的。
String是所有语言中最常用的一个类。我们知道在Java中,String是不可变的、final的。Java在运行时也保存了一个字符串池(String pool),这使得String成为了一个特别的类。
String类不可变性的好处
只有当字符串是不可变的,字符串池才有可能实现。字符串池的实现可以在运行时节约很多heap空间,因为不同的字符串变量都指向池中的同一个字符串。但如果字符串是可变的,那么String interning将不能实现(译者注:String interning是指对不同的字符串仅仅只保存一个,即不会保存多个相同的字符串。),因为这样的话,如果变量改变了它的值,那么其它指向这个值的变量的值也会一起改变。
如果字符串是可变的,那么会引起很严重的安全问题。譬如,数据库的用户名、密码都是以字符串的形式传入来获得数据库的连接,或者在socket编程中,主机名和端口都是以字符串的形式传入。因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变字符串指向的对象的值,造成安全漏洞。
因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。
类加载器要用到字符串,不可变性提供了安全性,以便正确的类被加载。譬如你想加载java.sql.Connection类,而这个值被改成了myhacked.Connection,那么会对你的数据库造成不可知的破坏。
因为字符串是不可变的,所以在它创建的时候hashcode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。
4.HashMap的源码,实现原理,底层结构
参考:http://blog.csdn.net/vking_wang/article/details/14166593
http://zhangshixi.iteye.com/blog/672697?page=2#comments
5.反射中,Class.forName和classloader的区别
转自:http://www.linuxidc.com/Linux/2014-01/94895.htm
Java中class.forName和classLoader都可用来对类进行加载。前者除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。而classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。Class.forName(name, initialize, loader)带参函数也可控制是否加载static块。并且只有调用了newInstance()方法采用调用构造函数,创建类的对象 示例代码如下:
package com.blueray.java.test;
public class ClassLoaderTest {
/**
* @param args
*/
public static void main(String[] args) {
ClassLoader classLoader=StaticSample.class.getClassLoader();
try {
System.out.println("Before load class");
Class clazz=classLoader.loadClass(StaticSample.class.getName());
System.out.println("After load class.");
System.out.println("executing newInstance");
clazz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
StaticSample:
package com.blueray.java.test;
public class StaticSample {
static{
System.out.println(StaticSample.class.getName()+" is loading the static block");
}
public StaticSample(){
System.out.println("StaticSample Constructor is executing.");
}
}
运行结果如下:
Before load class
After load class.
executing newInstance
com.blueray.java.test.StaticSample is loading the static block
StaticSample Constructor is executing.
6.说说你知道的几个Java集合类:list、set、queue、map实现类
参考:http://www.cnblogs.com/LittleHann/p/3690187.html?utm_source=tuicool&utm_medium=referral
7.描述一下ArrayList和LinkedList各自实现和区别
转自:http://www.importnew.com/6629.html
LinkedeList和ArrayList都实现了List接口,但是它们的工作原理却不一样。它们之间最主要的区别在于ArrayList是可改变大小的数组,而LinkedList是双向链接串列(doubly LinkedList)。ArrayList更受欢迎,很多场景下ArrayList比LinkedList更为适用。这篇文章中我们将会看看LinkedeList和ArrayList的不同,而且我们试图来看看什么场景下更适宜使用LinkedList,而不用ArrayList。
LinkedList和ArrayList的区别
LinkedList和ArrayList的差别主要来自于Array和LinkedList数据结构的不同。如果你很熟悉Array和LinkedList,你很容易得出下面的结论:
1) 因为Array是基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的。Array获取数据的时间复杂度是O(1),但是要删除数据却是开销很大的,因为这需要重排数组中的所有数据。
2) 相对于ArrayList,LinkedList插入是更快的。因为LinkedList不像ArrayList一样,不需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重新装入一个新的数组,这是ArrayList最坏的一种情况,时间复杂度是O(n),而LinkedList中插入或删除的时间复杂度仅为O(1)。ArrayList在插入数据时还需要更新索引(除了插入数组的尾部)。
3) 类似于插入数据,删除数据时,LinkedList也优于ArrayList。
4) LinkedList需要更多的内存,因为ArrayList的每个索引的位置是实际的数据,而LinkedList中的每个节点中存储的是实际的数据和前后节点的位置。
什么场景下更适宜使用LinkedList,而不用ArrayList
我前面已经提到,很多场景下ArrayList更受欢迎,但是还有些情况下LinkedList更为合适。譬如:
1) 你的应用不会随机访问数据。因为如果你需要LinkedList中的第n个元素的时候,你需要从第一个元素顺序数到第n个数据,然后读取数据。
2) 你的应用更多的插入和删除元素,更少的读取数据。因为插入和删除元素不涉及重排数据,所以它要比ArrayList要快。
以上就是关于ArrayList和LinkedList的差别。你需要一个不同步的基于索引的数据访问时,请尽量使用ArrayList。ArrayList很快,也很容易使用。但是要记得要给定一个合适的初始大小,尽可能的减少更改数组的大小。
8.Java中的队列都有哪些,有什么区别
转自:http://blog.itpub.net/143526/viewspace-1060365/
9.Java7、Java8的新特性
转自:http://blog.csdn.net/zhongweijian/article/details/9258997
10.Java数组和链表两种结构的操作效率,在哪些情况下(从开头开始,从结尾开始,从中间开始),哪些操作(插入,查找,删除)的效率高
参考:http://blog.csdn.net/a19881029/article/details/22695289
11.Java内存泄露的问题调查定位:jmap,jstack的使用等等
参考:http://blog.csdn.net/gzh0222/article/details/8538727
12.string、stringbuilder、stringbuffer区别
参考:http://www.cnblogs.com/xudong-bupt/p/3961159.html
13.hashtable和hashmap的区别
参考:http://www.cnblogs.com/carbs/archive/2012/07/04/2576995.html
14.异常的结构,运行时异常和非运行时异常,各举个例子
参考:http://www.tuicool.com/articles/YVZBNfN
15.String 类的常用方法
转自:http://www.pc6.com/java/j_50343.html
16.Java 的引用类型有哪几种
参考:http://blog.csdn.net/coding_or_coded/article/details/6603549
17.抽象类和接口的区别
参考:http://www.importnew.com/12399.html
18.java的基础类型和字节大小
参考:http://www.cnblogs.com/doit8791/archive/2012/05/25/2517448.html
Java基本类型共有八种,基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double。数值类型又可以分为整数类型byte、short、int、long和浮点数类型float、double。JAVA中的数值类型不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。实际上,JAVA中还存在另外一种基本类型void,它也有对应的包装类 java.lang.Void,不过我们无法直接对它们进行操作。8 中类型表示范围如下:
byte:8位,最大存储数据量是255,存放的数据范围是-128~127之间。
short:16位,最大数据存储量是65536,数据范围是-32768~32767之间。
int:32位,最大数据存储容量是2的32次方减1,数据范围是负的2的31次方到正的2的31次方减1。
long:64位,最大数据存储容量是2的64次方减1,数据范围为负的2的63次方到正的2的63次方减1。
float:32位,数据范围在3.4e-45~1.4e38,直接赋值时必须在数字后加上f或F。
double:64位,数据范围在4.9e-324~1.8e308,赋值时可以加d或D也可以不加。
boolean:只有true和false两个取值。
char:16位,存储Unicode码,用单引号赋值。
19.Hashtable,HashMap,ConcurrentHashMap底层实现原理与线程安全问题
参考:http://blog.csdn.net/xuefeng0707/article/details/40834595
20.如果不让你用Java Jdk提供的工具,你自己实现一个Map,你怎么做。
http://www.cnblogs.com/xwdreamer/archive/2012/05/14/2499339.html
21.Hash冲突怎么办?哪些解决散列冲突的方法?
参考:http://xiaolu123456.iteye.com/blog/1485349
22.HashMap冲突很厉害,最差性能,你会怎么解决?从O(n)提升到log(n)
参考:http://www.2cto.com/kf/201505/399352.html
理解了hashmap的实现,聪明的人肯定已经知道怎么更加高性能的使用hashmap。不过在此之前还是先说明下初始容量和负载因子的含义。
Hashmap的设想是在O(1)的时间复杂度存取数据,根据我们的分析,在最坏情况下,时间复杂度很可能是o(n),但这肯定极少出现。但是某个链表中存在多个元素还是有相当大的可能的。当hashmap中的元素数量越接近数组长度,这个几率就越大。为了保证hashmap的性能,我们对元素数量/数组长度的值做了上限,此值就是负载因子。当比值大于负载因子时,就需要对内置数组进行扩容,从而提高读写性能。但这也正是问题的所在,对数组扩容,代价较大,时间复杂度时O(n)。
故我们在hashmap需要存放的元素数量可以预估的情况下,预先设定一个初始容量,来避免自动扩容的操作来提高性能。
23.什么时候ReHash
参考:http://www.tuicool.com/articles/qqyENz
24.hashCode() 与 equals() 生成算法、方法怎么重写
参考:http://blog.csdn.net/jiangwei0910410003/article/details/22739953
框架
1.hibernate和ibatis的区别
转自:http://blog.csdn.net/cdh1213/article/details/5967405
hibernate与ibatis比较
hibernate 是当前最流行的o/r mapping框架,它出身于sf.net,现在已经成为jboss的一部分了。
ibatis 是另外一种优秀的o/r mapping框架,目前属于apache的一个子项目了。
相对hibernate“o/r”而言,ibatis是一种“sql mapping”的orm实现。
hibernate对数据库结构提供了较为完整的封装,hibernate的o/r mapping实现了pojo 和数据库表之间的映射,以及sql 的自动生成和执行。程序员往往只需定义好了pojo 到数据库表的映射关系,即可通过hibernate 提供的方法完成持久层操作。程序员甚至不需要对sql 的熟练掌握, hibernate/ojb 会根据制定的存储逻辑,自动生成对应的sql 并调用jdbc 接口加以执行。
而ibatis 的着力点,则在于pojo 与sql之间的映射关系。也就是说,ibatis并不会为程序员在运行期自动生成sql 执行。具体的sql 需要程序员编写,然后通过映射配置文件,将sql所需的参数,以及返回的结果字段映射到指定pojo。
使用ibatis 提供的orm机制,对业务逻辑实现人员而言,面对的是纯粹的java对象。
这一层与通过hibernate 实现orm 而言基本一致,而对于具体的数据操作,hibernate会自动生成sql 语句,而ibatis 则要求开发者编写具体的sql 语句。相对hibernate而言,ibatis 以sql开发的工作量和数据库移植性上的让步,为系统设计提供了更大的自由空间。
hibernate与ibatis的对比:
1.ibatis非常简单易学,hibernate相对较复杂,门槛较高。
2.二者都是比较优秀的开源产品
3.当系统属于二次开发,无法对数据库结构做到控制和修改,那ibatis的灵活性将比hibernate更适合
4.系统数据处理量巨大,性能要求极为苛刻,这往往意味着我们必须通过经过高度优化的sql语句(或存储过程)才能达到系统性能设计指标。在这种情况下ibatis会有更好的可控性和表现。
5.ibatis需要手写sql语句,也可以生成一部分,hibernate则基本上可以自动生成,偶尔会写一些hql。同样的需求,ibatis的工作量比hibernate要大很多。类似的,如果涉及到数据库字段的修改,hibernate修改的地方很少,而ibatis要把那些sql mapping的地方一一修改。
6.以数据库字段一一对应映射得到的po和hibernte这种对象化映射得到的po是截然不同的,本质区别在于这种po是扁平化的,不像hibernate映射的po是可以表达立体的对象继承,聚合等等关系的,这将会直接影响到你的整个软件系统的设计思路。
7.hibernate现在已经是主流o/r mapping框架,从文档的丰富性,产品的完善性,版本的开发速度都要强于ibatis。
2.讲讲mybatis的连接池
参考:http://www.tuicool.com/articles/RvqEjeR
3.spring框架中需要引用哪些jar包,以及这些jar包的用途
参考:http://www.cnblogs.com/BensonHe/p/3903050.html
4.springMVC的原理
参考:http://blog.sina.com.cn/s/blog_7ef0a3fb0101po57.html
5.springMVC注解的意思
参考:http://aijuans.iteye.com/blog/2160141
6. spring中beanFactory和ApplicationContext的联系和区别
作用:
1. BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期。
2. ApplicationContext除了提供上述BeanFactory所能提供的功能之外,还提供了更完整的框架功能:
a. 国际化支持
b. 资源访问:Resource rs = ctx. getResource(“classpath:config.properties”), “file:c:/config.properties”
c. 事件传递:通过实现ApplicationContextAware接口
3. 常用的获取ApplicationContext的方法:
FileSystemXmlApplicationContext:从文件系统或者url指定的xml配置文件创建,参数为配置文件名或文件名数组
ClassPathXmlApplicationContext:从classpath的xml配置文件创建,可以从jar包中读取配置文件
WebApplicationContextUtils:从web应用的根目录读取配置文件,需要先在web.xml中配置,可以配置监听器或者servlet来实现
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
这两种方式都默认配置文件为web-inf/applicationContext.xml,也可使用context-param指定配置文件
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/myApplicationContext.xml</param-value>
</context-param>
7.spring注入的几种方式
参考:http://developer.51cto.com/art/201207/348019.htm
8.spring如何实现事物管理的
参考:http://michael-softtech.iteye.com/blog/813835
9.springIOC
参考:http://blog.csdn.net/it_man/article/details/4402245
10.hibernate中的1级和2级缓存的使用方式以及区别原理(Lazy-Load的理解)
参考:http://www.jb51.net/article/75161.htm
11.Hibernate的原理体系架构,五大核心接口,Hibernate对象的三种状态转换,事务管理
参考:http://www.cnblogs.com/shysunlove/archive/2012/11/21/2780240.html
多线程
1.Java创建线程之后,直接调用start()方法和run()的区别
参考:http://www.tuicool.com/articles/7nyEziU
2.常用的线程池模式以及不同线程池的使用场景
参考:http://www.cnblogs.com/dolphin0520/p/3932921.html
3.newFixedThreadPool此种线程池如果线程数达到最大值后会怎么办,底层原理
参考:http://www.oschina.net/question/565065_86540
4.多线程之间通信的同步问题,synchronized锁的是对象,衍伸出和synchronized相关很多的具体问题,例如同一个类不同方法都有synchronized锁,一个对象是否可以同时访问。或者一个类的static构造方法加上synchronized之后的锁的影响。
参考:http://www.cnblogs.com/shipengzhi/articles/2223100.html
5.了解可重入锁的含义,以及ReentrantLock 和synchronized的区别
http://outofmemory.cn/java/java.util.concurrent/synchronized-locks-Lock-ReentrantLock
6.同步的数据结构,例如concurrentHashMap的源码理解以及内部实现原理,为什么他是同步的且效率高
参考:http://www.cnblogs.com/ITtangtang/p/3948786.html
7.atomicinteger和Volatile等线程安全操作的关键字的理解和使用
参考:http://www.cnblogs.com/dolphin0520/p/3920373.html
8.线程间通信,wait和notify
参考:http://www.jb51.net/article/40746.htm
9.定时线程的使用
参考:http://www.2cto.com/kf/201502/376021.html
10.场景:在一个主线程中,要求有大量(很多很多)子线程执行完之后,主线程才执行完成。多种方式,考虑效率
参考:http://www.tuicool.com/articles/ZvAFny
11.进程和线程的区别
参考:http://www.cnblogs.com/way_testlife/archive/2011/04/16/2018312.html
12.什么叫线程安全
线程安全:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题
13.线程的几种状态
参考:http://lavasoft.blog.51cto.com/62575/99153/
14.并发、同步的接口或方法
转自:http://blog.csdn.net/woshisap/article/details/43119569
1:线程池
与每次需要时都创建线程相比,线程池可以降低创建线程的开销,这也是因为线程池在线程执行结束后进行的是回收操作,而不是真正的
销毁线程。
2:ReentrantLock
ReentrantLock提供了tryLock方法,tryLock调用的时候,如果锁被其他线程持有,那么tryLock会立即返回,返回结果为false,如果锁没有被
其他线程持有,那么当前调用线程会持有锁,并且tryLock返回的结果是true,
lock.lock();
try {
//do something
} finally {
lock.unlock();
}
3:volatile
保证了同一个变量在多线程中的可见性,所以它更多是用于修饰作为开关状态的变量,因为volatile保证了只有一份主存中的数据。
4:Atomics
public class Count {
private AtomicInteger counter = new AtomicInteger();
public int increase() {
return counter.incrementAndGet();
}
public int decrease() {
return counter.decrementAndGet();
}
}
AtomicInteger内部通过JNI的方式使用了硬件支持的CAS指令。
5:CountDownLatch
它是java.util.concurrent包中的一个类,它主要提供的机制是当多个(具体数量等于初始化CountDown时的count参数的值)线程都到达了预期状态
或完成预期工作时触发事件,其他线程可以等待这个事件来出发自己后续的工作,等待的线程可以是多个,即CountDownLatch是可以唤醒多个等待
的线程的,到达自己预期状态的线程会调用CountDownLatch的countDown方法,而等待的线程会调用CountDownLatch的await方法
6:CyclicBarrier
循环屏障,CyclicBarrier可以协同多个线程,让多个线程在这个屏障前等待,直到所有线程都到达了这个屏障时,再一起继续执行后面的动作。
CyclicBarrier和CountDownLatch都是用于多个线程间的协调的,二者的一个很大的差别是,CountDownLatch是在多个线程都进行了latch.countDown
后才会触发事件,唤醒await在latch上的线程,而执行countDown的线程,执行完countDown后,会继续自己线程的工作;
CyclicBarrier是一个栅栏,用于同步所有调用await方法的线程,并且等所有线程都到了await方法,这些线程才一起返回继续各自的工作,因为使用CyclicBarrier的线程都会阻塞在await方法上,所以在线程池中使用CyclicBarrier时要特别小心,如果线程池的线程 数过少,那么就会发生死锁了,
CyclicBarrier可以循环使用,CountDownLatch不能循环使用。
7:Semaphore
是用于管理信号量的,构造的时候传入可供管理的信号量的数值,信号量对量管理的信号就像令牌,构造时传入个数,总数就是控制并发的数量。
semaphore.acquire();
try {
//调用远程通信的方法
} finally () {
semaphore.release();
}
8:Exchanger
Exchanger,从名字上讲就是交换,它用于在两个线程之间进行数据交换,线程会阻塞在Exchanger的exchange方法上,直到另一个线程也到了
同一个Exchanger的exchange方法时,二者进行交换,然后两个线程会继续执行自身相关的代码。
9:Future和FutureTask
Future<HashMap> future = getDataFromRemote2();
//do something
HashMap data = (HashMap)future.get();
private Future<HashMap> getDateFromRemote2() {
return threadPool.submit(new Callable<HashMap>() {
public HashMap call() {
return getDataFromRemote();
}
});
}
思路:调用函数后马上返回,然后继续向下执行,急需要数据时再来用,或者说再来等待这个数据,具体实现方式有两种,一个是用Future,另一个
使用回调。
15.HashMap 是否线程安全,为何不安全。 ConcurrentHashMap,线程安全,为何安全。底层实现是怎么样的。
参考:http://blog.csdn.net/xuefeng0707/article/details/40834595
16.J.U.C下的常见类的使用。 ThreadPool的深入考察; BlockingQueue的使用。(take,poll的区别,put,offer的区别);原子类的实现
http://ifeve.com/j-u-c-framework/
参考:http://wsmajunfeng.iteye.com/blog/1629354
17.简单介绍下多线程的情况,从建立一个线程开始。然后怎么控制同步过程,多线程常用的方法和结构
参考:http://www.jb51.net/article/36553.htm
18.volatile的理解
参考:http://www.infoq.com/cn/articles/java-memory-model-4/
19.实现多线程有几种方式,多线程同步怎么做,说说几个线程里常用的方法
参考:http://www.jb51.net/article/43417.htm
http://www.cnblogs.com/psjay/archive/2010/04/01/1702465.html
http://blog.csdn.net/you_off3/article/details/7572704
20.进程间的通讯
网络通信
1. http是无状态通信,http的请求方式有哪些,可以自己定义新的请求方式么
参考:http://www.cnblogs.com/yin-jingyu/archive/2011/08/01/2123548.html
2. socket通信,以及长连接,分包,连接异常断开的处理
参考:http://developer.51cto.com/art/201202/318163.htm
更多推荐
已为社区贡献2条内容
所有评论(0)