java-面试简答题答案及详解

1. */简述下列问题

Listsetmap的区别

 Listset是继承自Collection接口的接口,map是独立的接口,不继承Collection接口

List接口存储一组不唯一可以有重复的,

有序的对象,查找元素效率高,插入删除效率低

Set接口存储一组唯一的无序的对象

检索效率低,插入删除效率高

Map接口存储一组键值对象,提供keyvalue值的映射

 

ArrayListvector的区别

 

2) VectorArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。

ArrayList它允许对元素进行快速随机访问它适合随机查找和遍历,不适合插入和删除。

VectorArrayList一样,也是通过数组实现的访问它比访问ArrayList慢。

3) 

HashMapHashtable的区别

  HashtableHashMap它们的性能方面的比较类似 VectorArrayList,比如Hashtable的方法是同步的,HashMap的不是。

  HashMapHashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度。

 

HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)

HashMap是非synchronized,而Hashtablesynchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。

另一个区别是HashMap的迭代器(Iterator)fail-fast迭代器,而Hashtableenumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是EnumerationIterator的区别。

由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable

HashMap不能保证随着时间的推移Map中的元素次序是不变的。

2. 简述jspServlet的异同之处

  1.jsp经编译后就变成了servlet(jsp本质就是servlet,jvm只能识别java的类,不能识别jsp代码,web容器将jsp的代码编译成jvm能够识别的java)

 

2.jsp更擅长表现于页面显示,servlet更擅长于逻辑控制

 

3.setvlet中没有内置对象,jsp中的内置对象都是必须通过HttpServletRequest对象,HttpServletResponse对象及HttpServlet对象得到

 

4.jspservlet的一种简化,使用jsp只需要完成程序员需用输出到客户端的内容,jsp中的java脚本如何镶嵌到一个类中,由jsp容器完成,而servlet则是个完整的java类,这个类的service方法用于生成对客户端的响应

3. 简述jsp内置对象及其作用

JSP中一共预先定义了9个这样的对象,分别为:requestresponsesessionapplicationoutpagecontextconfigpageexception

1request对象

request 对象是 javax.servlet.httpServletRequest类型的对象。 该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。request对象的作用域为一次请求。

2response对象

response 代表的是对客户端的响应,主要是将JSP容器处理过的对象传回到客户端。response对象也具有作用域,它只在JSP页面内有效。

3session对象

session 对象是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态。session对象内部使用Map类来保存数据,因此保存数据的格式为 “Key/value”。 session对象的value可以使复杂的对象类型,而不仅仅局限于字符串类型。

4application对象

 application 对象可将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效。与session对象相比,application对象生命周期更长,类似于系统的“全局变量”。

5out 对象

out 对象用于在Web浏览器内输出信息,并且管理应用服务器上的输出缓冲区。在使用 out 对象输出数据时,可以对数据缓冲区进行操作,及时清除缓冲区中的残余数据,为其他的输出让出缓冲空间。待数据输出完毕后,要及时关闭输出流。

6pageContext 对象

pageContext 对象的作用是取得任何范围的参数,通过它可以获取 JSP页面的outrequestreponsesessionapplication 等对象。pageContext对象的创建和初始化都是由容器来完成的,在JSP页面中可以直接使用 pageContext对象。

7config 对象

config 对象的主要作用是取得服务器的配置信息。通过 pageConext对象的 getServletConfig() 方法可以获取一个config对象。当一个Servlet 初始化时,容器把某些信息通过 config对象传递给这个 Servlet。 开发者可以在web.xml 文件中为应用程序环境中的Servlet程序和JSP页面提供初始化参数。

8page 对象

page 对象代表JSP本身,只有在JSP页面内才是合法的。 page隐含对象本质上包含当前 Servlet接口引用的变量,类似于Java编程中的 this 指针。

9exception 对象

exception 对象的作用是显示异常信息,只有在包含 isErrorPage="true" 的页面中才可以被使用,在一般的JSP页面中使用该对象将无法编译JSP文件。excepation对象和Java的所有对象一样,都具有系统提供的继承结构。exception 对象几乎定义了所有异常情况。在Java程序中,可以使用try/catch关键字来处理异常情况; 如果在JSP页面中出现没有捕获到的异常,就会生成 exception 对象,并把 exception 对象传送到在page指令中设定的错误页面中,然后在错误页面中处理相应的 exception 对象。

4. 简述spring的特点以及原理

   IOCinversion of control)控制反转

         概念:控制权有对象本身转向容器;由容器根据配置文件区创建实例并创建各个实例之间的依赖关系。

         核心:spring封装了抽象工厂模式;bean工厂创建的各个实例称作为bean

         理解:喜欢吃的东西不一定自己亲自去做,交给食品加工厂去做不是更好吗。spring让一个对象不用创建new了,可以自动生产,这就是利用java的反射机制动态创建、调用对象,spring就是在运行时,根xml pring配置文件动态创建对象,和调用对象里的方法的。

         spring IOC 应用了单例模式,一次new一个全局对象,也可以在配置文件中进行配置,配置为不使用单例模式。

   AOPaspect oriented programming)面向切面编程

         1、不使用代理方式

 2、代理的两种方式

         静态代理:

         针对每个具体类分别编写代理类。针对一个接口编写一个代理类;

动态代理:

         针对一个方面编程写一个invocationHandler,然后借用JDK反射包中的proxy类为各个接口动态生成相应的代理类。

 如何使用JDK动态代理呢?

        1、实现InvocationHandler接口。

        2、通过Proxy,根据目标来生成代理。

        3invoke方法,该方法中调用具体的切入方法。

动态代理与静态代理区别

        静态代理:由程序员创建,再对其编译。在程序运行之前.class文件已经存在了。静态代理:在程序运行时,运用反射的机制动态创建而完成。无需程序员手动编写代码,利用jdk的动态代理机制即可,不仅简化了编程工作,且提高了软件的可扩展性,因为java的反射机制可以生成任意类型的动态代理。

        动态代理使用场景:不允许直接访问某些类,对访问要做特殊处理;或者对原始方法进行统一的扩展,例如日志的记录。

         springAOP

         springAOP核心也是动态代理,spring采用三种方式实现代理功能。1java的动态代理方式。2CGlib方式。3Aspectj方式。

         默认模式

         spring使用java动态代理和CGlib的混合方式提供服务,即若对象实现了接口则spring自动采用java动态代理进行支持,否则则采用CGlib方式进行支持;也可以强制制定使用cglib方式代理,在配置文件中进行配置。

5. 一个.java”源文件中是否可以包括多个类(不是内部类)?有什么限制?

 可以的

但是只能有一个public, 而且如果有public类的话,这个文件的名字要和这个类的名字一样。

如果都没有public类,名字可以不和这个类一样。

6. 静态变量和实例变量的区别

   在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。

        在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

7. 给出下面代码段

1 public class Test{

2 int n=0;

3   int m=0;

4 public Test(int a) {m=a;}

5 public static void main(String[] arg){

6 Test t1;

7 int j,k;

8 j=3;k=5;

9 t1=new Test();

10 ……

11}

12}

上述代码编译时是否出现错误如有错误请写出错误原因

第九行 引用TEST方法时候没有传入变量

8. 什么是对象持久化

对象持久化就是将对象存储在可持久保存的存储介质上,例如主流的关系数据库中

9. 请写出代表Servlet声明周期的几个方法并简单描述其生命周期

  一个servlet的生命周期由不熟servlet的容器来控制,当一个请求映射到一个servlet的时候,该容器执行下列步骤。

      1.如果一个Servlet的实例不存在,则Web容器

           加载servlet类,创建一个servlet实例,调用init()方法初始化Servlet实例

      2.调用Service方法,传递一个请求和相应对象,

      3调用Destroy方法,移除一个Servlet

1;服务器创建一个Servlet实例

2:服务器调用Servletinit()方法初始化servlet实例

3. 服务器调用service方法

4. 调用destroy方法销毁实例

 

10. Jsp有哪些内置对象作用分别是什么

第三题

JSP中一共预先定义了9个这样的对象,分别为:requestresponsesessionapplicationoutpagecontextconfigpageexception

1request对象

request 对象是 javax.servlet.httpServletRequest类型的对象。 该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。request对象的作用域为一次请求。

2response对象

response 代表的是对客户端的响应,主要是将JSP容器处理过的对象传回到客户端。response对象也具有作用域,它只在JSP页面内有效。

3session对象

session 对象是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态。session对象内部使用Map类来保存数据,因此保存数据的格式为 “Key/value”。 session对象的value可以使复杂的对象类型,而不仅仅局限于字符串类型。

4application对象

 application 对象可将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效。与session对象相比,application对象生命周期更长,类似于系统的“全局变量”。

5out 对象

out 对象用于在Web浏览器内输出信息,并且管理应用服务器上的输出缓冲区。在使用 out 对象输出数据时,可以对数据缓冲区进行操作,及时清除缓冲区中的残余数据,为其他的输出让出缓冲空间。待数据输出完毕后,要及时关闭输出流。

6pageContext 对象

pageContext 对象的作用是取得任何范围的参数,通过它可以获取 JSP页面的outrequestreponsesessionapplication 等对象。pageContext对象的创建和初始化都是由容器来完成的,在JSP页面中可以直接使用 pageContext对象。

7config 对象

config 对象的主要作用是取得服务器的配置信息。通过 pageConext对象的 getServletConfig() 方法可以获取一个config对象。当一个Servlet 初始化时,容器把某些信息通过 config对象传递给这个 Servlet。 开发者可以在web.xml 文件中为应用程序环境中的Servlet程序和JSP页面提供初始化参数。

8page 对象

page 对象代表JSP本身,只有在JSP页面内才是合法的。 page隐含对象本质上包含当前 Servlet接口引用的变量,类似于Java编程中的 this 指针。

9exception 对象

exception 对象的作用是显示异常信息,只有在包含 isErrorPage="true" 的页面中才可以被使用,在一般的JSP页面中使用该对象将无法编译JSP文件。excepation对象和Java的所有对象一样,都具有系统提供的继承结构。exception 对象几乎定义了所有异常情况。在Java程序中,可以使用try/catch关键字来处理异常情况; 如果在JSP页面中出现没有捕获到的异常,就会生成 exception 对象,并把 exception 对象传送到在page指令中设定的错误页面中,然后在错误页面中处理相应的 exception 对象。

11. 什么是cookie?sessioncookie有什么区别

Cookie Web 应用程序保存用户相关信息提供了一种有用的方法。

1session 在服务器端,cookie 在客户端(浏览器)

2session 默认被存在在服务器的一个文件里(不是内存)

3session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 session_id

4session 可以放在 文件、数据库、或内存中都可以。

5,用户验证这种场合一般会用 session

12. Mvc分别是那几个单词的缩写它的各部分都有哪些技术来实现如何实现

MVC(Model/View/Controller)模式是国外用得比较多的一种设计模式,好象最早是在Smaltalk中出现。MVC包括三类对象。Model是应用对象,View是它在屏幕上的表示,Controller定义用户界面对用户输入的响应方式。

模型-视图-控制器(MVC)是80年代Smalltalk-80出现的一种软件设计模式,现在已经被广泛的使用。

1、模型(Model

模型是应用程序的主体部分。模型表示业务数据,或者业务逻辑.

2、视图(View

视图是应用程序中用户界面相关的部分,是用户看到并与之交互的界面。

3、控制器(controller)

控制器工作就是根据用户的输入,控制用户界面数据显示和更新model对象状态。

视图层:jsphtmlphp之类超文本标记语言都可以

控制层:webwork serverlet struts

数据层:herbernate ibatis

 

13. J2EE是技术平台还是框架它主要包含哪些技术

J2EE本身是一个标准,一个为企业分布式应用的开发提供的标准平台。

J2EE也是一个框架,包括JDBC,RMI,JMS,EJB,JTA等技术

14. 说出数据库的五种约束并简单描述 

              约束:

实体完整性

主键约束(不能为空)

唯一性约束(可以为空)

非空约束

域完整性

Check约束

引用完整性

Foreign KEY约束(外键约束)

          1.—-主键约束(Primay Key Coustraint) 唯一性,非空性

 2.—-唯一约束 (Unique Counstraint)唯一性,可以空,但只能有一个

 3.—-检查约束 (Check Counstraint) 对该列数据的范围、格式的限制(如:年龄、性别等)

 4.—-默认约束 (Default Counstraint) 该数据的默认值

 5.—-外键约束 (Foreign Key Counstraint) 需要建立两表间的关系并引用主表的列

1 主关键字约束

 主关键字约束指定表的一列或几列的组合的值在表中具有惟一性,即能惟一地指定一行记录。每个表中只能有一列被指定为主关键字,且IMAGE TEXT 类型的列不能被指定为主关键字,也不允许指定主关键字列有NULL 属性。

2 外关键字约束

 外关键字约束定义了表之间的关系。当一个表中的一个列或多个列的组合和其它表中的主关键字定义相同时,就可以将这些列或列的组合定义为外关键字,并设定它适合哪个表中哪些列相关联。这样,当在定义主关键字约束的表中更新列值,时其它表中有与之相关联的外关键字约束的表中的外关键字列也将被相应地做相同的更新。外关键字约束的作用还体现在,当向含有外关键字的表插入数据时,如果与之相关联的表的列中无与插入的外关键字列值相同的值时,系统会拒绝插入数据。与主关键字相同,不能使用一个定义为 TEXT IMAGE 数据类型的列创建外关键字。外关键字最多由16 个列组成。

惟一性约束

 惟一性约束指定一个或多个列的组合的值具有惟一性,以防止在列中输入重复的值。惟一性约束指定的列可以有NULL 属性。由于主关键字值是具有惟一性的,因此主关键字列不能再设定惟一性约束。惟一性约束最多由16 个列组成。

检查约束

 检查约束对输入列或整个表中的值设置检查条件,以限制输入值,保证数据库的数据完整性。可以对每个列设置符合检查。

缺省约束

 缺省约束通过定义列的缺省值或使用数据库的缺省值对象绑定表的列,来指定列的缺省值。SQL Server 推荐使用缺省约束,而不使用定义缺省值的方式来指定列的缺省值。有关绑定缺省约束的方法请参见“数据完整性”章节。

15. 数组有没有length()方法?String有没有length()方法

求数组的长度可以使用数组的length属性。String length()方法,用来求字符串的长度

16. ErrorException有什么区别

Error类和Exception类的父类都是throwable类,他们的区别是:

Error类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。

Exception类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。

Exception类又分为运行时异常(Runtime Exception)和受检查的异常(Checked Exception ),运行时异常;ArithmaticException,IllegalArgumentException,编译能通过,但是一运行就终止了,程序不会处理运行时异常,出现这类异常,程序会终止。而受检查的异常,要么用try。。。catch捕获,要么用throws字句声明抛出,交给它的父类处理,否则编译不会通过。

常见的异常;

ArrayIndexOutOfBoundsException 数组下标越界异常,

ArithmaticException 算数异常 如除数为零

NullPointerException 空指针异常

IllegalArgumentException 不合法参数异常

17. Try{}里有一个return语句,那么紧跟在这个try后的finally{}里的code会不会被执行,什么时候被执行,在return前还是后?

下面是个测试程序

public class FinallyTest

{

public static void main(String[] args) {

 

System.out.println(new FinallyTest().test());;

}

 

static int test()

{

int x = 1;

try

{

x++;

return x;

}

finally

{

++x;

}

}

}

结果是2,意思是finally里的代码没执行?

肯定执行了

你在finally里加一条输出语句你就知道了

但结果为什么会是2呢?

try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。

在转去之前,try中先把要返回的结果存放到不同于a的局部变量中去,执行完finally之后,在从中取出返回结果,

因此,即使finally中对变量a进行了改变,但是不会影响返回结果。

它应该使用栈保存返回值。

18. Finalfinallyfinalize有什么联系和区别?

简单区别:

final用于声明属性,方法和类,分别表示属性不可交变,方法不可覆盖,类不可继承。

finally是异常处理语句结构的一部分,表示总是执行。

finalizeObject类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,供垃圾收集时的其他资源回收,例如关闭文件等。

1.中等区别:

虽然这三个单词在Java中都存在,但是并没有太多关联:

finaljava中的关键字,修饰符。

      1.如果一个类被声明为final,就意味着它不能再派生出新的子类,不能作为父类被继承。因此,一个类不能同时被声明为absrtact抽象类的和final的类。

       2.如果将变量或者方法声明为final,可以保证它们在使用中不被改变.

                 2.1 被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。

                 2.2被声明final的方法只能使用,不能重载。

2 .finallyjava的一种异常处理机制。            

       finally是对Java 异常处理模型的最佳补充。finally 结构使代码总会执行,而不管有无异常发生。使用 finally 可以维护对象的内部状态,并可以清理非内存资源。特别是在关闭数据库连接这方面,如果程序员把数据库连接的close()方法放到finally中,就会大大降低程序出错的几率。

3.finalizeJava中的一个方法名。  

      Java技术使用finalize()方法在垃圾收集器将对象从内存中清除出去前,做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在Object类中定义的,因此所有的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。

详细区别:

     这是一道再经典不过的面试题了,我们在各个公司的面试题中几乎都能看到它的身影。finalfinallyfinalize虽然长得像孪生三兄弟一样,但是它们的含义和用法却是大相径庭。这一次我们就一起来回顾一下这方面的知识。

1.final关键字我们首先来说说final。它可以用于以下四个地方:     1. 定义变量,包括静态的和非静态的。     2. 定义方法的参数。     3. 定义方法。     4. 定义类。我们依次来回顾一下每种情况下final的作用。

1.1 定义变量,包括静态的和非静态的。定义方法的参数

第一种情况:

          如果final修饰的是一个基本类型,就表示这个变量被赋予的值是不可变的,即它是个常量;

          如果final修饰的是一个对象,就表示这个变量被赋予的引用是不可变的

这里需要提醒大家注意的是,不可改变的只是这个变量所保存的引用,并不是这个引用所指向的对象。

 

第二种情况:

           final的含义与第一种情况相同。

 

实际上对于前两种情况,有一种更贴切的表述final的含义的描述,那就是,如果一个变量或方法参数被final修饰,就表示它只能被赋值一次,但是JAVA虚拟机为变量设定的默认值不记作一次赋值。

final修饰的变量必须被初始化。初始化的方式有以下几种:     1. 在定义的时候初始化。     2. final变量可以在初始化块中初始化,不可以在静态初始化块中初始化。     3. 静态final变量可以在静态初始化块中初始化,不可以在初始化块中初始化。     4. final变量还可以在类的构造器中初始化,但是静态final变量不可以。

通过下面的代码可以验证以上的观点:

Java代码public class FinalTest {     // 在定义时初始化     public final int A = 10;

 

    // 在初始化块中初始化

     public final int B;     {          B = 20;     }

     // 非静态final变量不能在静态初始化块中初始化     // public final int C;     // static {          // C = 30;     // }

     // 静态常量,在定义时初始化     public static final int STATIC_D = 40;

 

   // 静态常量,在静态初始化块中初始化

     public static final int STATIC_E;     static {          STATIC_E = 50;     }

     // 静态变量不能在初始化块中初始化     // public static final int STATIC_F;     // {          // STATIC_F = 60;     // }

       public final int G;

     // 静态final变量不可以在构造器中初始化     // public static final int STATIC_H;     // 在构造器中初始化          public FinalTest() {               G = 70;

// 静态final变量不可以在构造器中初始化

// STATIC_H = 80;

 

// final的变量第二次赋值时,编译会报错

// A = 99;

// STATIC_D = 99;

          }

// final变量未被初始化,编译时就会报错

// public final int I;

// 静态final变量未被初始化,编译时就会报错

// public static final int STATIC_J;

}

 

我们运行上面的代码之后出了可以发现final变量(常量)和静态final变量(静态常量)被初始化时,编译会报错。

final修饰的变量(常量)比非final的变量(普通变量)拥有更高的效率,因此我们在际编程中应该尽可能多的用常量来代替普通变量,这也是一个很好的编程习惯。

1.2 定义方法当final用来定义一个方法时,会有什么效果呢?正如大家所知,它表示这个方法不可以被子类重写,但是它这不影响它被子类继承。我们写段代码来验证一下:

Java代码public class ParentClass {     public final void TestFinal() {          System.out.println("父类--这是一个final方法");     }}public class SubClass extends ParentClass {     /**     * 子类无法重写(override)父类的final方法,否则编译时会报错     */     // public void www.gzlij.com TestFinal() {     // System.out.println("子类--重写final方法");     // }     public static void main(String[] args) {          SubClass sc = new SubClass();          sc.TestFinal();     }}

这里需要特殊说明的是,具有private访问权限的方法也可以增加final修饰,但是由于子无法继承private方法,因此也无法重写它。编译器在处理private方法时,是按照final方来对待的,这样可以提高该方法被调用时的效率。不过子类仍然可以定义同父类中private方法具有同样结构的方法,但是这并不会产生重写的效果,而且它们之间也不存在必然联系。

1.3 定义类

最后我们再来回顾一下final用于类的情况。这个大家应该也很熟悉了,因为我们最常用的String类就是final的。由于final类不允许被继承,编译器在处理时把它的所有方法都当作final的,因此final类比普通类拥有更高的效率。而由关键字abstract定义的抽象类含有必须由继承自它的子类重载实现的抽象方法,因此无法同时用finalabstract来修饰同一个类。同样的道理,final也不能用来修饰接口。 final的类的所有方法都不能被重写,但这并不表示final的类的属性(变量)值也是不可改变的,要想做到final类的属性值不可改变,必须给它增加final修饰,请看下面的例子:

 

Java代码public final class FinalTest {

int i = 10;

 final int j = 50;

public static void main(String[] args) {

     FinalTest ft = new FinalTest();

     ft.i = 99;          // finalFinalTest的属性值 i是可以改变的,因为属性值i前面没有final//

// ft.j = 49;         // 报错....因为 j 属性是final 的不可以改变。

     System.out.println(ft.i);

}

}

运行上面的代码试试看,结果是99,而不是初始化时的10

2.finally语句

接下来我们一起回顾一下finally的用法。这个就比较简单了,它只能用在try/catch语句中并且附带着一个语句块,表示这段语句最终总是被执行。请看下面的代码:

Java代码public final class FinallyTest {

public static void main(String[] args) {

try {

     throw new NullPointerException();

} catch (NullPointerException e) {

     System.out.println("程序抛出了异常");

} finally {

 //这里总会被执行,不受break,return影响另如数据库连接的close()一般写在这里,可以降低程序的出错几率

     System.out.println("执行了finally语句块");                      

}

}

}

 

运行结果说明了finally的作用:1. 程序抛出了异常2. 执行了finally语句块请大家注意,捕获程序抛出的异常之后,既不加处理,也不继续向上抛出异常,并不是良好的编程习惯,它掩盖了程序执行中发生的错误,这里只是方便演示,请不要学习。

那么,有没有一种情况使finally语句块得不到执行呢?大家可能想到了

returncontinuebreak这三个可以打乱代码顺序执行语句的规律。那我们就来试试看,这三个语句是否能影响finally语句块的执行:

Java代码public final class FinallyTest {

          // 测试return语句

            结果显示:编译器在编译return new ReturnClass();时,将它分成了两个步骤,new ReturnClass()return,前一个创建对象的语句是在finally语句块之前被执行的,而后一个return语句是在finally语句块之后执行的,也就是说finally语句块是在程序退出方法之前被执行的

public ReturnClass testReturn() {

try {

     return new ReturnClass();

} catch (Exception e) {

     e.printStackTrace();

} finally {

     System.out.println("执行了finally语句");

}

return null;

}

 

// 测试continue语句

public void testContinue() {

for (int i = 0; i < 3; i++) {

try {

System.out.println(i);

if (i == 1) {

continue;

}

} catch (Exception e) {

     e.printStackTrace();

} finally {

     System.out.println("执行了finally语句");

}

}

}

 

// 测试break语句

public void testBreak() {

for (int i = 0; i < 3; i++) {

try {

     System.out.println(i);

     if (i == 1) {

          break;

     }

} catch (Exception e) {

     e.printStackTrace();

} finally {

     System.out.println("执行了finally语句");

}

}

}

public static void main(String[] args) {

 

FinallyTest ft = new FinallyTest();

 

// 测试return语句

ft.testReturn();

System.out.println();

 

// 测试continue语句

ft.testContinue();

System.out.println();

 

// 测试break语句

ft.testBreak();

}

}class ReturnClass {     public ReturnClass() {          System.out.println("执行了return语句");     }}

上面这段代码的运行结果如下:1. 执行了return语句2. 执行了finally语句3.4. 05. 执行了finally语句6. 17. 执行了finally语句8. 29. 执行了finally语句10.11. 012. 执行了finally语句13. 114. 执行了finally语句

 

 

很明显,returncontinuebreak都没能阻止finally语句块的执行。从输出的结果来看,return语句似乎在 finally语句块之前执行了,事实真的如此吗?我们来想想看,return语句的作用是什么呢?是退出当前的方法,并将值或对象返回。如果 finally语句块是在return语句之后执行的,那么return语句被执行后就已经退出当前方法了,finally语句块又如何能被执行呢?因此,正确的执行顺序应该是这样的:编译器在编译return new ReturnClass();时,将它分成了两个步骤,new ReturnClass()return,前一个创建对象的语句是在finally语句块

之前被执行的,而后一个return语句是在finally语句块之后执行的,也就是说finally语句块是在程序退出方法之前被执行的。同样,finally语句块是在循环被跳过(continue)和中断(break)之前被执行的。

3.finalize方法最后,我们再来看看finalize,它是一个方法,属于java.lang.Object类,它的定义如下:Java代码protected void finalize() throws Throwable { }众所周知,finalize()方法是GCgarbage collector)运行机制的一部分在此我们只说说finalize()方法的作用是什么呢?finalize()方法是在GC清理它所从属的对象时被调用的,如果执行它的过程中抛出了无法捕获的异常(uncaught exception),GC将终止对改对象的清理,并且该异常会被忽略;直到下一次GC开始清理这个对象时,它的finalize()会被再次调用。请看下面的示例:

Java代码public final class FinallyTest {

// 重写finalize()方法

protected void finalize() throws Throwable {

     System.out.println("执行了finalize()方法");

}

public static void main(String[] args) {

     FinallyTest ft = new FinallyTest();

     ft = null;

     System.gc();   

}

}

运行结果如下:• 执行了finalize()方法

程序调用了java.lang.System类的gc()方法,引起GC的执行,GC在清理ft对象时调用了它的finalize()方法,因此才有了上面的输出结果。调用System.gc()等同于调用下面这行代码:Java代码Runtime.getRuntime().gc();调用它们的作用只是建议垃圾收集器(GC)启动,清理无用的对象释放内存空间,但是G的启动并不是一定的,这由JAVA虚拟机来决定。直到 JAVA虚拟机停止运行,有些对象的finalize()可能都没有被运行过,那么怎样保证所有对象的这个方法在JAVA虚拟机停止运行之前一定被调用呢?答案是我们可以调用System类的另一个方法:

Java代码public static void runFinalizersOnExit(boolean value) {//other code}    给这个方法传入true就可以保证对象的finalize()方法在JAVA虚拟机停止运行前一定被运行了,不过遗憾的是这个方法是不安全的,它会导致有用的对象finalize()被误调用,因此已不被赞成使用了。    由于finalize()属于Object类,因此所有类都有这个方法,Object的任意子类都可以重写(override)该方法,在其中释放系统资源或者做其它的清理工作,如关闭输入输出流。通过以上知识的回顾,我想大家对于finalfinallyfinalize的用法区别已经很清楚了。

19. 解释下SeriallzationDeserialization

Java提供了一种叫做对象序列化的机制,他把对象表示成一连串的字节,里面包含了对象的数据,对象的类型信息,对象内部的数据的类型信息等等。因此,序列化可以看成是为了把对象存储在磁盘上或者是从磁盘上读出来并重建对象而把对象扁平化的一种方式。反序列化是把对象从扁平状态转化成活动对象的相反的步骤。

20. Servlet的作用以及Servlet需要实现的核心接口是什么

Servlet(Servlet Applet):    是用JAVA编写的服务器端程序。

          定义:狭义上:指java语言实现的一个接口

          广义上:指任意一个实现了这个Servlet接口的类。

   作用:主要用于交互式地浏览和修改数据,生成Web内容。

这个过程主要有:(1)客户端发送请求到服务器端

               2)服务器将请求信息发送至Servlet

               3Servlet生成响应内容并将其传给服务器。

               4)服务器将响应返回给客户端。

    一个Servlet就是Java编辑语言中的一个类,它被用来扩展服务器的性能,服务器上驻留着可以通过“请求-响应”编辑模式型来访问的应用程序。虽然Servlet可以对任何类型的请求产生响应,但通常只用来扩展Web服务器的应用程序。

    Servlet看起来像是通常的Java程序。Servlet导入特定的属于javaServlet API的包。因为是对象字节码,可动态地从网络加载,可以说ServletServer就如同AppletClient一样,但是,由于Servlet运行Server中,它们并不需要一个图形用户界面。从这个角度看,Servlet也被称为FacelessObject(隐形的根类).

二、Servlet的生命周期

    1.客户端请求该Servlet;

     2.加载Servlet类到内存;

     3.实例化并调用init()方法初始化该Servlet

     4.service()(根据请求方法不同调用doGet()或者doPost(),此外还有doHead()doPut()doTrace()doDelete()doOptions())

      5.destroy()销毁。

三、Servlet的通讯

    Servlet:JAVA编写的在服务器上运行的小程序/.接收client请求,处理,响应.

    1.include:包含

        应用场景:在复杂动态网页中,有公共部分可提取,可以把公共部分分别定义成servlet,使用include合并到一起.

        使用:        //获取请求分发对象

                RequestDispatcher rd = request.getRequestDispatcher("/url-pattern");

                //include

                rd.include(request, response);

        特点:        1)地址栏不变

                2)服务器端的转发(在服务端运行)

                3)看到的是所有servlet的结果之和

                4)共享同一个request

    2.forward:转发

        应用场景: 一个Servlt从数据库中取出数据,转到另外一个servlet进行显示

        使用:        //获取请求分发对象

                RequestDispatcher rd = request.getRequestDispatcher("/url-pattern");

                //forward

                rd.forward(request, response);

        特点:        1)地址栏不变

                2)服务器端的转发(在服务端运行)

                3)永久转向(看到的是最后一个servlet的处理结果)

                4)共享同一个request

ServletConfig接口:用于获取Servlet初始化参数和ServletContext对象;

SercletContext接口:代表当前Servlet运行环境,Servlet可以通过ServletContext对象来访问Servlet容器中的各种资源;

HttpServletRequest接口:用于封装HTTP请求消息

HttpServletReponse接口:用于封装HTTP响应消息

21. 简述Servlet的声明周期

1.Server创建一个Servlet的实例

2.Server调用Servletinit()方法

3.一个客户端的请求到达Server

4.Server创建一个请求对象

5.Server创建一个响应对象

6.servlet做出相应的响应

7.调用Destroy()方法来销毁 

22. Try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码块与执行顺序怎样

肯定执行了

你在finally里加一条输出语句你就知道了

但结果为什么会是2呢?

try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。

在转去之前,try中先把要返回的结果存放到不同于a的局部变量中去,执行完finally之后,在从中取出返回结果,

因此,即使finally中对变量a进行了改变,但是不会影响返回结果。

它应该使用栈保存返回值。

主函数调用子函数并得到结果的过程,好比主函数准备一个空罐子,当子函数要返回结果时,先把结果放在罐子里,然后再将程序逻辑返回到主函数。所谓返回,就是子函数说,我不运行了,你主函数继续运行吧,这没什么结果可言,结果是在说这话之前放进罐子里的。

当有第二个return的时候,主函数就会将上一个结果覆盖,

所以对于上面第二种情况的输出结果:一开始main函数的空罐子接收的是i=1,后面执行finally,将i=2返回,所以最后输出的结果是i=2

http://blog.csdn.net/xiaaiwu/article/details/52021269

23. 线程的创建方式那种方式更受欢迎

三种方式可以用来创建线程:

继承Thread

实现Runnable接口

应用程序可以使用Executor框架来创建线程池

实现Runnable接口这种方式更受欢迎,因为这不需要继承Thread类。在应用设计中已经继承了别的对象的情况下,这需要多继承(而Java不支持多继  承),只能实现接口。

同时,线程池也是非常高效的,很容易实现和使用

24. 什么是迭代器

1. 迭代器其实就是指针,读取集合或数组中的值,读完指向下一条数据

2. 迭代器的效率比较高,并且可以实现for循环不能实现的功能,比如remove

 

25. HashMap的工作原理

HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象。”

http://www.importnew.com/7099.html

26. Jstl是什么优点有哪些

JSP标准标签库,包含的各种标签可以用jsp中。好处:1.可以编写没有Java代码的jsp页面,使得jsp页面更容易被web人员理解,表达更清晰。减少程序出错,让程序容易维护 。2.在应用服务器之间提供一致的接口,最大程序的提高了web应用在各应用服务器之间的移植

 

27. Hibernate的工作原理以及优点

Hibrnate是封装了JDBC的一种开放源代码的对象/关系框架,使程序员可以用面向对象的思想操作数据库。Hibrnate是一种对象/关系映射的解决方案。即将对象与对象的关系映射到数据库中表与表之间的关系,

28. Session.load()session.get()的区别

二者均可根据实体类和id从数据库中读取记录,并返回与之对应的实体对象。区别:http://blog.csdn.net/henry115/article/details/8254482

1.session.load()

这种方式总是返回一个代理而不是真正的查询数据库。在hibernate里面,代理是根据ID值获取的对象,该对象的属性还没有初始化,它看起来就是一个临时的虚列对象而已,

如果load()方法没有找到数据,就会抛出ObjectNotFoundException

2.session.get()

这种方式总是从数据库查询数据返回一个真实的对象,这个对象就代表着数据库中的一行而非代理

如果没有找到就返回null

load方法支持延迟加载而get则不会

http://www.cnblogs.com/xiaoluo501395377/p/3371776.html

 

29. 当一个对象被当做参数传递一个方法后此方法可改变这个对象的属性并可返回变化后的结果那么这里到底是值传递还是引用传递

是值传递,Java编程语言只有值传参数,当一个对象实例作为参数传递到方法中时,参数的值就是该对象的引用,对象的内容可以在被调用方法中改变,而对象的引用是永远不会改变的。

对象是引用传递,也就是你传递过去的只是一个地址,而程序只会去调用该地址下的值,所以一个对象作为一个参数传递给一个方法后,并且该方法对对象进行更改了,该对象的值就不是原来进方法之前的了,而是改变的了

 

30. 写出jsp中导入javaBeancom.test.USerBean)代码

< %@page import="com.test.USerBean" %>

 

31. XML文档定义有几种形式他们之间有何本质区别

两种定义形式dtd(文档类型定义)schemaXML模式)

XML schemaDTD都用于文档验证,但二者还有一定区别,本质区别:schema本身是XML的,可以被XML解析器解析(这也是从DTD上发展schema的根本目的)。

Scheme支持丰富的数据类型,而DTD不支持元素的数据类型,对属性的类型定义也很有限,

Schema是内容开放模型,可扩展、功能性强,而DTD扩展性差。

Schema支持命名空间机制而DTD不支持

Schema可针对不同情况对整个XML文档或文档局部进行验证;而DTD缺乏这种灵活性。

Schema完全遵循XML规范,符合XML语法,可以和DOM结合使用,功能强大,而DTD语法本身有自身的语法和要求,难以学习。

 

32. String、StringBufferStringBulider的区别

String类是不可变类,任何改变都会导致新的String对象生成,而stringbuffer则是可变类,可以向对象中添加新的字符串,

如果操作少量的数据用String

单线程下操作大量数据用StringBulider

多线程操作大量数据用stiringbuffer

 

33. Intinteger有什么区别

Int是基本数据类型,而integetint的封装类型是对象类型,

 

34. Java的基本数据类型有 String是不是基本类型

8种基本数据类型int.short.long.boolean.float.double.byte.charstring是引用数据类型

 

35. 你所知道的集合类都有哪些主要方法

最常用的集合类是 List MapList 的具体实现包括 ArrayList Vector,它们是可变大小的列表,比较适合构建、存储和操作任何类型对象的元素列表。 List 适用于按数值索引访问元素的情形。

Map 提供了一个更通用的

元素存储方法。 Map 集合类用于存储元素对(称作“键”和“值”),其中每个键映射到一个值

 

ArrayList 
ArrayList实现了可变大小的数组。它允许所有元素,包括nullArrayList没有同步。 
sizeisEmptygetset方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。 
  每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。 
  和LinkedList一样,ArrayList也是非同步的(unsynchronized)。 

HashMap 
HashMapHashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null valuenull key。,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。 

 

http://blog.csdn.net/nszkadrgg/article/details/8184917

36. 页面间传递的方法有哪些

1. 直接在url后面添加

2. Sessionrequest

3. Jsp:param

37. 请用图文说明SpringMVCStruts2的工作模式

 

工作原理
上面的是springMVC的工作原理图:

1、客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配DispatcherServlet的请求映射路径(在web.xml中指定),web容器将请求转交给DispatcherServlet.

2、DipatcherServlet接收到这个请求之后将根据请求的信息(包括URL、Http方法、请求报文头和请求参数Cookie等)以及HandlerMapping的配置找到处理请求的处理器(Handler)。

3-4、DispatcherServlet根据HandlerMapping找到对应的Handler,将处理权交给Handler(Handler将具体的处理进行封装),再由具体的HandlerAdapter对Handler进行具体的调用。

5、Handler对数据处理完成以后将返回一个ModelAndView()对象给DispatcherServlet。

6、Handler返回的ModelAndView()只是一个逻辑视图并不是一个正式的视图,DispatcherSevlet通过ViewResolver将逻辑视图转化为真正的视图View。

7、Dispatcher通过model解析出ModelAndView()中的参数进行解析最终展现出完整的view并返回给客户端。

工作机制是什么

Control的调用(续)

接着对于(二)的补充:主要是小结下Control的处理逻辑的关键操作;

对于control的处理关键就是:DispatcherServlet的handlerMappings集合中根据请求的URL匹配每一个handlerMapping对象中的某个handler,匹配成功之后将会返回这个handler的处理连接handlerExecutionChain对象。而这个handlerExecutionChain对象中将会包含用户自定义的多个handlerInterceptor对象。

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

/**

     * Return the HandlerExecutionChain for this request.

     * <p>Tries all handler mappings in order.

     * @param request current HTTP request

     * @return the HandlerExecutionChain, or <code>null</code> if no handler could be found

     */

    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

        for (HandlerMapping hm : this.handlerMappings) {

            if (logger.isTraceEnabled()) {

                logger.trace(

                        "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");

            }

            HandlerExecutionChain handler = hm.getHandler(request);

            if (handler != null) {

                return handler;

            }

        }

        return null;

    }

而对于handlerInterceptor接口中定义的三个方法中,preHandler和postHandler分别在handler的执行前和执行后执行,afterCompletion在view渲染完成、在DispatcherServlet返回之前执行。

 

PS:这么我们需要注意的是:当preHandler返回false时,当前的请求将在执行完afterCompletion后直接返回,handler也将不会执行。

在类HandlerExecutionChain中的getHandler()方法是返回object对象的;

1

2

3

4

5

6

7

/**

     * Return the handler object to execute.

     * @return the handler object

     */

    public Object getHandler() {

        return this.handler;

    }

这里的handler是没有类型的,handler的类型是由handlerAdapter决定的。dispatcherServlet会根据handler对象在其handlerAdapters集合中匹配哪个HandlerAdapter实例支持该对象。接下来去执行handler对象的相应方法了,如果该handler对象的相应方法返回一个ModelAndView对象接下来就是去执行View渲染了。

1

2

3

4

5

6

7

/**

     * Return the handler object to execute.

     * @return the handler object

     */

    public Object getHandler() {

        return this.handler;

    }

 

---------------------------------------邪恶的分割线---------------------------------------------

Model设计

如果handler兑现返回了ModelAndView对象,那么说明Handler需要传一个Model实例给view去渲染模版。除了渲染页面需要model实例,在业务逻辑层通常也有Model实例。

 

ModelAndView对象是连接业务逻辑层与view展示层的桥梁,对spring MVC来说它也是连接Handler与view的桥梁。ModelAndView对象顾名思义会持有一个ModelMap对象和一个View对象或者View的名称。ModelMap对象就是执行模版渲染时候所需要的变量对应的实例,如jsp的通过request.getAttribute(String)获取的JSTL标签名对应的对象。velocity中context.get(String)获取$foo对应的变量实例。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

public class ModelAndView {

 

/** View instance or view name String */

    private Object view;

 

    /** Model Map */

    private ModelMap model;

 

    /** Indicates whether or not this instance has been cleared with a call to {@link #clear()} */

    private boolean cleared = false;

 

.....

 

}

 

ModelMap其实也是一个Map,Handler中将模版中需要的对象存在这个Map中,然后传递到view对应的ViewResolver中。

1

2

3

4

public interface ViewResolver {

    View resolveViewName(String viewName, Locale locale) throws Exception;

 

}

 

不同的ViewResolver会对这个Map中的对象有不同的处理方式;

 

· velocity中将这个Map保存到VelocityContext中。

· JSP中将每一个ModelMap中的元素分别设置到request.setAttribute(modelName,modelValue);

-----------------------邪恶的分割线-----------------------------------------------

view设计

spring MVC中,view模块需要两个组件来支持:RequestToViewNameTranslator和ViewResolver

1

2

3

4

5

6

7

8

9

10

11

12

public interface RequestToViewNameTranslator {

 

    /**

     * Translate the given {@link HttpServletRequest} into a view name.

     * @param request the incoming {@link HttpServletRequest} providing

     * the context from which a view name is to be resolved

     * @return the view name (or <code>null</code> if no default found)

     * @throws Exception if view name translation fails

     */

    String getViewName(HttpServletRequest request) throws Exception;

 

}

对于 ViewResolver,前面有写到了,就不写了;

-----------------------邪恶的分割线-------------------------------------------------

RequestToViewNameTranslator:主要支持用户自定义对viewName的解析,如将请求的ViewName加上前缀或者后缀,或者替换成特定的字符串等。

ViewResolver:主要是根据用户请求的viewName创建适合的模版引擎来渲染最终的页面,ViewResolver会根据viewName创建一个view对象,调用view对象的Void render方法渲染出页面;

 

1

2

3

public interface View {

void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;

}

下面来总结下 Spring MVC解析View的逻辑:

· dispatcherServlet方法调用getDefaultViewName()方法;

1

2

3

4

5

6

7

8

9

/**

     * Translate the supplied request into a default view name.

     * @param request current HTTP servlet request

     * @return the view name (or <code>null</code> if no default found)

     * @throws Exception if view name translation failed

     */

    protected String getDefaultViewName(HttpServletRequest request) throws Exception {

        return this.viewNameTranslator.getViewName(request);

    }

· 调用了RequestToViewNameTranslator的getViewName方法;

1

2

3

4

5

6

7

8

9

10

11

12

public interface RequestToViewNameTranslator {

 

    /**

     * Translate the given {@link HttpServletRequest} into a view name.

     * @param request the incoming {@link HttpServletRequest} providing

     * the context from which a view name is to be resolved

     * @return the view name (or <code>null</code> if no default found)

     * @throws Exception if view name translation fails

     */

    String getViewName(HttpServletRequest request) throws Exception;

 

}

 

· 调用LocaleResolver接口的resolveLocale方法;

1

Locale resolveLocale(HttpServletRequest request);

· 调用ViewResolver接口的resolveViewName方法,返回view对象

1

View resolveViewName(String viewName, Locale locale) throws Exception;

· 调用render方法渲染出页面

技术优势

    Struts2有两方面的技术优势,一是所有的Struts2应用程序都是基于client/server HTTP交换协议,The Java Servlet API揭示了Java Servlet只是Java API的一个很小子集,这样我们可以在业务逻辑部分使用功能强大的Java语言进行程序设计。

    二是提供了对MVC的一个清晰的实现,这一实现包含了很多参与对所以请求进行处理的关键组件,如:拦截器、OGNL表达式语言、堆栈。

    因为struts2有这样目标,并且有这样的优势,所以,这是我们学习struts2的理由,下面,我们在深入剖析一下struts的工作原理。

工作原理

    Suruts2的工作原理可以用下面这张图来描述,下面我们分步骤介绍一下每一步的核心内容

 

一个请求在Struts2框架中的处理大概分为以下几个步骤 

    1、客户端初始化一个指向Servlet容器(例如Tomcat)的请求

    2、这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin) 

    3、接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action 

       FilterDispatcher是控制器的核心,就是mvc中c控制层的核心。下面粗略的分析下我理解的FilterDispatcher工作流程和原理:FilterDispatcher进行初始化并启用核心doFilter

[html] view plain copy

1. public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException ...{  

2.         HttpServletRequest request = (HttpServletRequest) req;  

3.         HttpServletResponse response = (HttpServletResponse) res;  

4.         ServletContext servletContext = filterConfig.getServletContext();  

5.         // 在这里处理了HttpServletRequest和HttpServletResponse。  

6.         DispatcherUtils du = DispatcherUtils.getInstance();  

7.         du.prepare(request, response);//正如这个方法名字一样进行locale、encoding以及特殊request parameters设置  

8.         try ...{  

9.             request = du.wrapRequest(request, servletContext);//对request进行包装  

10.         } catch (IOException e) ...{  

11.             String message = "Could not wrap servlet request with MultipartRequestWrapper!";  

12.             LOG.error(message, e);  

13.             throw new ServletException(message, e);  

14.         }  

15.                 ActionMapperIF mapper = ActionMapperFactory.getMapper();//得到action的mapper  

16.         ActionMapping mapping = mapper.getMapping(request);// 得到action 的 mapping  

17.         if (mapping == null) ...{  

18.             // there is no action in this request, should we look for a static resource?  

19.             String resourcePath = RequestUtils.getServletPath(request);  

20.             if ("".equals(resourcePath) && null != request.getPathInfo()) ...{  

21.                 resourcePath = request.getPathInfo();  

22.             }  

23.             if ("true".equals(Configuration.get(WebWorkConstants.WEBWORK_SERVE_STATIC_CONTENT))   

24.                     && resourcePath.startsWith("/webwork")) ...{  

25.                 String name = resourcePath.substring("/webwork".length());  

26.                 findStaticResource(name, response);  

27.             } else ...{  

28.                 // this is a normal request, let it pass through  

29.                 chain.doFilter(request, response);  

30.             }  

31.             // WW did its job here  

32.             return;  

33.         }  

34.         Object o = null;  

35.         try ...{  

36.             //setupContainer(request);  

37.             o = beforeActionInvocation(request, servletContext);  

38. //整个框架最最核心的方法,下面分析  

39.             du.serviceAction(request, response, servletContext, mapping);  

40.         } finally ...{  

41.             afterActionInvocation(request, servletContext, o);  

42.             ActionContext.setContext(null);  

43.         }  

44.     }  

45. du.serviceAction(request, response, servletContext, mapping);  

46. //这个方法询问ActionMapper是否需要调用某个Action来处理这个(request)请求,如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy  

47.    

48. public void serviceAction(HttpServletRequest request, HttpServletResponse response, String namespace, String actionName, Map requestMap, Map parameterMap, Map sessionMap, Map applicationMap) ...{   

49.         HashMap extraContext = createContextMap(requestMap, parameterMap, sessionMap, applicationMap, request, response, getServletConfig());  //实例化Map请求 ,询问ActionMapper是否需要调用某个Action来处理这个(request)请求  

50.         extraContext.put(SERVLET_DISPATCHER, this);   

51.         OgnlValueStack stack = (OgnlValueStack) request.getAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY);   

52.         if (stack != null) ...{   

53.             extraContext.put(ActionContext.VALUE_STACK,new OgnlValueStack(stack));   

54.         }   

55.         try ...{   

56.             ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy(namespace, actionName, extraContext);   

57. //这里actionName是通过两道getActionName解析出来的, FilterDispatcher把请求的处理交给ActionProxy,下面是ServletDispatcher的 TODO:   

58.             request.setAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY, proxy.getInvocation().getStack());   

59.             proxy.execute();   

60.          //通过代理模式执行ActionProxy  

61.             if (stack != null)...{   

62.                 request.setAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY,stack);   

63.             }   

64.         } catch (ConfigurationException e) ...{   

65.             log.error("Could not find action", e);   

66.             sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e);   

67.         } catch (Exception e) ...{   

68.             log.error("Could not execute action", e);   

69.             sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);   

70.         }   

71. }   

 

 

    4、如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy 

    5、ActionProxy通过ConfigurationManager询问框架的配置文件,找到需要调用的Action类 ,这里,我们一般是从struts.xml配置中读取。

    6、ActionProxy创建一个ActionInvocation的实例。

    7、ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。

    下面我们来看看ActionInvocation是如何工作的:

    ActionInvocation是Xworks 中Action 调度的核心。而对Interceptor 的调度,也正是由ActionInvocation负责。ActionInvocation 是一个接口,而DefaultActionInvocation 则是Webwork 对ActionInvocation的默认实现。

    Interceptor的调度流程大致如下:

    1.ActionInvocation初始化时,根据配置,加载Action相关的所有Interceptor。

    2. 通过ActionInvocation.invoke方法调用Action实现时,执行Interceptor。

    Interceptor将很多功能从我们的Action中独立出来,大量减少了我们Action的代码,独立出来的行为具有很好的重用性。XWork、WebWork的许多功能都是有Interceptor实现,可以在配置文件中组装Action用到的Interceptor,它会按照你指定的顺序,在Action执行前后运行。

    这里,我们简单的介绍一下Interceptor

    在struts2中自带了很多拦截器,在struts2-core-2.1.6.jar这个包下的struts-default.xml中我们可以发现:

[html] view plain copy

1. <interceptors>  

2.            <interceptor name="alias"class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>  

3.            <interceptor name="autowiring"class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>  

4.            <interceptor name="chain"class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>  

5.            <interceptor name="conversionError"class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>  

6.            <interceptor name="clearSession"class="org.apache.struts2.interceptor.ClearSessionInterceptor"/>  

7.            <interceptor name="createSession"class="org.apache.struts2.interceptor.CreateSessionInterceptor"/>  

8.            <interceptor name="debugging"class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor"/>  

9.            <interceptor name="externalRef"class="com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor"/>  

10.            <interceptor name="execAndWait"class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>  

11.            <interceptor name="exception"class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>  

12.            <interceptor name="fileUpload"class="org.apache.struts2.interceptor.FileUploadInterceptor"/>  

13.            <interceptor name="i18n"class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>  

14.            <interceptor name="logger"class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>  

15.            <interceptor name="modelDriven"class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>  

16.            <interceptor name="scopedModelDriven"class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>  

17.            <interceptor name="params"class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>  

18.            <interceptor name="actionMappingParams"class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>  

19.            <interceptor name="prepare"class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>  

20.            <interceptor name="staticParams"class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>  

21.            <interceptor name="scope"class="org.apache.struts2.interceptor.ScopeInterceptor"/>  

22.            <interceptor name="servletConfig"class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>  

23.            <interceptor name="sessionAutowiring"class="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor"/>  

24.            <interceptor name="timer"class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>  

25.            <interceptor name="token"class="org.apache.struts2.interceptor.TokenInterceptor"/>  

26.            <interceptor name="tokenSession"class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>  

27.            <interceptor name="validation"class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>  

28.            <interceptor name="workflow"class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>  

29.            <interceptor name="store"class="org.apache.struts2.interceptor.MessageStoreInterceptor"/>  

30.            <interceptor name="checkbox"class="org.apache.struts2.interceptor.CheckboxInterceptor"/>  

31.            <interceptor name="profiling"class="org.apache.struts2.interceptor.ProfilingActivationInterceptor"/>  

32.            <interceptor name="roles"class="org.apache.struts2.interceptor.RolesInterceptor"/>  

33.            <interceptor name="jsonValidation"class="org.apache.struts2.interceptor.validation.JSONValidationInterceptor"/>  

34.            <interceptornameinterceptorname="annotationWorkflow"class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor"/>  

 

    对于sturts2自带的拦截器,使用起来就相对比较方便了,我们只需要在struts.xml的action标签中加入<interceptor-ref name="logger " />并且struts.xml扩展struts-default,就可以使用,

   如果是要自定义拦截器,首先需要写一个拦截器的类:

[html] view plain copy

1. package ceshi;  

2. import com.opensymphony.xwork2.ActionInvocation;  

3. import com.opensymphony.xwork2.interceptor.AbstractInterceptor;  

4.    

5. publicclassAuthorizationInterceptor extends AbstractInterceptor {  

6.    

7.     @Override  

8.     public Stringintercept(ActionInvocation ai)throws Exception {  

9.          

10.            System.out.println("abc");  

11.             return ai.invoke();  

12.              

13.     }  

14.    

15. }  

 

并且在struts.xml中进行配置

[html] view plain copy

1. <!DOCTYPEstruts PUBLIC  

2. "-//Apache SoftwareFoundation//DTD Struts Configuration 2.0//EN"  

3. "http://struts.apache.org/dtds/struts-2.0.dtd">  

4.    

5.    

6. <struts>  

7.     <package name="test"extends="struts-default">  

8.      <interceptors>  

9.       <interceptor name="abc"class ="ceshi.AuthorizationInterceptor"/>  

10.     </interceptors>  

11.         <action name="TestLogger"class="vaannila.TestLoggerAction">  

12.            <interceptor-refnameinterceptor-refname="abc"/>  

13.            <result name="success">/success.jsp</result>  

14.            </action>  

15.     </package>  

16. </struts>  

 

    8、一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper

 

在上述过程中所有的对象(Action,Results,Interceptors,等)都是通过ObjectFactory来创建的。

 

Struts2和struts1的比较

    struts2相对于struts1来说简单了很多,并且功能强大了很多,我们可以从几个方面来看:

    从体系结构来看:struts2大量使用拦截器来出来请求,从而允许与业务逻辑控制器 与 servlet-api分离,避免了侵入性;而struts1.x在action中明显的侵入了servlet-api.

    从线程安全分析:struts2.x是线程安全的,每一个对象产生一个实例,避免了线程安全问题;而struts1.x在action中属于单线程。

    性能方面:struts2.x测试可以脱离web容器,而struts1.x依赖servlet-api,测试需要依赖web容器。

    请求参数封装对比:struts2.x使用ModelDriven模式,这样我们 直接 封装model对象,无需要继承任何struts2的基类,避免了侵入性。

    标签的优势:标签库几乎可以完全替代JSTL的标签库,并且 struts2.x支持强大的ognl表达式。

    当然,struts2和struts1相比,在 文件上传,数据校验 等方面也 方便了好多。在这就不详谈了。

    

    一个比较优秀的框架可以帮着我们更高效,稳定的开发合格的产品,不过我们也不要依赖框架,我们只要理解了思想,设计模式,我们可以自己扩展功能,不然 就要 永远让别人牵着走了!

https://zhidao.baidu.com/question/1608172076361330947.html

38. 举例说明MySQL、OracleSQL ServerSQL语法上的不同点

1.放在内存中的表在写别名使用as

sql:  select * from (select * from base_org) as bs    -- 可以用as 

 orcl:  select * from (select * from base_org)  bs      --不用as 

2.连接符

Sql: +

Orcl: ||

3.是否为空的函数

sql:   isnull(a.STORE_TYPE, '') 

     orcl:  nvl (a.STORE_TYPE, '') 

http://zhongdao.iteye.com/blog/951852

39. 列举几种常见的异常并说明含义

1. 空指针异常:调用空对象的方法或属性导致

2. ClassCastException:类型强制转换异常

比如:Object x = new String("String");
  System.out.println((Integer) x);

3. ArrayIndexOutOfBoundsException

4. ArithmeticException:算数运算异常

5. NumberFormatException数字格式异常,比如将it转换成integer

 

40. 解释事务的隔离级别和传播级别

1Spring声明式事务

声明式事务(declarative transaction management)Spring提供的对程序事务管理的方式之一。

Spring的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中申明。用在Spring配置文件中声明式的处理事务来代替代码式的处理事务。这样的好处是,事务管理不侵入开发的组件,具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可;在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译,这样维护起来极其方便。

Spring使用AOP来完成声明式的事务管理,因而声明式事务是以方法为单位,Spring的事务属性自然就在于描述事务应用至方法上的策略,在Spring中事务属性有以下参数:

属性

类型

描述

propagation

枚举型:Propagation

可选的传播性设置

isolation

枚举型:Isolation

可选的隔离性级别(默认值:ISOLATION_DEFAULT)

readOnly

布尔型

读写型事务 vs. 只读型事务

timeout

int型(以秒为单位)

事务超时

rollbackFor

一组Class类的实例,必须是Throwable的子类

一组异常类,遇到时 必须 进行回滚。默认情况下checked exceptions不进行回滚,仅unchecked exceptions(即RuntimeException的子类)才进行事务回滚。

rollbackForClassname

一组Class类的名字,必须是Throwable的子类

一组异常类名,遇到时 必须 进行回滚

noRollbackFor

一组Class类的实例,必须是Throwable的子类

一组异常类,遇到时 必须不 回滚。

noRollbackForClassname

一组Class类的名字,必须是Throwable的子类

一组异常类,遇到时 必须不 回滚

 

2Spring传播行为

 

REQUIRED

业务方法需要在一个事务中运行,如果方法运行时,已处在一个事务中,那么就加入该事务,否则自己创建一个新的事务.这是spring默认的传播行为.

SUPPORTS

如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分,如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行.

MANDATORY

只能在一个已存在事务中执行,业务方法不能发起自己的事务,如果业务方法在没有事务的环境下调用,就抛异常

REQUIRES_NEW

业务方法总是会为自己发起一个新的事务,如果方法已运行在一个事务中,则原有事务被挂起,新的事务被创建,直到方法结束,新事务才结束,原先的事务才会恢复执行.

NOT_SUPPORTED

声明方法需要事务,如果方法没有关联到一个事务,容器不会为它开启事务.如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行.

NEVER

声明方法绝对不能在事务范围内执行,如果方法在某个事务范围内执行,容器就抛异常.只有没关联到事务,才正常执行.

NESTED

如果一个活动的事务存在,则运行在一个嵌套的事务中.如果没有活动的事务,则按REQUIRED属性执行.它使用了一个单独的事务, 这个事务拥有多个可以回滚的保证点.内部事务回滚不会对外部事务造成影响, 它只对DataSourceTransactionManager 事务管理器起效.

 .详细解释如下:

Required:默认的事务传播行为,表示必须有逻辑事务,否则新建一个事务,使用PROPAGATION_REQUIRED指定,表示如果当前存在一个逻辑事务,则加入该逻辑事务,否则将新建一个逻辑事务:

 

RequiresNew:创建新的逻辑事务,使用PROPAGATION_REQUIRES_NEW指定,表示每次都创建新的逻辑事务(物理事务也是不同的)因此外部事务可以不受内部事务回滚状态的影响独立提交或者回滚。

 

Supports:支持当前事务,使用PROPAGATION_SUPPORTS指定,指如果当前存在逻辑事务,就加入到该逻辑事务,如果当前没有逻辑事务,就以非事务方式执行。

NotSupported:不支持事务,如果当前存在事务则暂停该事务,使用PROPAGATION_NOT_SUPPORTED指定,即以非事务方式执行,如果当前存在逻辑事务,就把当前事务暂停,以非事务方式执行。

Mandatory:使用PROPAGATION_MANDATORY指定,如果当前有事务,使用当前事务执行,如果当前没有事务,则抛出异常(IllegalTransactionStateException)。

Never:不支持事务,如果当前存在是事务则抛出IllegalTransactionStateException异常,使用PROPAGATION_NEVER指定。

Nested:嵌套事务支持,使用PROPAGATION_NESTED指定,如果当前存在事务,则在嵌套事务内执行,如果当前不存在事务,则创建一个新的事务,嵌套事务使用数据库中的保存点来实现,即嵌套事务回滚不影响外部事务,但外部事务回滚将导致嵌套事务回滚。

Nested和RequiresNew的区别: 

· RequiresNew每次都创建新的独立的物理事务,而Nested只有一个物理事务;

· Nested嵌套事务回滚或提交不会导致外部事务回滚或提交,但外部事务回滚将导致嵌套事务回滚,而 RequiresNew由于都是全新的事务,所以之间是无关联的;

· Nested使用JDBC 3的保存点实现,即如果使用低版本驱动将导致不支持嵌套事务。

    实际应用中一般使用默认的事务传播行为,偶尔会用到RequiresNew和Nested方式。

 

3Spring的隔离级别

声明式事务的第二个方面是隔离级别。隔离级别定义一个事务可能受其他并发事务活动活动影响的程度。另一种考虑一个事务的隔离级别的方式,是把它想象为那个事务对于事物处理数据的自私程度。

在一个典型的应用程序中,多个事务同时运行,经常会为了完成他们的工作而操作同一个数据。并发虽然是必需的,但是会导致一下问题:

丢失更新   : 
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。 
:
事务A和事务B同时修改某行的值,
1.事务A将数值改为1并提交
2.事务B将数值改为2并提交。
这时数据的值为2,事务A所做的更新将会丢失。 
解决办法:对行加锁,只允许并发一个更新事务。

 

脏读: 

一个事务读到另一个事务未提交的更新数据

:

1.Mary的原工资为1000, 财务人员将Mary的工资改为了8000(但未提交事务)         
2.Mary读取自己的工资 ,发现自己的工资变为了8000,欢天喜地!
3.而财务发现操作有误,回滚了事务,Mary的工资又变为了1000, 像这样,Mary记取的工资数8000是一个脏数据。

 

不可重复读: 

在同一个事务中,多次读取同一数据,返回的结果有所不同换句话说就是,后续读取可以读到另一个事务已提交的更新数据相反"可重复读"在同一事务多次读取数据时,能够保证所读数据一样,也就是后续读取不能读到另一事务已提交的更新数据.

:

1.在事务1中,Mary 读取了自己的工资为1000,操作并没有完成
2.在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务.
3.在事务1中,Mary 再次读取自己的工资时,工资变为了2000
解决办法:如果只有在修改事务完全提交之后才可以读取数据,则可以避免该问题。

 

幻读: 

一个事务读取到另一个事务已提交的insert数据.

:

第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时 (此时第一事务还未提交,第二个事务向表中插入一行新数据。这时第一个事务再去读取表时,发现表中还有没有修改的数据行,就好象发生了幻觉一样。

在理想状态下,事务之间将完全隔离,从而可以防止这些问题发生。然而,完全隔离会影响性能,因为隔离经常牵扯到锁定在数据库中的记录(而且有时是锁定完整的数据表)。侵占性的锁定会阻碍并发,要求事务相互等待来完成工作。

考虑到完全隔离会影响性能,而且并不是所有应用程序都要求完全隔离,所以有时可以在事务隔离方面灵活处理。因此,就会有好几个隔离级别。

 

隔离级别

含义

ISOLATION_DEFAULT

使用后端数据库默认的隔离级别。

ISOLATION_READ_UNCOMMITTED

允许读取尚未提交的更改。可能导致脏读、幻影读或不可重复读。

ISOLATION_READ_COMMITTED

允许从已经提交的并发事务读取。可防止脏读,但幻影读和不可重复读仍可能会发生。

ISOLATION_REPEATABLE_READ

对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻影读仍可能发生。

ISOLATION_SERIALIZABLE

完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的。

详细解释如下:

 1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
      另外四个与JDBC的隔离级别相对应
 2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
      这种隔离级别会产生脏读,不可重复读和幻像读。
 3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
 4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
      它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)
 5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
      除了防止脏读,不可重复读外,还避免了幻像读。

http://blog.csdn.net/yujin753/article/details/42242297

 

41. 列举三个常用的线程安全的类再列举三个常用的线程不安全的类

线程安全的类:StringBufferHashTable Vector

线程不安全的类:StringBuildHashMapList

42. 简述造成线程死锁的原因,以及如何避免死锁

所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。

造成死锁的原因:

1)竞争不可抢占性资源。

2)竞争可消耗资源。

3)进程推进顺序不当。

避免死锁的方法:

1)加锁顺序(线程按照一定的顺序加锁)

2)加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)

3)死锁检测

43. 简述java对象的声明周期

Java中,对象的生命周期包括以下几个阶段:

1.创建阶段(Created)

2.应用阶段(In Use)

3.不可见阶段(Invisible)

4.不可达阶段(Unreachable)

5.收集阶段(Collected)

6.终结阶段(Finalized)

7.对象空间重分配阶段(De-allocated)

 

44. HashMap的存储原理

HashMap存储的是一组键值对,我们通过put方法来存储一个键以及其对应的值,然后可以通过get方法传入键,从而获取与这个键相对应的值。

45. 当数据表中A、B字段做了组合索引 单独使用A或单独使用B会有索引效果吗?

AB两字段做组合索引的时候,谁在前面,谁在后面,如果A在前,那么单独使用A会有索引效果,单独使用B则没有,反之亦然。同理,使用like模糊查询时,如果只是使用前面%,那么有索引效果,如果使用双%号匹配,那么则无索引效果

46. 数据库存储日期格式如何考虑时区转换问题

使用TimeStamp

47. 一条sql执行过长的时间如何去优化从哪些方面

1、查看sql是否涉及多表的联表或者子查询,如果有,看是否能进行业务拆分,相关字段冗余或者合并成临时表(业务和算法的优化)

2、涉及链表的查询,是否能进行分表查询,单表查询之后的结果进行字段整合

3、如果以上两种都不能操作,非要链表查询,那么考虑对相对应的查询条件做索引。加快查询速度

4、针对数量大的表进行历史表分离(如交易流水表)

5、数据库主从分离,读写分离,降低读写针对同一表同时的压力

48. 你的接口服务数据被别人截包了,你如何防止数据恶意提交?

答:我们可以在接口传输参数里面设置一个业务编号,这个编号用来区分是否重复提交。这样即使数据被抓包了,对方也无法区分每个字段你的含义。

49. 多线程有几种实现方法同步有几种实现方法

多线程实现方法有两种:一种是实现Runnable 接口,一种是继承Thread类。

 实现同步也有两种:一种是用同步方法,一种是用同步块。

同步方法就是在方法返回类型后面加上synchronized, 比如:public void * synchronized add(){...}

同步块就是直接写:synchronized (这里写需要同步的对象){...}

50. 简述servlet的生命周期--------------------**+*

实例化--->servlet容器创建servlet的实例

初始化--->该容器调用init()方法

请求处理--->如果请求servlet,则容器调用service()方法

服务终止--->销毁实例之前调用destroy()方法


猜你喜欢

转载自blog.csdn.net/lpdfight/article/details/78198773