Java 技术面试题及答案
一、算法题
1、判断一个数是否为2的N次幂
答:设这个数为n,然后用这个数的二进制和(n-1)的二进制做求与运算,如果所得的结果为0,那么即为二进制数。例如:10000000 与 01111111 ,两者取与计算为0
2、给定一个数组A(1-100)判断A里面是否有重复元素
答:定义一个hashmap集合,key存放A中的元素值,value存放该元素值出现的次数,假如用count表示,如果count>=2,说明有重复元素。
3、给定一个字符串ab_cd_e,要求字母放前面,下划线放后面。
答:
A、把字符串转换为字符数组(toCharArray)
B、定义一个StringBuilder,用来存放排序后字符
C、遍历字符数组,判断如果'a'<Char[i]<'z',就添加到sb中
D、再接着继续遍历字符数组,如果为空,退出;不为空,将元素添加到Sb中
E、将sb转化为字符串(toString())
4、判断一个链表是否是一个环
答:定义两个指针:
一个快指针(fast),假如每次移动两步;
一个慢指针(slow),假如每次移动一步。
判断两个指针能否相遇,如果能,则是一个环。
如果不能,快指针一定先指向NULL,则不成环。
class X { Boolean isExitsLoop(list head) { list slow=head; list fast=head; while((fast && fast.head) != null) { slow=slow.next; fast=fast.next.next; if(slow==fast){ break; } } return !(fast==null || fast.next==null); } }
二、Java 基础题
1、HashMap与TreeMap的区别
答:
相同点:两者都是线程不安全的,都继承自AbstractMap
不同点:HashMap基于哈希表实现,使用HashMap要求添加的键明确定义hashcode()和equals()方法,适用于在Map中增删查元素,速度通常比TreeMAp要快一点,遍历结果是没有排序的。
TreeMap基于红黑树实现,适用于按自然顺序或自定义顺序遍历键(key),实现SortedMap接口,遍历得到的结果(键)是排过序的。
2、static成员是否能访问非静态成员
答:静态成员属于类,不需要生成对象就存在了,
而非静态需要生成对象才产生,
所以,静态成员(属于类)不能直接访问非静态成员(属于对象)
3、TCP 与 UDP的区别
答:
A、TCP(传输控制协议),是面向连接的协议;UDP(用户数据报协议),是不面向连接的;
B、对系统资源的要求,TCP较多,UDP较少
C、TCP需要经过三次对话建立连接,UDP程序设计结构较为简单
D、TCP是流模式,UDP是数据报模式
E、TCP保证数据的正确性和顺序,UDP不能保证,可能丢失包。
Java 技术应用
1、JDBC、Ibatis(MyBatis)、Hibernate对比、以及优点缺点
答:
JDBC是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成
Hibernate、iBatis、myBatis都是Java的数据库DAO层框架。
与JDBC比较,Ibatis(MyBatis)优点如下:
A、减少了大量的代码量(61%);
B、架构级性能增强
C、sql语句与程序代码分离(便与修改)
D、增强了移植性
三者对比
(1) JDBC: 手动,手动写sql语句
delete、insert、update要将对象的值一个一个取出传到sql中,不能直接传入一个对象。
select:返回的是一个resultset,要从ResultSet中一行一行、一个字段一个字段的取出,然后封装到一个对象中,不直接返回一个对象。
(2) ibatis的特点:半自动化
sql要手动写
delete、insert、update:直接传入一个对象
select:直接返回一个对象
(3) hibernate: 全自动
不写sql,自动封装
delete、insert、update:直接传入一个对象
select: 直接返回一个对象
总结:
JDBC更加灵活,更加有效率,系统运行速度快。但是用起来麻烦,不方便数据库的移植。
Ibatis(MyBatis)、Hibernate是关系数据库框架,开发速度快,更加面向对象,可以移植更换数据库,但是影响系统性能。
2、PrepareStatement 相比 statement优点
答:优势
A、相对比较安全,可以防止sql注入
B、有预编译功能,相同操作批量数据效率较高
PrepareStatement是预编译,使用Statement时sql中要进行很多的单引号拼接字符串,容易出错也比较麻烦。从安全方面来说,就是存在sql注入PrepareStatement传参数时候使用了占位符"?",解决了此类问题,(效率高)。
3、TCP为什么3次握手,四次挥手
答:TCP三次握手的目的是为了解决网络中存在延迟而重复分组的问题,防止server端一直等待,浪费资源。保证数据的可靠传输。
举个栗子(已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了),三次握手能解决此问题。client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。
四次挥手目的:
试想一下,假如现在你是客户端,你想断开跟Server的所有连接该怎么做?
第一步,你自己先停止向Server端发送数据,并等待Server的回复。但事情还没有完,虽然你自身不往Server发送数据了,但是因为你们之前已经建立好平等的连接了,所以此时他也有主动权向你发送数据;故Server端还得终止主动向你发送数据,并等待你的确认。其实,说白了就是保证双方的一个合约的完整执行!
名词解释:
seq:序列号
ACK:确认标志
SYN:请求同步标志
FIN:结束标志
三次握手:
(1) 客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文1
(2) 当服务器接收到客户端发来的SYN时,会向客户端发送一个SYN+ACK数据包,这是三次握手中的第2个报文,这个报文同时带ACK标志和SYN标志。因此它表示对刚才客户端SYN报文的回应;同时又标志SYN给客户端,询问客户端是否准备好进行数据通讯。
(3) 客户端接收到,再次回应服务段一个ACK报文,确认发送。这是报文段3。
四次挥手:
(1) 先由客户端向服务器端发送一个FIN,请求关闭数据传输
(2) 当服务器接收到客户端的FIN时,向客户端发送一个ACK,其中ack的值等于FIN+SEQ
(3) 服务器向客户端发送一个FIN,告诉客户端应用程序关闭
(4) 客户端收到服务器端的FIN时,回复一个ACK给服务器端。其中ack的值等于FIN+SEQ
4、进程和线程含义及区别
答:(1)含义:
进程:具有一定独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位。
线程:是进程的一个实体,是CPU调度和分配的基本单位
(2)区别:
A、主要区别就是他们是不同操作系统的资源管理方式。
B、一个程序至少有一个进程,一个进程至少有一个线程
C、线程的划分尺度小于进程,使得多线程程序的并发性高
D、进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其他进程产生影响。但是线程没有独立的地址空间,一个线程死掉等于整个线程就死掉,因此多进程比多线程健壮。
E、线程在执行过程中与进程还是有区别的。每个独立的进程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
5、多线程什么情况下执行 wait 和 notify
答:调用wait和notify方法前,必须获得锁对象,也就是必须用在synchronized机制中的while循环中。
比如说两个线程A和B,当线程A获取到锁对象后,判断while循环条件是否满足,如果不满足,无法继续下一处理的时候,调用wait()方法。
在B线程中,B线程更改了某些条件,使得线程A的条件满足了,就调用notify()唤醒A
6、tomcat负载均衡
http://www.cnblogs.com/rocomp/p/4802396.html
7、Spring容器如何加载
https://my.oschina.net/chape/blog/136453
8、Servlet生命周期(什么时候destory)
答:servlet生命周期由javax.servlet.Servlet接口的init(),service()和destory()方法表达。Servlet被实例化之后,运行其init()方法,
请求到达时运行其service()方法,service()方法会自动派遣运行与请求对应的doXXX(doGet与doPost)等,当服务器决定将实例销毁的时候,
调用其destory()方法。
9、MySQL 底层实现,B+树原理
答:
(1)http://blog.csdn.net/u012978884/article/details/52416997
(2)B+树是为文件系统需要而设计的一种平衡查找树;http://blog.csdn.net/sykpour/article/details/25142759
10、10PB数据,每一条是一个qq号,统计出现频率最多的qq号
答:用hash的方法,hash(QQ) mod 10000,根据尾号取模把QQ分配到10000个文件中,这样每个文件的内存就是100MB,每个文件100MB,可以完全加载到内存中进行排序,相同的QQ(同一个QQ字符串的hash值是一样的,这是解题关键)肯定存在相同的文件中,然后对每一个文件用HashMap(qq,qq.count)统计每个qq出现的次数。然后,记录每个文件的最大访问次数的QQ,最后,从10000个文件中找出来一个最大的即可。核心解题思想:hash(QQ) + 分而治之 (注:可否使用堆排序来实现呢?)
11、JVM新生代和老年代如何区分,新生代垃圾回收用什么算法,copy算法内存是怎么分的
答:
(1) JAVA堆中是JVM管理的最大的一块内存空间,主要存放对象实例。
详见米扑博客:JVM 基础知识
Java 中堆被分为两个两块区域,即新生代(young,1/3)和老年代(old,2/3)
所谓的新生代和老年代是针对于分代收集算法来定义的。
区别:存放对象生命周期不同,垃圾回收机制不同。
新生代GC(minor gc) 主要是用来存放新生的对象,分为Eden和Survivor(from,to)两个区,这样划分是为了更好的管理堆内存中的对象,方便GC算法---复制coping算法来进行垃圾回收。
老年代GC(major gc)主要存放应用程序中生命周期长的内存对象,指发生在老年代的垃圾回收动作,所采用是的标记--整理算法。
(2)新生代采用复制算法回收垃圾。
(3)copy算法基本思想:将内存分为两块,每次只用其中的一块,当这一块内存用完,就将还活着的对象复制到另一块上面。
具体地说,在GC开始的时候,对象只会存在到Eden区和From Survivor区中,而To Survivor区的内容是空的,紧接着进行GC,然后Eden区存活的对象都会被复制到“To”,而“From”区里面的对象年龄会加1,当年龄达到一定数值(年龄阈值),对象会被移动到老年代里,没有达到的被复制到“To”里面
因此经过GC后,Eden和“from”中的对象会被清空,这个时候,“From”和“To”交换角色,然后重复这样的过程,直到“To”区域被填满,“To”被填满后,会将所有的对象都移动到老年代中。
12、HashMap的实现原理
(http://zhangshixi.iteye.com/blog/672697)
答:
(1) HashMap的概述
HashMap是基于哈希表的Map接口的非同步(非线程安全)实现,允许使用null值和null键,此类不保证映射的顺序。
(2) HashMap的数据结构
HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。
HashMap的底层就是一个数组结构,数组中的每一项又是一个链表
(3) HashMap的存取实现
存储(put): 当往HashMap中put元素的时候,先根据key的HashCode重新计算hash值,根据这个hash值得到这个元素在数组中的下标,如果该位置已经有其他元素,那么该位置的元素将已链表的形式存放,新加的放在链头。如果没有元素,就直接将该元素放在此位置。
获取(get): HashMap中get元素时,首先计算key的hashCode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。
总结:
HashMap在底层将Key-value当成一个整体进行处理,这个整体就是一个Entry对象。
HashMap底层采用一个Entry[]数组来保存所有的Key-value
对,当需要存储一个Entry对象时,会根据 hash算法来决定其在数组中的存储位置,再根据 equals方法决定其在数组位置上链表中的存储位置,当需要取出一个Entry对象时,先根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该对象。
13、数组和链表的比较
数组:数组是将元素在内存中连续存放,由于每个元素占用的内存相同,可以通过下标迅速访问数组中的任何元素,但是增加或者删除一个元素,就需要移动大量的元素,比较缓慢。
链表:链表中的元素在内存中不是顺序存储的,而是通过指针存在一起,每个节点包括两个部分,存储元素的数据域与存储下一结点地址的指针域
如果访问链表中元素,需要从第一个元素开始,一直找到需要的元素的位置,所以缓慢。但是增加删除元素,只需要修改指针就可以,速度较快。
区别:
(1)存储位置:
数组逻辑上相邻的元素在物理存储位置上也相邻,而链表不一定;
(2)存储空间:
链表存放的内存空间可以是连续的,也可以不连续,但是数组则是连续的一段存储空间;
(3)长度的可变性:
链表的长度可变,数组不可变
(4)访问方式:
数组可以随机访问其中元素,链表必须顺序访问。
优缺点:
1)数组
优点:使用方便,查询效率高,内存为一连续区域
缺点:大小固定,不适合动态存储,不方便动态添加。
2)链表
优点:可动态添加删除,大小可变
缺点:查询效率低。
14、ArrayList 和 Linkedlist 以及 Vector对比
答:ArrayList与Vector都是使用数组的方式进行存储,此数组元素数大于实际存储数据以便增加和插入元素,他们都允许按序直接索引元素,因此
查询较快,但是插入数组元素涉及到数组元素移动等内存操作,因此增删比较慢。Vector由于使用了synchronized方法,所以线程安全,但性能较差。
LinkedList使用双向链表的方式进行存储,按序索引数据需要向前或者向后遍历,因此查询比较慢;但是插入数据只需要记录本项的前后两项
即可,因此增删快,LinkedList也是线程不安全的。
15、准备一个了解或者感兴趣的新技术
面试题,说说对 Spring IOC和AOP的理解
在面试中,经常会问,说说你对 Spring IOC 和 AOP的理解,问题很宽泛,似乎不知道从何说起。
回答思路:
1. 先用通俗易懂的话解释下何为IOC和AOP
2. 各自的实现原理
3. 自己的项目中如何使用
以下是个人的一些总结,仅供参考。
1. IOC
许多应用都是通过彼此间的相互合作来实现业务逻辑的,如类A要调用类B的方法,
以前我们都是在类A中,通过自身new一个类B,然后在调用类B的方法,
现在我们把new类B的事情交给spring来做,在我们调用的时候,容器会为我们实例化。
2. IOC容器的初始化过程
资源定位,即定义bean的xml-------》载入--------》IOC容器注册,注册beanDefinition
IOC容器的初始化过程,一般不包含bean的依赖注入的实现,在spring IOC设计中,bean的注册和依赖注入是两个过程,,依赖注入一般发生在应用第一次索取bean的时候,但是也可以在xm中配置,在容器初始化的时候,这个bean就完成了初始化。
3. 三种注入方式,构造器、接口、setter注入,我们常用的是set注入
4. bean是如何创建--- 工厂模式
5. 数据是如何注入-------反射
6. AOP
面向切面编程,在我们的应用中,经常需要做一些事情,但是这些事情与核心业务无关,
比如,要记录所有update*方法的执行时间时间,操作人等等信息,记录到日志,
通过spring的AOP技术,就可以在不修改update*的代码的情况下完成该需求。
7. AOP的实现原理------代理
以下文章本人觉得可以很好地回答前两个问题,特此转载供读者参考:
http://blog.csdn.net/it_man/article/details/4402245 IOC的定义及实现原理---反射
http://www.cnblogs.com/yanbincn/archive/2012/06/01/2530377.html AOP的定义实现原理---代理
http://outofmemory.cn/code-snippet/3762/Spring-AOP-learn-example AOP的应用的三种实现方式
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2021-02-11 05:38:15
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!
转载注明: Java 技术面试题及答案 (米扑博客)