关闭

技术面试题目汇总

标签: 面试
306人阅读 评论(0) 收藏 举报
分类:

一、java三大框架

1、Spring

Spring是一个轻量级的,分层的java开发框架,它的核心是控制反转(IOC)和面向切面(AOP)。控制反转是指一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。面向切面编程是指允许通过分离应用的业务逻辑与系统级服务(例如日志和事务transaction)管理)进行内聚性的开发。应用对象只需要关注业务逻辑这一个切面,不需要去关注系统级的关注点,比如日志或事务支持。Spring还提供一个容器,管理应用对象的配置和生命周期。Spring框架在一个XML文件里对应用对象进行声明,Spring也提供很多基础功能(事务管理、持久化框架集成等等),只需要关注应用逻辑的开发。

所以,使用Spring框架,可以写出更干净、易管理、易测试的代码。

2、Hibernate

Hibernate是一个开源的对象关系(O/R)映射框架,它对JDBC进行了轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。Hibernate可以应用在任何使用JDBC的场合。

Hibernate的核心接口一共有5个,分别为:Session、SessionFactory、Transaction、Query和Configuration。这5个核心接口在任何开发中都会用到。通过这些接口,不仅可以对持久化对象进行存取,还能够进行事务控制。下面对这五个核心接口分别加以介绍。

1.Session接口:负责执行被持久化对象的CRUD操作(CRUD的任务是完成与数据库的交流,包含了很多常见的SQL语句。)。但需要注意的是Session对象是非线程安全的。同时,Hibernate的session不同于JSP应用中的HttpSession。这里当使用session这个术语时,其实指的是Hibernate中的session,而以后会将HttpSession对象称为用户session。

2.SessionFactory接口:负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。需要注意的是SessionFactory并不是轻量级的,因为一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。

3.Configuration接口:负责配置并启动Hibernate,创建SessionFactory对象。在Hibernate的启动的过程中,Configuration类的实例首先定位映射文档位置、读取配置,然后创建SessionFactory对象。

4.Transaction接口:负责事务相关的操作。它是可选的,开发人员也可以设计编写自己的底层事务处理代码。

5.Query和Criteria接口:负责执行各种数据库查询。它可以使用HQL语言或SQL语句两种表达方式。

3、Struts

Struts是MVC框架在Web应用上的实现,能够很好地帮助java 开发者利用J2EE开发Web应用。如果我们想混合使用Servlets和JSP的优点来建立可扩展的应用,struts是一个不错的选择。

1.流程:服务器启动后,根据web.xml加载ActionServlet读取struts-config.xml文件内容到内存。

2.架构:Struts对Model,View和Controller都提供了对应的组件。ActionServlet,这个类是Struts的核心控制器,负责拦截来自用户的请求。

        Model部分:由JavaBean组成,ActionForm用于封装用户的请求参数,封装成ActionForm对象,该对象被ActionServlet转发给Action,Action根据ActionFrom里面的请求参数处理用户的请求。JavaBean则封装了底层的业务逻辑,包括数据库访问等。

View部分:该部分采用JSP实现。Struts提供了丰富的标签库,通过标签库可以减少脚本的使用,自定义的标签库可以实现与Model的有效交互,并增加了现实功能。对应上图的JSP部分。

   Controller组件:Controller组件有两个部分组成——系统核心控制器,业务逻辑控制器。   系统核心控制器,对应上图的ActionServlet。该控制器由Struts框架提供,继承HttpServlet类,因此可以配置成标注的Servlet。该控制器负责拦截所有的HTTP请求,然后根据用户请求决定是否要转给业务逻辑控制器。业务逻辑控制器,负责处理用户请求,本身不具备处理能力,而是调用Model来完成处理。对应Action部分。

二、数据结构单向链表操作

1、链表反转

思路:将第一个元素的指针域设为空,接着循环每个元素,修改它的Next属性,然后将头指针指向最后一个元素。另外也可以采用递归的方式。

 public static Link Reverve(Link list)
 2     {
 3         if (list == null || list.get_Next() == null || list.get_Next().get_Next() == null)
 4         {
 5             System.out.println("list is null or just contains 1 element, so do not need to reverve.");
 6             return list;
 7         }        
 8         Link current = list.get_Next();
 9         Link next = current.get_Next();
10         current.set_Next(null);
11         while(next != null)
12         {
13             Link temp = next.get_Next();
14             next.set_Next(current);
15             current = next;
16             next = temp;
17         }
18         list.set_Next(current);
19         
20         return list;
21     }

2、输出指定位置的元素(倒数第N个元素)

思路:1、我们可以使用两个游标来遍历链表,第一个游标先走N步,然后两个游标同时前进,当第一个游标走到链表的最后时,第二个游标就走到了倒数第N个元素。2、直接考虑的话,要先遍历链表,得到链表的总长度n,然后再遍历到n-N个节点,取出该元素的值。

 1     public static Link find(Link list, int rPos)
 2     {
 3         if (list == null || list.get_Next() == null)
 4         {
 5             return null;
 6         }
 7         int i = 1;
 8         Link first = list.get_Next();
 9         Link second = list.get_Next();
10         while(true)
11         {
12             if (i==rPos || first == null) break;
13             first = first.get_Next();
14             i++;
15         }
16         if (first == null)
17         {
18             System.out.println("The length of list is less than " + rPos + ".");
19             return null;
20         }
21         while(first.get_Next() != null)
22         {
23             first = first.get_Next();
24             second = second.get_Next();
25         }
26         
27         return second;
28     }
3、删除指定节点
思路:可以分情况讨论,如果指定节点不是尾节点,那么可以采用取巧的方式,将指定节点的值修改为下一个节点的值,将指定节点的Next属性设置为Next.Next;但如果指定节点为尾节点,那么只能是从头开始遍历。
1     public static void delete(Link list, Link element)
 2     {
 3         if (element.get_Next() != null)
 4         {
 5             element.set_Value(element.get_Next().get_Value());
 6             element.set_Next(element.get_Next().get_Next());
 7         }
 8         else
 9         {
10             Link current = list.get_Next();
11             while(current.get_Next() != element)
12             {
13                 current = current.get_Next();
14             }
15             current.set_Next(null);
16         }
17     }
4、删除重复节点
思路:采用hashtable来存取链表中的元素,遍历链表,当指定节点的元素在hashtable中已经存在,那么删除该节点。
1     public static void removeDuplicate(Link list)
 2     {
 3         if (list == null || list.get_Next() == null || list.get_Next().get_Next() == null) return;
 4         Hashtable table = new Hashtable();
 5         Link cur = list.get_Next();
 6         Link next = cur.get_Next();
 7         table.put(cur.get_Value(), 1);
 8         while(next != null)
 9         {
10             if (table.containsKey(next.get_Value()))
11             {
12                 cur.set_Next(next.get_Next());
13                 next = next.get_Next();                 
14             }
15             else
16             {
17                 table.put(next.get_Value(), 1);
18                 cur= next;
19                 next = next.get_Next();
20             }
21             
22         }        
23     }
5、如果一个单向链表,其中有环,怎么找出这个链表循环部分的第一个节点?

思想为:假设该节点在x位置处,假设步长为1的指针和步长为2的指针相遇在x+z处,循环的长度为y,那么2(x+z)-(x+z)=k*y,
那么当一个指针再从开始出后移时,另一个指针从相遇点开始后移时,这两个指针就会在循环开始处相遇。
三、简答题
1、动态链接库和静态链接库的优缺点:
     动态链接库简称dll,是Windows操作系统中实现共享函数库的方式。它有两种使用方式:一种是静态加载,即在应用程序启动 的时候被加载,一种是动态加载,即在动态链接库被使用的时候才被应用程序加载。
    优点如下:
    1、共享代码,dll中的代码可以被多个应用程序共享
    2、节省内存,启动多个应用程序的时候,只需要将dll加载到内存一次
    2、易于维护,dll文件独立于exe文件,更换dll文件就可以升级系统功能,极大地提高了系统的可维护性和可扩展性
    缺点:不能解决引用计数等问题
  静态链接库:函数和数据被编译进一个二进制文件(通常扩展名为.lib)。 在编译应用程序的时候,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件(.EXE文件)。 静态链接库作为代码的一部分,在编译时被链接。
    优点:代码装载速度快
    缺点如下:
    1、因为在编译的时候就要把静态库链接进去,生成的可执行文件比较大
    2、如果多个应用程序使用的话,就会被装载多次,浪费内存
    3、每次修改重建库文件中的代码后,都要重新编译所有的源代码,增加编译和发布的复杂性
2、轮询任务调度和可抢占式调度有什么区别?

(1)轮询调度的原理是每一次把来自用户的请求轮流分配给内部中的服务器,从1开始,直到N(内部服务器个数),然后再重新开始循环。 只有在当前任务主动放弃CPU控制权的情况下(比如任务挂起),才允许其他任务(包括高优先级的任务)控制CPU。其优点是简洁,它无需记录当前所有连接的状态,所以它是一种无状态调度。但不利于后面的请求尤其是高优先级的任务及时得到响应。

(2)抢占式调度允许高优先级的任务打断当前执行的任务,抢占CPU的控制权。这有利于后面的高优先级的任务也能及时得到响应。但实现相对较复杂且可能出现低优先级的任务长期得不到调度。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:7232次
    • 积分:171
    • 等级:
    • 排名:千里之外
    • 原创:6篇
    • 转载:11篇
    • 译文:2篇
    • 评论:1条
    文章分类
    文章存档
    最新评论