Ali

一、String,StringBuffer, StringBuilder 的区别是什么?String为什么是不可变的?

String 是不可改变,定长;
StringBuffer, StringBuilder
是不定长,可改变.
     
注意:本来以为StringBuilderStringBufferequals 方法是可以比较两个字符串的内容是否相等,今天才发现不是这么回事。这两个类都直接继承自Object ,并且没有重写equals 方法。

Java代码 复制代码  收藏代码
  1. StringBuilder sb1 = new StringBuilder("123");    
  2. StringBuilder sb2 = new StringBuilder("123"); System.out.println(sb1.equals(sb2));   
  3. 输出结果是:false  
StringBuilder sb1 = new StringBuilder("123"); 
StringBuilder sb2 = new StringBuilder("123"); System.out.println(sb1.equals(sb2));
输出结果是:false

 

  若要比较内容是否相同,sb1.toString().equals(sb2.toString())

 

  简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String对象,然后将指针指向新的 String对象,所以经常改变内容的字符串最好不要用 String,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM GC就会开始工作,那速度是一定会相当慢的。
      
而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM解释成了 StringBuffer对象的拼接,所以这些时候 String对象的速度并不会比 StringBuffer对象慢,而特别是以下的字符串对象生成中, String效率是远要比 StringBuffer快的:

Java代码 复制代码  收藏代码
  1. String S1 = “This is only a” + “ simple” + “ test”;    
  2. StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);    
String S1 = “This is only a” + “ simple” + “ test”; 
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);  

 

   你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM的一个把戏,在 JVM眼里,这个

 String S1 = “This is only a” + “ simple” + “test”;其实就是:
 String S1 = “This is only a simple test”;
所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String对象的话,速度就没那么快了,譬如:

 

Java代码 复制代码  收藏代码
  1. String S2 = “This is only a”;    
  2. String S3 = “ simple”;    
  3. String S4 = “ test”;    
  4. String S1 = S2 +S3 + S4;    
String S2 = “This is only a”; 
String S3 = “ simple”; 
String S4 = “ test”; 
String S1 = S2 +S3 + S4;  

 

这时候 JVM会规规矩矩的按照原来的方式去做


在大部分情况下 StringBuffer > String

StringBuffer
Java.lang.StringBuffer 线程安全的可变字符序列。一个类似于 String的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一 致。
StringBuffer
上的主要操作是 append insert方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。 append方法始终将这些字符添加到缓冲区的末端;而 insert方法则在指定的点添加字符。
   
例如,如果 z 引用一个当前内容是“start” 的字符串缓冲区对象,则此方法调用 z.append("le")会使字符串缓冲区包含“startle” ,而 z.insert(4, "le")将更改字符串缓冲区,使之包含“starlet”
在大部分情况下 StringBuilder > StringBuffer

java.lang.StringBuilde
java.lang.StringBuilder 一个可变的字符序列是5.0 新增的。此 类提供一个与 StringBuffer兼容的 API ,但不保证同步。该类被设计用作 StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer要快。两者的方法基本相同。

通过非官方试验测试,StringBuilderStringBuffer 的测试总结如下:

1 . 为了获得更好的性能,在构造StirngBuffer StirngBuilder时应尽可能指定它的容量。当然,如果你操作的字符串长度不超过 16 个字符就不用了。

2 . 相同情况下使用StirngBuilder 相比使用 StringBuffer仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。而在现实的模块化编程中,负责某一模块的程序员不一定能清晰地判断该模块是否会放入多线程的环境中运行,因此:除非你能确定你的系统的瓶颈是在StringBuffer上,并且确定你的模块不会运行在多线程模式下,否则还是用 StringBuffer 吧 J

3 . 用好现有的类比引入新的类更重要。很多程序员在使用StringBuffer 时是不指定其容量的(至少我见到的情况是这样),如果这样的习惯带入StringBuilder 的使用中,你将只能获得 10 %左右的性能提升(不要忘了,你可要冒多线程的风险噢);但如果你使用指定容量的StringBuffer,你将马上获得 45%左右的性能提升,甚至比不使用指定容量的 StirngBuilder 都快30% 左右。


二、VECTOR,ARRAYLIST, LINKEDLIST的区别是什么?

ArrayList底层是数组实现的,而LinkedList是链表实现的。Vector和ArrayList一样是数组实现的,二者的差别在于:Vector是线程安全的,所以性能上不如ArrayList


三、HASHTABLE, HASGMAQ,TreeMap区别

java为数据结构中的映射定义了一个接口java.util.Map;它有四个实现类,分别是HashMap Hashtable LinkedHashMap 和TreeMap
Map主要用于存储健值对,根据键得到值,因此不允许键重复,但允许值重复。
Hashmap 是一个 最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力,或者使用ConcurrentHashMap。
Hashtable 与 HashMap类似,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了 Hashtable在写入时会比较慢。
LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为 LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。

四、ConcurrentMap和HashMap的区别

ConcurrentHashMap的目标是实现支持高并发、高吞吐量的线程安全的HashMap。当然不能直接对整个hashtable加锁,所以在ConcurrentHashMap中,数据的组织结构和HashMap有所区别。

一个ConcurrentHashMap由多个segment组成,每一个segment都包含了一个HashEntry数组的hashtable,
每一个segment包含了对自己的hashtable的操作,比如get,put,replace等操作,这些操作发生的时候,对自己的hashtable进行锁定。由于每一个segment写操作只锁定自己的hashtable,所以可能存在多个线程同时写的情况,性能无疑好于只有一个hashtable锁定的情况。

参考:http://geeklu.com/2010/07/concurrenthashmap/


五、Tomcat,apache,jboss的区别

  Apache全球应用最广泛的http服务器,免费,出自apache基金组织  
  Tomcat应用也算非常广泛的web服务器,支持部分j2ee,免费,出自apache基金组织  
  JBoss开源的应用服务器,比较受人喜爱,免费(文档要收费)  
  weblogic应该说算是业界第一的app   server,全部支持j2ee1.4,  对于开发者,有免费使用一年的许可证,用起来比较舒服,出资BEA公司,呵呵,我用的就是这个,所以比较熟悉
  jboss也支持j2ee

  JBoss和WebLogic都含有Jsp和Servlet容器,也就可以做web容器,
  JBoss和WebLogic也包含EJB容器,是完整的J2EE应用服务器

  tomcat 只能做jsp和servlet的container


六、GET POST区别
七、SESSION, COOKIE区别

cookie 和session 的区别:

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。

2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
   考虑到安全应当使用session

3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
   考虑到减轻服务器性能方面,应当使用COOKIE

4、单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K。

5、所以个人建议:
   将登陆信息等重要信息存放为SESSION
   其他信息如果需要保留,可以放在COOKIE中


八、Servlet的生命周期

见下。。。
九、HTTP 报文包含内容

  客户端向WEB服务端发送请求报文,HTTP协议的请求报文格式为:
请求消息 = 请求行(实体头信息)CRLF[实体内容]请求行 = 方法 URL HTTP版本号 CRLF方法 = GET|HEAD|POST|扩展方法URL = 协议名称 + 宿主名 + 目录与文件名
其中"CRLF"表示回车换行。
    "请求行"中的"方法"描述了对指定资源执行的动作,常用的方法"GET"、"HEAD"和"POST"等3种。

 

十、Statement与PreparedStatement的区别,什么是SQL注入,如何防止SQL注入

Java 中访问数据库的步骤如下:
1)注册驱动;
2)建立连接;
3)创建Statement;
4)执行sql 语句;
5)处理结果集(若sql 语句为查询语句);
6)关闭连接。
PreparedStatement 被创建时即指定了SQL 语句,通常用于执行多次结构相
同的SQL 语句。
Statement是直接发SQL语句到数据库
PreparedStatement是将你用过的SQL语句进行预编译,如果下次你执行相同的SQL语句时,数据库就会调用以前预编译过的SQL语句。
所以用PreparedStatement执行SQL语句的速度远远快于Statement。
SQL注入是一种技术,利用一个安全漏洞发生在数据库层的应用程序。该漏洞存在时,用户输入的是不是正确过滤字符串转义字符中嵌入SQL语句或用户输入不强类型,从而出人意料地执行。事实上,它是一个实例一个更一般类别的安全漏洞,可能会发生时,一个编程或脚本语言是内嵌另一个。
 
 
SQL注入攻击例子及Statement和PreparedStatement的比较
 
SQL注入攻击是利用是指利用设计上的漏洞,在目标服务器上运行Sql语句以及进行其他方式的攻击,
动态生成Sql语句时没有对用户输入的数据进行验证是Sql注入攻击得逞的主要原因。
对于JDBC而言,SQL注入攻击只对Statement有效,对PreparedStatement是无效的,这是因为PreparedStatement不允许在不同的插入时间改变查询的逻辑结构。
如验证用户是否存在的SQL语句为:
select count(*) from usertable where name='用户名'and pswd='密码'
如果在 用户名字段 中 输入 ' or '1'='1' or '1'='1
或是在 密码字段 中 输入 1' or '1'='1
将绕过验证,但这种手段只对只对Statement有效,对PreparedStatement无效。
PreparedStatement相对Statement有以下优点:
1.防注入攻击
2.多次运行速度快
3.防止数据库缓冲区溢出
4.代码的可读性可维护性好
 
这四点使得PreparedStatement成为访问数据库的语句对象的首选,缺点是灵活性不够好,有些场合还是必须使用Statement。



十一、redirect, foward区别


十二、关于JAVA内存模型,一个对象(两个属性,四个方法)实例化100次,现在内存中的存储状态,几个对象,几个属性,几个方法。

对象和属性还有方法是一个整体,如果属性和方法不是静态的,那么就是 100个对象,每个对象都有2属性,4方法

如果属性方法是静态的,那么属于类的,永远只存在一份


十三、谈谈Hibernate的理解,一级和二级缓存的作用,在项目中Hibernate都是怎么使用缓存的
十四、反射讲一讲,主要是概念,都在哪需要反射机制,反射的性能,如何优化

IOC用到,AOP用到,HIBERNATE要用也许还有别的。

Java的反射机制允许程序在运行时透过反射API取得任何一个已知名称的class的内部信息,主要包括属性名,属性名的修饰符,方法名,方法返回值,方法修饰符等信息。


十五、谈谈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。

十六、对Spring的理解,项目中都用什么?怎么用的?对IOC、和AOP的理解及实现原理

(略)
十七、线程同步,并发操作怎么控制

(略)
十八、描述struts的工作流程。

(略)
十九、Tomcat的session处理,如果让你实现一个tomcatserver,如何实现session机制

(略)
二十、关于Cache(Ehcache,Memcached)

(略)
二一、sql的优化相关问题

(略)
二二、oracle中 rownum与rowid的理解,一千条记录我查200到300的记录怎么查?

在查询中,我们可以注意到,类似于“select xx from table where rownum < n”(n>1)这样的查询是有正确含义的,而“select xx from table where rownum = n”这样的查询只在n=1的时候成立,“select xx from table where rownum > n”(n>1)这样的查询只能得到一个空集。另外“select xx from table where rownum > 0”这个查询会返回所有的记录。这是为什么呢?原因就在于Oracle对rownum的处理上,rownum是在得到结果集的时候产生的,用于标记结果集中结果顺序的一个字段,这个字段被称为“伪数列”,也就是事实上不存在的一个数列。它的特点是按顺序标记,而且是逐次递加的,换句话说就是只有有rownum=1的记录,才可能有rownum=2的记录。

    让我们回头来分析一下在where中使用rownum作为查询条件的情况。在rownum取=1,或者rownum <= n (n>1)的时候,没有问题。那么为什么当条件为rownum = n或者rownum >= n时明明有数据却只能得到一个空集呢?假设我们的查询条件为rownum = 2,那么在查询出的第一条记录的时候,oracle标记此条记录rownum为1,结果发现和rownum=2的条件不符,于是结果集为空。写到这里,我忽然有一个有趣的想法:假如有一条查询语句为select xx,yy from table where zz > 20 and rownum < 10,那么在执行的时候,是先按照zz>20的条件查询出一个结果集,然后按照rownum取出前10条返回?还是在按照zz>20的条件先查询,然后有一个记录就标记一个rownum,到rownum<10的时候就停止查询?我觉得应该是后者,也就是在执行语句的时候,不是做full scan,而是取够数据就停止查询。要验证这个想法应该很简单,找一个数据量非常大的表进行查询就可以了。可惜目前我没有这样的表。

    我们可以看出,直接使用rownum是要受到限制的。但是很容易遇到这样的需求“查出符合条件的第xx条到第xx条记录”,比如页面的分页处理。这个时候如何构造出适合自己的结果集?嗯,墙边那位说全取出来手工挑选的哥们可以拉出去了。当然这样做也是可以的,但是前提是整个数据集的数据条数不多的情况下。假如遇到上十万百条的数据,全部取出来的话,用户就不用干别的事情了。这个时候用户应该怎么做呢?当然就是要用到我们介绍的rownum拉!rownum不是个“伪数列”么,好说,我们现在把它弄成一个实在的字段就可以了。

    具体做法就是利用子查询,在构建临时表的时候,把rownum也一起构造进去。比如“select xx,yy from (select xx,yy,rownum as xyz from table where zz >20) where xyz between 10 and 20”这样就可以了。另外使用oracle提供的结果集处理函数minus也可以做到,例如“select xx,yy from table where zz > 20 and rownum <20 minus select xx,yy from table where zz>20 and rownum <10”,但是使用minus好像比使用子查询更加消耗资源。

    和rownum相似,oracle还提供了另外一个伪数列:rowid。不过rowid和rownum不同,一般说来每一行数据对应的rowid是固定而且唯一的,在这一行数据存入数据库的时候就确定了。可以利用rowid来查询记录,而且通过rowid查询记录是查询速度最快的查询方法。(这个我没有试过,另外要记住一个长度在18位,而且没有太明显规律的字符串是一个很困难的事情,所以我个人认为利用rowid查询记录的实用性不是很大)rowid只有在表发生移动(比如表空间变化,数据导入/导出以后),才会发生变化。


二三、如何分析ORACLE的执行计划?

在SQL/PLUS的窗口运行以下命令
set   time   on; (说明:打开时间显示)
set   autotrace   on; (说明:打开自动分析统计,并显示SQL语句的运行结果)
set   autotrace   traceonly; (说明:打开自动分析统计,不显示SQL语句的运行结果)

二四、 DB中索引原理,种类,使用索引的好处和问题是什么?

(略)
二五、JVM垃圾回收实现原理。垃圾回收的线程优先级。

进行垃圾回收的线程是一种低优先级线程,在一个Java程序的生命周期中,它只有在内存空闲的时候才有机会

二六、jvm 最大内存设置。设置的原理。结合垃圾回收讲讲。

默认的java虚拟机的大小比较小,在对大数据进行处理时java就会报错:java.lang.OutOfMemoryError。
设置jvm内存的方法,对于单独的.class,可以用下面的方法对Test运行时的jvm内存进行设置。
java -Xms64m -Xmx256m Test
-Xms是设置内存初始化的大小
-Xmx是设置最大能够使用内存的大小(最好不要超过物理内存大小)
在weblogic中,可以在startweblogic.cmd中对每个domain虚拟内存的大小进行设置,默认的设置是在commEnv.cmd里面。

1、了解j2EE规范,选择几点进行重点消化。
2、异常分类,一般性异常和运行期异常,异常捕获。
3、了解spring mvc框架,和struts mvc框架的区别。
4、要对spring和ibatis非常熟悉,必须,熟知。
5、应适当关注需求分析和产品方面的知识。
6、了解多线程相关知识
7、了解java5以及java6新特性

下面简单的列出Java5和Java6的主要新特性。
Java5:

1。泛型 Generics :
   引入泛型之后,允许指定集合里元素的类型,面去了强制类型转换,并得到强类型在编译时刻进行类型检查的好处。
不光是类型安全,Parameterized Type作为参数和返回值,Generic是vararg、annotation、enumeration、collection等功能的基石
a, 类型安全
抛弃List、Map,使用List<String>、Map<Integer, String>
给List、Map添加元素或者使用Iterator<T>遍历时,编译期就可以给你检查出类型错误

b, 方法参数和返回值统统加上Type
抛弃List getStringListFromIntegerList(List list)
使用List<String> getgetStringListFromIntegerList(List<Integer> list)

c, 不再需要类型转换
List<String> l = new ArrayList<String>()
String s = l.get(i)

d, 类型通配符
假设一个打印List<T>中元素的方法printList,我们希望任何类型T的List<T>都可以被打印:
代码
   1. public void printList(List<?> list, PrintStream out) throws IOException { 
   2.   for (Iterator<?> i = list.iterator(); i.hasNext(); ) { 
   3.     out.println(i.next().toString()); 
   4.   } 
   5. } 
类型通配符"?"让我们的printList方法更通用

e, 限制类型参数
如果通配符?让我们的参数类型过于广泛,我们还可以限制一下它:
代码
   1. public void printList(List<? extends Number> list, PrintStream out) throws IOException { 
   2.   for (Iterator<? extends Number> i = list.iterator(); i.hasNext(); ) { 
   3.     out.println(i.next().toString()); 
   4.   } 
   5. } 


2。枚举类型 Enumeration:

3。自动类型包装和解包装(autoboxing & unboxing): 

   听起来很玄,实际上做的事情非常简单,类型自动转换罢了。 
   自动装包:基本类型自动转为包装类.(int >> Integer)
   自动拆包:包装类自动转为基本类型.(Integer >> int)
  Java 1.4
public class program {
  public static void main(String[] args) {     
    int i = 13;
    Integer o = new Integer(i);
   
    Integer x = new Integer(13);
    int y = x.intValue();
  }
}

Java 5
public class program {
  public static void main(String[] args) {    
    // Boxing
    int i = 13;
    Integer o = i;
    
    // UnBoxing
    Integer x = new Integer(13);
    int y = x;
  }
}

4。变长参数 varargs ( variable number of arguments )
    参数类型相同时,把重载函数合并到一起了
    以前是这样:
       public void write(Object obj1)
       public void write(Object obj1,Object obj2)
       public   void   write(Object Obj1,Object obj2,Object obj3)
    现在合在一起只要这样写就行了:  
    public void write(Object... objs) {
for (Object obj: objs)
System.out.println(obj);
   }

5。Annotations
Annotation是Java中的metadata

A, Tiger中预定义的三种标准annotation
a, Override
指出某个method覆盖了superclass的method
当你要覆盖的方法名拼写出错时编译不通过
b, Deprecated
指出某个method或element类型的使用是被阻止的
子类将不能覆盖该方法
c, SupressWarnings
关闭class、method、field/variable初始化的编译期警告
比如没有List没有使用Generic,则@SuppressWarnings("unchecked")将去掉编译期警告,这对将程序移植到JDK1.4有意义

B, 自定义annotation
public @interface Marked {}

C, meta-annotation
或者说annotation的annotation
四种标准的meta-annotation全部定义在java.lang.annotaion包中:
a, Target
指定所定义的annotation可以用在哪些程序单元上
如果Target没有指定,则表示该annotation可以使用在任意程序单元上
代码
   1. @Target({ElementType.ANNOTATION_TYPE, 
   2.          ElementType.CONSTRUCTOR, 
   3.          ElementType.FIELD, 
   4.          ElementType.LOCAL_VARIABLE, 
   5.          ElementType.METHOD, 
   6.          ElementType.PACKAGE, 
   7.          ElementType.PARAMETER, 
   8.          ElementType.TYPE}) 
   9. public @interface TODO {} 


b, Retention
指出Java编译期如何对待annotation
annotation可以被编译期丢掉,或者保留在编译过的class文件中
在annotation被保留时,它也指定是否会在JVM加载class时读取该annotation
代码
   1. @Retention(RetentionPolicy.SOURCE)  // Annotation会被编译期丢弃 
   2. public @interface TODO1 {} 
   3. @Retention(RetentionPolicy.CLASS)   // Annotation保留在class文件中,但会被JVM忽略 
   4. public @interface TODO2 {} 
   5. @Retention(RetentionPolicy.RUNTIME) // Annotation保留在class文件中且会被JVM读取 
   6. public @interface TODO3 {} 


c, Documented
指出被定义的annotation被视为所熟悉的程序单元的公开API之一
被@Documented标注的annotation会在javadoc中显示,这在annotation对它标注的元素被客户端使用时有影响时起作用
d, Inherited
该meta-annotation应用于目标为class的annotation类型上,被此annotattion标注的class会自动继承父类的annotation

D, Annotation的反射
我们发现java.lang.Class有许多与Annotation的反射相关的方法,如getAnnotations、isAnnotationpresent
我们可以利用Annotation反射来做许多事情,比如自定义Annotation来做Model对象验证
代码
   1. @Retention(RetentionPolicy.RUNTIME) 
   2. @Target({ ElementType.FIELD, ElementType.METHOD }) 
   3. public @interface RejectEmpty { 
   4.     /** hint title used in error message */ 
   5.     String value() default ""; 
   6. } 
   7.  
   8. @Retention(RetentionPolicy.RUNTIME) 
   9. @Target( { ElementType.FIELD, ElementType.METHOD }) 
  10. public @interface AcceptInt { 
  11.     int min() default Integer.MIN_VALUE; 
  12.     int max() default Integer.MAX_VALUE; 
  13.     String hint() default ""; 
  14. } 
使用@RejectEmpty和@AcceptInt标注我们的Model的field,然后利用反射来做Model验证

6。新的迭代语句 ( enhanced for loop) for/in
抛弃Iterator吧
代码
  1. for(int n : numbes) {  
  2.   println(n);  
  3. }  
  4.   
  5. for(String s : stringList) {  
  6.   println(s);  
  7. }  
自定义实现Iterable接口或继承现有Collection的类来让你的类可以使用for/in

7。静态引入 static imports
   就是把其它类的静态方法引入,变成自己的方法。
   import static java.lang.Math.*;  
   r = sin(PI * 2); 
   //无需再写r = Math.sin(Math.PI * 2);

  enum元素也可以import
  1. import static java.lang.System.out;  
  2. import static xx.xx.xx.SomeEnum.*; 

8。新的格式化方法 java.util.Formatter
    让你拥有C的printf()风格的字符串格式化
    formatter.format("Remaining account balance: $%.2f", balance); 


9。新的线程模型和并发库 Thread framework

Tiger引进大量全新的并发性功能,更好的支持mutilthread

HashMap的替代者ConcurrentHashMap和ArrayList的替代者CopyOnWriteArrayList让我们用的放心、舒心、省心
在大并发量读取时采用java.util.concurrent包里的一些类会让大家满意

BlockingQueue、Callable、Executor、Semaphore...



Java6:
1。引入了一个支持脚本引擎的新框架
2。UI的增强
3。对Web Service支持的增强(JAX-WS 2.0 和 JAXB 2.0)
4。一系列新的安全相关的增强(本地敏感资源服务 Locale Sensitive Services SPI)
5。JDBC 4.0
6。Compiler API
7。通用的Annotations支持


8、熟悉linux相关命令操作。
9、工厂模式,简单工厂、抽象工厂的区别
10、动态代理模式

Servlet的生命周期:
   
    servlet有良好的生存期的定义,包括如何加载、实例化、初始化、处理客户端请求以及如何被移除。这个生存期由javax.servlet.Servlet接口的init,service和destroy方法表达。

  1、加载和实例化

  容器负责加载和实例化一个servlet。实例化和加载可以发生在引擎启动的时候,也可以推迟到容器需要该servlet为客户请求服务的时候。

  首先容器必须先定位servlet类,在必要的情况下,容器使用通常的Java类加载工具加载该servlet,可能是从本机文件系统,也可以是从远程文件系统甚至其它的网络服务。容器加载servlet类以后,它会实例化该类的一个实例。需要注意的是可能会实例化多个实例,例如一个servlet类因为有不同的初始参数而有多个定义,或者servlet实现SingleThreadModel而导致容器为之生成一个实例池。

  2、初始化

  servlet加载并实例化后,容器必须在它能够处理客户端请求前初始化它。初始化的过程主要是读取永久的配置信息,昂贵资源(例如JDBC连接)以及其它仅仅需要执行一次的任务。通过调用它的init方法并给它传递唯一的一个(每个servlet定义一个)ServletConfig对象完成这个过程。给它传递的这个配置对象允许servlet访问容器的配置信息中的名称-值对(name-value)初始化参数。这个配置对象同时给servlet 提供了访问实现了ServletContext接口的具体对象的方法,该对象描述了servlet的运行环境。

  2.1初始化的错误处理

  在初始化期间,servlet实例可能通过抛出UnavailableException 或者 ServletException异常表明它不能进行有效服务。如果一个servlet抛出一个这样的异常,它将不会被置入有效服务并且应该被容器立即释放。在此情况下destroy方法不会被调用因为初始化没有成功完成。在失败的实例被释放后,容器可能在任何时候实例化一个新的实例,对这个规则的唯一例外是如果失败的servlet抛出的异常是UnavailableException并且该异常指出了最小的无效时间,那么容器就会至少等待该时间指明的时限才会重新试图创建一个新的实例。

  2.2、工具因素

  当工具(注:根据笔者的理解,这个工具可能是应用服务器的某些检查工具,通常是验证应用的合法性和完整性)加载和内省(introspect)一个web应用时,它可能加载和内省该应用中的类,这个行为将触发那些类的静态初始方法被执行,因此,开发者不能假定只要当servlet的init方法被调用后它才处于活动容器运行状态(active container runtime)。作为一个例子,这意味着servlet不能在它的静态(类)初始化方法被调用时试图建立数据库连接或者连接EJB容器。

  3、处理请求

  在servlet被适当地初始化后,容器就可以使用它去处理请求了。每一个请求由ServletRequest类型的对象代表,而servlet使用 ServletResponse回应该请求。这些对象被作为service方法的参数传递给servlet。在HTTP请求的情况下,容器必须提供代表请求和回应的HttpServletRequest和HttpServletResponse的具体实现。需要注意的是容器可能会创建一个servlet实例并将之放入等待服务的状态,但是这个实例在它的生存期中可能根本没有处理过任何请求。

  3.1、多线程问题

  容器可能同时将多个客户端的请求发送给一个实例的service方法,这也就意味着开发者必须确保编写的servlet可以处理并发问题。如果开发者想防止这种缺省的行为,那么他可以让他编写的servlet实现SingleThreadModel。实现这个类可以保证一次只会有一个线程在执行service 方法并且一次性执行完。容器可以通过将请求排队或者维护一个servlet实例池满足这一点。如果servlet是分布式应用的一部分,那么,那么容器可能在该应用分布的每个JVM中都维护一个实例池。如果开发者使用synchronized关键字定义service方法(或者是doGet和 doPost),容器将排队处理请求,这是由底层的java运行时系统要求的。我们强烈推荐开发者不要同步service方法或者HTTPServlet 的诸如doGet和doPost这样的服务方法。

  3.2、处理请求中的异常

  servlet在对请求进行服务的时候有可能抛出ServletException或者UnavailableException异常。ServletException表明在处理请求的过程中发生了错误容器应该使用合适的方法清除该请求。UnavailableException表明servlet不能对请求进行处理,可能是暂时的,也可能是永久的。如果UnavailableException指明是永久性的,那么容器必须将servlet从服务中移除,调用它的destroy方法并释放它的实例。如果指明是暂时的,那么容器可以选择在异常信息里面指明的这个暂时无法服务的时间段里面不向它发送任何请求。在这个时间段里面被被拒绝的请求必须使用SERVICE_UNAVAILABLE (503)返回状态进行响应并且应该携带稍后重试(Retry-After)的响应头表明不能服务只是暂时的。容器也可以选择不对暂时性和永久性的不可用进行区分而全部当作永久性的并移除抛出异常的servlet。

  3.3线程安全

  开发者应该注意容器实现的请求和响应对象(注:即容器实现的HttpServletRequest和HttpServletResponese)没有被保证是线程安全的,这就意味着他们只能在请求处理线程的范围内被使用,这些对象不能被其它执行线程所引用,因为引用的行为是不确定的。

  4、服务结束

  容器没有被要求将一个加载的servlet保存多长时间,因此一个servlet实例可能只在容器中存活了几毫秒,当然也可能是其它更长的任意时间(但是肯定会短于容器的生存期)当容器决定将之移除时(原因可能是保存内存资源或者自己被关闭),那么它必须允许servlet释放它正在使用的任何资源并保存任何永久状态(这个过程通过调用destroy方法达到)。容器在能够调用destroy方法前,它必须允许那些正在service方法中执行的线程执行完或者在服务器定义的一段时间内执行(这个时间段在容器调用destroy之前)。一旦destroy方法被调用,容器就不会再向该实例发送任何请求。如果容器需要再使用该servlet,它必须创建新的实例。destroy方法完成后,容器必须释放servlet实例以便它能够被垃圾回收。

Java中Error与Exception的区别:


Exceptions

1.可以是 可被控制(checked) 或 不可控制的(unchecked)

2.表示一个由程序员导致的错误

3.应该在应用程序级被处理



Errors

1.总是 不可控制的(unchecked)

2.经常用来用于表示系统错误或低层资源的错误

3.如何可能的话,应该在系统级被捕捉

error   表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。 

exception   表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情

进程与线程的区别:


通俗的解释

一个系统运行着很多进程,可以比喻为一条马路上有很多马车
不同的进程可以理解为不同的马车
而同一辆马车可以有很多匹马来拉----这些马就是线程
假设道路的宽度恰好可以通过一辆马车
道路可以认为是临界资源
那么马车成为分配资源的最小单位(进程)
而同一个马车被很多匹马驱动(线程)----即最小的运行单位
每辆马车马匹数>=1
所以马匹数=1的时候进程和线程没有严格界限,只存在一个概念上的区分度
马匹数>1的时候才可以严格区分进程和线程


专业的解释

简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
     线程的划分尺度小于进程,使得多线程程序的并发性高。另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
      线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
      从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
     进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
     线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
     一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.

Java的序列化接口的作用:

Serializable接口,是作为一个标记使用的,因为本身没有任何方法需要实现;
Java内部的序列化机制会检查此接口,如果有这个接口,则序列化它,否则不序列化。
典型的用途是在分布式Java编程里,比如通过RMI或者EJB,需要在网络上传输的对象,一定要实现此接口,否则程序会出错,因为在网络上传递对象需要先序列化它。

使用序列化的目的有一个两个:一个是为了persistent对象,如在Hibernate中要保存的对象必须是序列化的;第二个是为了跨平台传输,消除平台间的差异,如在JMS中,传送的消息对象都必须是序列化的.

Hibernate的三种状态以及表现形式:




objects在hibernate中的生命周期中存在3种状态:transient, persistent, detached。附件1描述的即是hibernate application中objects的生命周期。

通过new操作符生成的object是transient object,此时的object还没有和数据库中的任何数据关联,所以一旦没有被引用,就会被jvm垃圾收集。一旦通过Hibernate 的Persistence manager执行了save()方法或者被其他已经存在的Persistent objects引用,那么object的状态就会从transient转为persistent。

Persistent objects是包含在transactions中的,它们的状态是通过transactions来控制的,  Persistent objects是和数据库中的表对应的,所以表示主键的属性不会为空,也就是说每一个persistent object都会有一个匹配的database identity,除非是通过new产生的新的transient object,此时object的database identity是空的,如果在transaction中对该object执行save()方法,那么在transaction成功结束的时候该 object会在数据库中新增一条对应的记录,其它已经存在的persistent objects会相应的更新数据库中的相应行。

当Hibernate中的Persistence Manager执行close()方法,也就是persistence Manager放弃对persistent objects的控制,那么persistent objects的状态就转为detached objects。这些detached objects可以在未来被新的persistence manager重新控制并使用。这种将object从transaction转向表现层然后又重新包含于新的Transaction的实现是 Hibernate的一个卖点。

在objects存在的三种状态中,处于persistent状态中object的比较是通过该object的database identity来确定的,所以这里需要override equals()来实现。其它状态中的objects就可以简单的通过java的equality来判断即可。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值