面试宝典2018

Java基础部分

1、一个".java"源文件中是否可以包括多个类(不是内部

)?有什么限制?

答:可以有多个类,但只能有一个 public 的类,并且 public 的类名必须与文件名相一致。

2Java 有没有 goto?

答:java 中的保留字,现在没有在 java 中使用。

3、说说&&&的区别。

答:a.&&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为 true , 整个运算结果才为 true,否则,只要有一方为 false,则结果为 false

b.&&还具有短路的功能,即如果第一个表达式为 false,则不再计算第二个表达式

c.&还可以用作位运算符,&操作符两边的表达式不是 boolean 类型时

 

4、在 JAVA 中如何跳出当前的多重嵌套循环?

使用带有标号的 break 语句

 

5switch 语句能否作用在 byte ,能否作用在 long ,能 否作用在 String ?

答:a.byte可以,自动转换。

   b.long不可以

   c.jdk1.7之后String是可以的

   解析:switch后必须:整数表达式或者枚举常量,byte,short,char 都可以隐含转换为 int

6short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1; 有什么错?

答:对于 short s1 = 1; s1 = s1 + 1; 由于 s1+1 运算时会自动提升表达式的类型,所以结果是 int ,再赋值 给 short 类型 s1 ,编译器将报告需要强制转换类型的错误。

对于 short s1 = 1; s1 += 1;由于 += java 语言规定的运算符,java 编译器会对它进行特殊处理,因此 可以正确编译。

7char 型变量中能不能存贮一个中文汉字?为什么?

答、char 型变量是用来存储 Unicode 编码的字符的,unicode 编码字符集中包含了汉字,所以,char 型变量 中当然可以存储汉字。必须是它收录的。

8、用最有效率的方法算出 2 乘以 8 等於几?

答:

2 << 3(左移3位相当于乘以23次方,右移3位相当于除以23次方)。

9、使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

答:使用 final 关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。

10"=="equals 方法究竟有什么区别?

答:==用来比较内存地址的值

   equals用来比较两个独立对象的内容是否相同

11、静态变量和实例变量的区别?

答:

a.静态变量前要加 static 关键字,而实例变量前则不加。

b.静态变量可以直接用类名.也可以用对象.

c.实例变量只能用对象.

d.类的静态变量内存中只有一份

12、是否可以从一个 static 方法内部发出对非 static 方法的 调用?

答:不可以。

13Integer int 的区别

答:int是原始数据类型,Integer是它的包装类。

   包装类有属性和方法,还可以判断是否为空。

14Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

答:round是四舍五入取整。12   11

15、下面的代码有什么不妥之处?

1. if(username.equals(zxx){}

2. int x=1;

   return x==1?true:false;

答:第一题:有可能出现空指针异常

   第二题:永远都是true

16、请说出作用域 public,private,protected,以及不写时的区别

答:a.它们是访问修饰符

   b.public可以跨包访问

     protected可以跨包访问必须是其子类

 不写  同包访问

 private 同类访问

 

17Overload Override 的区别。Overloaded 的方法是否 可以改变返回值的类型?

答:

a.Overload方法重载,Override方法重写

b.方法重载指的是同名不同参,方法名相同,参数不同(参数个数,参数类型,参数顺序).不一定有继承关系。

c.方法重写指的是同名又同参,返回类型也要相同。必须存在继承中。

d.方法重载时,返回类型可以不同。

 

18、构造器 Constructor 是否可被 override?

答:构造方法不可以被重写,因为构造方法不能被继承,但可以被重载。

 

19、接口是否可继承接口? 抽象类是否可实现(implements) 接口? 抽象类是否可继承具体类(concrete class)? 抽象类中 是否可以有静态的main方法?

答: 接口可以继承接口,抽象类可以实现接口,抽象类中可以有静态的main方法。

20、写 clone()方法时,通常都有一行代码,是什么?

答:

super.clone();

因为首先要把父类中的成员复制到位,然后才是复制自己的成员。

 

21、面向对象的特征有哪些方面

答: 面向对象的编程语言有封装、继承 、多态、抽象等 4 个主要的特征。

 

22java 中实现多态的机制是什么?

答: 父类的引用指向子类的对象。程序调用方法在运行期才动态绑定。

23abstract class interface 有什么区别?

答:

a.含有 abstract 修饰符的 class 即为抽象类,abstract 类不能创建的实例对象。

b.抽象类可以有构造方法,接口中不能有构造方法。

c.抽象类中可以有普通成员变量,接口中只有静态常量。

d.抽象类中可以包含非抽象的方法,接口中的方法只能是抽象的。

e.接口中的抽象方法只能是 public 类型的

f.接口中不能有静态方法

g.一个类可以实现多个接口,但只能继承一个抽象类。接口可以继承多个接口。

 

24abstract method 是否可同时是 static,是否可同时是 native,是否可同时是 synchronized?

答:

a.abstract method 不可同时是 static

b.abstract method 不可同时是 native

c.abstract method 不可同时是 synchronized

 

 

25、什么是内部类?Static Nested Class Inner Class 的不 同。

答:Static Nested Class是静态嵌套类,Inner Class是内部类。

a.内部类就是在一个类的内部定义的类,内部类中不能定义静态成员

b.在方法外部定义的内部类前面可以加上 static 关键字,从而成为 Static Nested Class,它脱离了类的实例,内部类必须先创建实例。

 

26、内部类可以引用它的包含类的成员吗?有没有什么限制?

答:

a.如果不是静态内部类,那没有什么限制

b.静态内部类不能访问外部类的成员

 

27Anonymous Inner Class (匿名内部类) 是否可以 extends(继承)其它类,是否可以 implements(实 现)interface(接口)?

 

答:匿名内部类可以继承其他类或实现其他接口。

28super.getClass()方法调用

下面程序的输出结果是多少?

import java.util.Date;

public class Test extends Date{

public static void main(String[] args) { new Test().test();

}

public void test(){ System.out.println(super.getClass().getName());

} }

答案是Test,因为getClass()Object 类中定义成了 final,

子类不能覆盖该方法.

补充:getClass().getSuperClass().getName();得到父类名

29String 是最基本的数据类型吗?

答:

它不是基本数据类型,它是引用数据类型。

java.lang.String 类是 final 类型的,因此不可以继承这个类、不能修改这个类。

30String s = "Hello";s = s + " world!";这两行代码执行后,

原始的 String 对象中的内容到底变了没有?

答:没有。

31、是否可以继承 String ?

答:String 类是 final 类故不可以继承。

 

32String s = new String("xyz");创建了几个 String Object? 二者之间有什么区别?

答:两个或一个,xyz”对应一个对象,这个对象放在字符串常量缓冲区,常量”xyz”不管出现 多少遍,都是缓冲区中的那一个。new String 每写一遍,就创建一个新的对象,它一句那个常 量”xyz”对象的内容来创建出一个新 String 对象。如果以前就用过’xyz,这句代表就不会创 建”xyz”自己了,直接从缓冲区拿。

 

  1、栈区(stack)—   由编译器自动分配释放   ,存放函数的参数值,局部变量的值等。其  

  操作方式类似于数据结构中的栈。  

  2、堆区(heap)   —   一般由程序员分配释放,   若程序员不释放,程序结束时可能由OS回  

     。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。  

  3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的  

  全局变量和静态变量在一块区域,   未初始化的全局变量和未初始化的静态变量在相邻的另  

  一块区域。   -   程序结束后由系统释放。  

  4、文字常量区   —常量字符串就是放在这里的。   程序结束后由系统释放  

  5、程序代码区—存放函数体的二进制代码。  

 

 

33String StringBuffer 的区别

答:

a.它们可以储存和操作字符串

b.String 类提供了数值不可改变的字符串。而这个 StringBuffer 类提供 的字符串进行修改。

c.String 覆盖了 equals 方法和 hashCode 方法,StringBuffer 没有覆盖 equals 方法和 hashCode 方法,所以,StringBuffer 对象存储进 Java 集合类中时会出现问题。

 

34、如何把一段逗号分割的字符串转换成一个数组?

答:有两种

a. 字符串.split(,);

b. StingTokenizer

StringTokenizer tokener = new StringTokenizer("a,b,c", ",");

String[] result = new String[tokener.countTokens()];

int i = 0;

while (tokener.hasMoreElements()) {

result[i++] = tokener.nextToken();

}

 

35、数组有没有 length()这个方法? String 有没有 length()这 个方法?

答:数组没有 length()这个方法,length 的属性。String 有有 length()这个方法。

 

36、下面这条语句一共创建了多少个对象:String s="a"+"b"+"c"+"d";

答:只创建了一个 String 对象

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

 

答:会执行,在方法返回调用者前执行。return前。

38final, finally, finalize 的区别。

答:

a.final修饰类,此类不能被继承,final修饰方法,此方法不能被重写,final修饰变量变常量。

b.finally 是异常处理语句结构的一部分,表示总是执行,作用是释放资源。

c.finalize Object 类的一个方法.在垃圾收集器执行的时候会调用被回收对象的此方法.

39、运行时异常与一般异常有何异同?

答:

a.异常表示程序运行过程中可能出现的非正常状态

b.运行时异常表示虚拟机的通常操作中可能 遇到的异常,是一种常见运行错误。

c.java 编译器要求方法必须声明抛出可能发生的非运行时 异常,但是并不要求必须声明抛出未被捕获的运行时异常。

40error exception 有什么区别?

答:

a.error 表示恢复不是不可能但很困难的情况下的一种严重问题。一般指jvm出现的问题。

(比如说内存溢出。不可能指望程序能处理这样的情况)

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

41Java 中的异常处理机制的简单原理和应用。

答:

Java 所有异常的根类为 java.lang.Throwable,它有两个子类errorException

a.虚拟机死机的错误,这是Error.

b.程序可以死掉也可以不死掉的错误,Exception.

c.程序不应该死掉的错误;try..catch throws

d.数组脚本越界(ArrayIndexOutOfBoundsException),空指针异常 (NullPointerException)、类转换异常(ClassCastException),文件读写异常IOException,数字转换异常NumberFormatException;

42、请写出你最常见到的 5 runtime exception

ArrayIndexOutOfBoundsException 数组下标越界

ClassNotFoundException 类没有找到

EFOException 文档末尾异常

NullPointerException空指针异常

IOException文件读写异常

43JAVA 语言如何进行异常处理,关键字: throws,throw,try,catch,finally 分别代表什么意义?try 块 中可以抛出异常吗?

答:

a.Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。

b.Java中,每个异常都是一个对象,它是Throwable类或其子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并可以对其进行处理。

c.Java的异常处理是通过5个关键词来实现的:trycatchthrowthrowsfinally。一般情况下是用try来执行一段程序,如果系统会抛出(throw)一个异常对象,可以通过它的类型来捕获(catch)它,或通过总是执行代码块(finally)来处理;

try用来指定一块预防所有异常的程序;

catch子句紧跟在try块后面,用来指定你想要捕获的异常的类型;

throw语句用来明确地抛出一个异常;

throws用来声明一个方法可能抛出的各种异常(当然声明异常时允许无病呻吟);

finally为确保一段代码不管发生什么异常状况都要被执行;

 

try语句可以嵌套,每当遇到一个try语句,异常的结构就会被放入异常栈中,直到所有的try语句都完成。如果下一级的try语句没有对某种异常进行处理,异常栈就会执行出栈操作,直到遇到有处理这种异常的try语句或者最终将异常抛给JVM

d.try 块 中可以抛出异常.

44java中有几种方法可以实现一个线程?用什么关键字修 饰同步方法? stop()suspend()方法为何不推荐使用?

答:

a.Java 5以前实现多线程有两种实现方法:一种是继承Thread类;另一种是实现Runnable接口。两种方式都要通过重写run()方法来定义线程的行为,推荐使用后者,因为Java中的继承是单继承,一个类有一个父类,如果继承了Thread类就无法再继承其他类了,显然使用Runnable接口更为灵活。Java 5以后创建线程还有第三种方式:实现Callable接口,该接口中的call方法可以在线程执行结束时产生一个返回值。

b.synchronized关键字修饰同步方法

c.stop()它不安全,suspend()方法容易发生死锁

45sleep() wait() 有什么区别?

sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;

② 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;

sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;

sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。

 

46、同步和异步有何异同,在什么情况下分别使用他们?举 例说明。

答:

a.如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数

据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。

b.当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。

47、多线程有几种实现方法?同步有几种实现方法?

答:

a.分别是继承 Thread ,实现 Runnable 接口,实现Callable接口

b.分别是 synchronized,waitnotify

48、启动一个线程是用 run()还是 start()?

答:启动一个线程是调用 start()方法,使线程就绪状态,以后可以被调度为运行状态。

49、当一个线程进入一个对象的一个 synchronized 方法后, 其它线程是否可进入此对象的其它方法?

答:

a.其他方法前是否加了 synchronized 关键字,如果没加,则能。

b.如果这个方法内部调用了 wait,则可以进入其他 synchronized 方法。

c..如果其他个方法都加了 synchronized 关键字,并且内部没有调用 wait,则不能。

d.如果其他方法是 static,它用的同步锁是当前类的字节码,与非静态的方法不能 同步,因为非静态的方法用的是 this

50、线程的基本概念、线程的基本状态以及状态之间的关系

答:

a.一个程序中可以有多条执行线索同时执行,一个线程就是程序中的一条执行线索,每个 线程上都关联有要执行的代码,即可以有多段程序代码同时运行,每个程序至少都有 一个线程,main 方法执行的那个线程。

b.状态:就绪(ready),运行(run), 阻塞(synchronize),等待(wait) 和 休眠(sleep),挂起(resume),结束(end)wait 必须在 synchronized 内部调用。

c.调用线程的 start 方法后线程进入就绪状态,线程调度系统将就绪状态的线程转为运行状态,遇到 synchronized 语句时,由运行状态转为阻塞,synchronized 获得锁后, 由阻塞转为运行,在这种情况可以调用 wait 方法转为挂起状态,当线程关联的代码执 行完后,线程变为结束状态。

 

51、简述 synchronized java.util.concurrent.locks.Lock 的 异同 ?

答:

a.主要相同点:Lock 能完成 synchronized 所实现的所有功能

b.主要不同点:

Lock 有比 synchronized 更精确的线程语义和更好的性能。

synchronized 会自动释放锁,

Lock 一定要求程序员手工释放,并且必须在 finally 从句中释放。

Lock还有更强大的功能,例如,它的 tryLock 方法可以非阻塞方式去拿锁。

 

52、设计 4 个线程,其中两个线程每次对 j 增加 1,另外两 个线程对 j 每次减少 1。写出程序。

(可以放弃)

public class ThreadTest1

{

private int j;

public static void main(String args[]){ ThreadTest1 tt=new ThreadTest1(); Inc inc=tt.new Inc();

Dec dec=tt.new Dec();

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

Thread t=new Thread(inc); t.start();

t=new Thread(dec); t.start();

}

}

private synchronized void inc(){

j++; System.out.println(Thread.currentThread().getName()+"-inc:"+j); }

 private synchronized void dec(){ j--;

System.out.println(Thread.currentThread().getName()+"-dec:"+j);

}

class Inc implements Runnable{

public void run(){

for(int i=0;i<100;i++){ inc();

}

} }

class Dec implements Runnable{ public void run(){

for(int i=0;i<100;i++){ dec();

}

} }

}

----------随手再写的一个------------- class A

{

JManger j =new JManager();

main() {

new A().call(); }

void call {

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

new Thread(

new Runnable(){ public void run(){while(true){j.accumulate()}}}

).start();

new Thread(new Runnable(){ public void run(){while(true){j.sub()}}}).start(); }

} }

class JManager {

private j = 0;

public synchronized void subtract() {

j-- }

public synchronized void accumulate() {

j++; }

}

53、介绍 Collection 框架的结构

答:

Collection的实现类是AbstractList

List,Set,Vector的父类AbstractList

ListLinkedListArrayList

SetHashSetTreeSet

Vector是线程安全的

54Collection 框架中实现比较要实现什么接口

答:comparable/comparator

55ArrayList Vector 的区别

答:

a.这两个类都实现了 List 接口

b.他们都是有序集合,元素可重复

c.Vector 是线程安全的,也就是说是它的方法之间是线程同步的.

ArrayList 是线程序 不安全的,它的方法之间是线程不同步的

d.              初始容量   加载因子  扩容增量  扩容后长度

ArrayList   10              0.5           0.5+1    16

Vector        10             1              1                20

 

56HashMap Hashtable 的区别

答:

a.都实现了Map接口

b.HashMap允许空(null),(null),非线程安全,效率要高于 Hashtable

c.Hashtable不允许空(null),(null)值,线程安全,也就是说是同步的。

57List Map 区别?

答:

a. List是存储单列数据的集合, Map是存储键和值这样的双列数据的集合,

b.List 中存储的数 据是有顺序,并且允许重复;

c.Map 中存储的数据是没有顺序的,其键是不能重复的,它的 值是可以有重复的。

 

58ListMapSet 三个接口,存取元素时,各有什么特点?

答:

存元素时:

List有序可重复

Set无序不可重复

Map键值对存

取元素时:

      Listget

      SetIterator

      Mapkey

59、说出 ArrayList,Vector, LinkedList 的存储性能和特性

答:

 

a.ArrayList Vector 都是使用数组方式存储数据

b.Vector 由于使用了 synchronized 方法(线程安全), 通常性能上较 ArrayList ,

c.LinkedList 使用双向链表实现存储,增删改操作优于ArrayList,

查找操作中ArrayList优于LinkedList

详细说明:

       List以特定索引来存取元素,可以有重复元素。Set不能存放重复元素(用对象的equals()方法来区分元素是否重复)。Map保存键值对(key-value pair)映射,映射关系可以是一对一或多对一。SetMap容器都有基于哈希存储和排序树的两种实现版本,基于哈希存储的版本理论存取时间复杂度为O(1),而基于排序树版本的实现在插入或删除元素时会按照元素或元素的键(key)构成排序树从而达到排序和去重的效果。

 

60、去掉一个 Vector 集合中重复的元素

答:

第一种:contains方法

第二种:HashSet set = new HashSet(vector);

61Collection Collections 的区别。

答:

a.Collection是集合类接口,继承与他的接口主要有 Set List.

b.Collections是集合类的一个帮助类,供一系列静态方法实现对各种集合的搜索、排 序、线程安全化等操作。

62Set 里的元素是不能重复的,那么用什么方法来区分重 复与否呢? 是用==还是 equals()? 它们有何区别?

答:

a.equals()可以

==比较内存地址的值

equals()不同对象的内容是否相等

63、你所知道的集合类都有哪些?主要方法?

答:

a.最常用的集合类是 List Map

List 的具体实现包括 ArrayList Vector,

它们是 可变大小的列表,比较适合构建、存储和操作任何类型对象的元素列表。

 List 适用 于按数值索引访问元素的情形。

Map  供了一个更通用的元素存储方法。

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

64、两个对象值相同(x.equals(y) == true),但却可有不同的 hash code,这句话对不对?

答:

也对也不对。

a.如果此对象重写了equals方法,那么可能出现这两个对象的equals相同,而hashcode不同。

b.如果对象要保存在 HashSet HashMap ,它们的 equals 相等,那么,它们的 hashcode 值 就必须相等。

c.如果不是要保存在 HashSet HashMap,则与 hashcode 没有什么关系了,这时候 hashcode 不等是可以的,例如 arrayList 存储的对象就不用实现 hashcode,当然,我们没有理由不实现,通常都会去实现的。

 

65TreeSet 里面放对象,如果同时放入了父类和子类的实 例对象,那比较时使用的是父类的 compareTo 方法,还是使 用的子类的 compareTo 方法,还是抛异常!

答:当前的 add 方法放入的是哪个对象,就调用哪个对象 的 compareTo 方法

66、说出一些常用的类,,接口,请各举 5

答:

a.常用的类:BufferedReader BufferedWriter FileReader FileWirter String Integer

java.util.Date,System,Class,List,HashMap

b.常用的包:java.lang java.io java.util

java.sql ,javax.servlet,org.apache.strtuts.action,org.hibernate

c.常用的接口:Remote List Map Document

NodeList ,Servlet,HttpServletRequest,HttpServletResponse,Transaction(Hibernate)Session(Hibernate),HttpSession

67java 中有几种类型的流?JDK 为每种类型的流 供了一 些抽象类以供继承,请说出他们分别是哪些类?

答:

字节流,字符流。

字节流继承于 InputStream OutputStream,

字符流继承于 InputStreamReader OutputStreamWriter

java.io 包中还有许多其他的流,主要是为了高性能和使用方便。

 

68、字节流与字符流的区别

答:

a.字节流继承于InputStreamOutputStream,字符流继承于ReaderWriter

b.字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,

而字节流处理单元为1个字节,操作字节和字节数组。

c.字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串

d.字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以

 

69、什么是 java 序列化,如何实现 java 序列化?或者请解 释 Serializable 接口的作用。

答:

a.java 序列化:将对象转换成二进制,目的是网络上进行传输。

b.实现Serializable 接口

c.该接口是一个 mini 接口,其中没有需要实现的方法,

implements Serializable 只是为了标注该对象是可被序列化的。

另一种:

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决对象流读写操作时可能引发的问题(如果不进行序列化可能会存在数据乱序的问题)。

要实现序列化,需要让一个类实现Serializable接口,该接口是一个标识性接口,标注该类对象是可被序列化的,然后使用一个输出流来构造一个对象输出流并通过writeObject(Object)方法就可以将实现对象写出(即保存其状态);如果需要反序列化则可以用一个输入流建立对象输入流,然后通过readObject方法从流中读取对象。序列化除了能够实现对象的持久化之外,还能够用于对象的深度克隆。

 

问:如何实现对象克隆?

答:有两种方式:

  1). 实现Cloneable接口并重写Object类中的clone()方法;

  2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的

 

70、 述一下 JVM 加载 class 文件的原理机制?

答:

a.装载:查找和导入class文件;

b.连接:

      (1)检查:检查载入的class文件数据的正确性;

      (2)准备:为类的静态变量分配存储空间;

      (3)解析:将符号引用转换成直接引用(这一步是可选的)

c.初始化:初始化静态变量,静态代码块。

这样的过程在程序调用类的静态成员的时候开始执行,

所以静态方法main()才会成为一般程序的入口方法。类的构造器也会引发该动作。

71heap stack 有什么区别。

答:

a.java 的内存分为两类,一类是栈内存,一类是堆内存。

b.栈内存是指程序进入一个方法时, 会为这个方法单独分配一块私属存储空间,用于存储这个方法内部的局部变量,当这 个方法结束时,分配给这个方法的栈会释放,这个栈中的变量也将随之释放。

c.堆是与栈作用不同的内存,一般用于存放不放在当前方法栈中的那些数据,例如,使用 new 创建的对象都放在堆里,所以,它不会随方法的结束而消失。方法中的局部变量 使用 final 修饰后,放在堆中,而不是栈中。

扩展知识:

String str = new String("hello");

上面的语句中变量str放在栈上,用new创建出来的字符串对象放在堆上,而"hello"这个字面量放在静态区。

 

72GC 是什么? 为什么要有 GC?

答:

a.GC是垃圾收集的意思(Gabage Collection),

b.内存处理是编程人员容易出现问题的地方, 忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,

c.Java  供的 GC 功能 可以自动监测对象是否超过作用域从而达到自动回收内存的目的,

d.Java 语言没有 供 释放已分配内存的显示操作方法。

 

73、垃圾回收的优点和原理。并考虑 2 种回收机制。

答:

a.java语言最显著的特点就是引入了垃圾回收机制,它使java程序员在编写程序时不再考虑内存管理的问题。

b.由于有这个垃圾回收机制,java中的对象不再有“作用域”的概念,只有引用的对象才有“作用域”。

c.垃圾回收机制有效的防止了内存泄露,可以有效的使用可使用的内存。

d.垃圾回收器通常作为一个单独的低级别的线程运行,在不可预知的情况下对内存堆中已经死亡的或很长时间没有用过的对象进行清除和回收。

f.程序员不能实时的对某个对象或所有对象调用垃圾回收器进行垃圾回收。

g.垃圾回收机制有分代复制垃圾回收、标记垃圾回收、增量垃圾回收。

 

 

74、垃圾回收器的基本原理是什么?垃圾回收器可以马上回 收内存吗?有什么办法主动通知虚拟机进行垃圾回收?

答:

a.对于 GC 来说,当程序员创建对象时,GC 就开始监控这个对象的地址、大小以及使用 情况。通常,GC 采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式 确定哪些对象是"可达的",哪些对象是"不可达的"。当 GC 确定一些对象为"不可达" ,GC 就有责任回收这些内存空间。

b.可以。

c.程序员可以手动执行 System.gc(),通知 GC 运行,但是 Java 语言规范并不保证 GC 一定会执行。

75、什么时候用 assert(断言)

答:

a.assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。

b.在实现中,assertion 就是在程序中的一条语句,它对一个 boolean 表达式进行检查,一个正 确程序必须保证这个 boolean 表达式的值为 true;如果该值为 false,说明程序已经处于不正确的状态下,assert 将给出警告或退出。

c.一般来说,assertion 用于保证程序最基本、关键的正确性。assertion 检查通常在开发和测试时开启。为了高性能,在软件发布后, assertion 检查通常是关闭的。

76java 中会存在内存泄漏吗,请简单述。

答:

a.所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。java 中有垃圾 回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动被 垃圾回收器从内存中清除掉。

b.理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个重要原因)

c.然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生。

例如hibernateSession(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露。

 

 

77、能不能自己写个类,也叫 java.lang.String?

答:

a.可以,但在应用的时候,需要用自己定义全类名加载,否则,系统的类加载器永远只是去 加载jre.jar包中的那个java.lang.String

 

78、数据类型之间的转换:

- 如何将字符串转换为基本数据类型?

- 如何将基本数据类型转换为字符串?

答:

a. 调用基本数据类型对应的包装类中的方法parseXXX(String)valueOf(String)即可返回相应基本类型;

b. 一种方法是将基本数据类型与空字符串("")连接(+)即可获得其所对应的字符串;

    另一种方法是调用String 类中的valueOf()方法返回相应字符串

79、如何实现字符串的反转及替换?

 

 public static String reverse(String originStr) {

        if(originStr == null || originStr.length() <= 1)

            return originStr;

        return reverse(originStr.substring(1)) + originStr.charAt(0);

    }

 

80、怎样将GB2312(简体中文)编码的字符串转换为ISO-8859-1编码的字符串?

答:代码如下所示:

String s1 = "你好";

String s2 = new String(s1.getBytes("GB2312"), "ISO-8859-1");

 

81、日期和时间:

- 如何取得年月日、小时分钟秒?

- 如何取得从197011000秒到现在的毫秒数?

- 如何取得某月的最后一天?

- 如何格式化日期?

答:

创建java.util.Calendar 实例,调用其get()方法传入不同的参数即可获得参数所对应的值。

Java 8中可以使用java.time.LocalDateTimel来获取

public class DateTimeTest {

    public static void main(String[] args) {

        Calendar cal = Calendar.getInstance();

        System.out.println(cal.get(Calendar.YEAR));

        System.out.println(cal.get(Calendar.MONTH));    // 0 - 11

        System.out.println(cal.get(Calendar.DATE));

        System.out.println(cal.get(Calendar.HOUR_OF_DAY));

        System.out.println(cal.get(Calendar.MINUTE));

        System.out.println(cal.get(Calendar.SECOND));

 

        // Java 8

        LocalDateTime dt = LocalDateTime.now();

        System.out.println(dt.getYear());

        System.out.println(dt.getMonthValue());     // 1 - 12

        System.out.println(dt.getDayOfMonth());

        System.out.println(dt.getHour());

        System.out.println(dt.getMinute());

        System.out.println(dt.getSecond());

    }

}

问题2:以下方法均可获得该毫秒数。

 

Calendar.getInstance().getTimeInMillis();

System.currentTimeMillis();

Clock.systemDefaultZone().millis(); // Java 8

问题3:代码如下所示。

 

Calendar time = Calendar.getInstance();

time.getActualMaximum(Calendar.DAY_OF_MONTH);

问题4:利用java.text.DataFormat 的子类(如SimpleDateFormat类)中的format(Date)方法可将日期格式化。Java 8中可以用java.time.format.DateTimeFormatter来格式化时间日期,代码如下所示。

 

import java.text.SimpleDateFormat;

import java.time.LocalDate;

import java.time.format.DateTimeFormatter;

import java.util.Date;

 

class DateFormatTest {

 

    public static void main(String[] args) {

        SimpleDateFormat oldFormatter = new SimpleDateFormat("yyyy/MM/dd");

        Date date1 = new Date();

        System.out.println(oldFormatter.format(date1));

 

        // Java 8

        DateTimeFormatter newFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");

        LocalDate date2 = LocalDate.now();

        System.out.println(date2.format(newFormatter));

    }

}

补充:Java的时间日期API一直以来都是被诟病的东西,为了解决这一问题,Java 8中引入了新的时间日期API,其中包括LocalDateLocalTimeLocalDateTimeClockInstant等类,这些的类的设计都使用了不变模式,因此是线程安全的设计。如果不理解这些内容,可以参考我的另一篇文章《关于Java并发编程的总结和思考》。

 

82、打印昨天的当前时刻。

import java.util.Calendar;

 

class YesterdayCurrent {

    public static void main(String[] args){

        Calendar cal = Calendar.getInstance();

        cal.add(Calendar.DATE, -1);

        System.out.println(cal.getTime());

    }

}

Java 8中,可以用下面的代码实现相同的功能。

 

import java.time.LocalDateTime;

 

class YesterdayCurrent {

 

    public static void main(String[] args) {

        LocalDateTime today = LocalDateTime.now();

        LocalDateTime yesterday = today.minusDays(1);

 

        System.out.println(yesterday);

    }

}

 

83、比较一下JavaJavaSciprt

答:

a.JavaScript Java是两个公司开发的不同的两个产品。

b.JavaScript静态语言,Java是动态语言

 

84、类ExampleA继承Exception,类ExampleB继承ExampleA

有如下代码片断:

 

try {

    throw new ExampleB("b")

} catchExampleA e{

    System.out.println("ExampleA");

} catchException e{

    System.out.println("Exception");

}

请问执行此段代码的输出是什么?

答:输出:ExampleA。(根据里氏代换原则[能使用父类型的地方一定能使用子类型],抓取ExampleA类型异常的catch块能够抓住try块中抛出的ExampleB类型的异常)

 

面试题 - 说出下面代码的运行结果。(此题的出处是《Java编程思想》一书)

class Annoyance extends Exception {}

class Sneeze extends Annoyance {}

 

class Human {

 

    public static void main(String[] args)

        throws Exception {

        try {

            try {

                throw new Sneeze();

            }

            catch ( Annoyance a ) {

                System.out.println("Caught Annoyance");

                throw a;

            }

        }

        catch ( Sneeze s ) {

            System.out.println("Caught Sneeze");

            return ;

        }

        finally {

            System.out.println("Hello World!");

        }

    }

}

 

85TreeMapTreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素?

答:TreeSet要求存放的对象所属的类必须实现Comparable接口,该接口提供了比较元素的compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap要求存放的键值对映射的键必须实现Comparable接口从而根据键对元素进行排序。Collections工具类的sort方法有两种重载的形式,第一种要求传入的待排序容器中存放的对象比较实现Comparable接口以实现元素的比较;第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator接口的子类型(需要重写compare方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java中对函数式编程的支持)。

例子1

 

 

public class Student implements Comparable<Student> {

    private String name;        // 姓名

    private int age;            // 年龄

 

    public Student(String name, int age) {

        this.name = name;

        this.age = age;

    }

 

    @Override

    public String toString() {

        return "Student [name=" + name + ", age=" + age + "]";

    }

 

    @Override

    public int compareTo(Student o) {

        return this.age - o.age; // 比较年龄(年龄的升序)

    }

 

}

import java.util.Set;

import java.util.TreeSet;

 

class Test01 {

 

    public static void main(String[] args) {

        Set<Student> set = new TreeSet<>();     // Java 7的钻石语法(构造器后面的尖括号中不需要写类型)

        set.add(new Student("Hao LUO", 33));

        set.add(new Student("XJ WANG", 32));

        set.add(new Student("Bruce LEE", 60));

        set.add(new Student("Bob YANG", 22));

 

        for(Student stu : set) {

            System.out.println(stu);

        }

//      输出结果:

//      Student [name=Bob YANG, age=22]

//      Student [name=XJ WANG, age=32]

//      Student [name=Hao LUO, age=33]

//      Student [name=Bruce LEE, age=60]

    }

}

 

例子2

 

public class Student {

    private String name;    // 姓名

    private int age;        // 年龄

 

    public Student(String name, int age) {

        this.name = name;

        this.age = age;

    }

 

    /**

     * 获取学生姓名

     */

    public String getName() {

        return name;

    }

 

    /**

     * 获取学生年龄

     */

    public int getAge() {

        return age;

    }

 

    @Override

    public String toString() {

        return "Student [name=" + name + ", age=" + age + "]";

    }

 

}

import java.util.ArrayList;

import java.util.Collections;

import java.util.Comparator;

import java.util.List;

 

class Test02 {

 

    public static void main(String[] args) {

        List<Student> list = new ArrayList<>();     // Java 7的钻石语法(构造器后面的尖括号中不需要写类型)

        list.add(new Student("Hao LUO", 33));

        list.add(new Student("XJ WANG", 32));

        list.add(new Student("Bruce LEE", 60));

        list.add(new Student("Bob YANG", 22));

 

        // 通过sort方法的第二个参数传入一个Comparator接口对象

        // 相当于是传入一个比较对象大小的算法到sort方法中

        // 由于Java中没有函数指针、仿函数、委托这样的概念

        // 因此要将一个算法传入一个方法中唯一的选择就是通过接口回调

        Collections.sort(list, new Comparator<Student> () {

 

            @Override

            public int compare(Student o1, Student o2) {

                return o1.getName().compareTo(o2.getName());    // 比较学生姓名

            }

        });

 

        for(Student stu : list) {

            System.out.println(stu);

        }

//      输出结果:

//      Student [name=Bob YANG, age=22]

//      Student [name=Bruce LEE, age=60]

//      Student [name=Hao LUO, age=33]

//      Student [name=XJ WANG, age=32]

    }

}

 

86、什么是线程池(thread pool)?

答:线程池顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。

87XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式?

答:

a.XML文档定义分为DTDSchema两种形式

b.Schema本身也是一个XML文件,可以被XML解析器解析,而且可以为XML承载的数据定义类型,约束能力较之DTD更强大。

c.dom/dom4j/sax/jdom/pull/StAX

88、你在项目中哪些地方用到了XML

答:

a.数据交互和信息配置,聚合数据大部分接口提供xmljson格式,ssh/ssm框架整合配置。

b.数据交互已经被JSON取代。

 

89、阐述JDBC操作数据库的步骤。

答:

加载驱动、创建连接、创建sql语句、执行sql语句、处理结果、关闭资源(先关近再关远)

 

90StatementPreparedStatement有什么区别?哪个性能更好?

答:与Statement相比,

PreparedStatement接口代表预编译的语句,它主要的优势在于可以减少SQL的编译错误并增加SQL的安全性(减少SQL注射攻击的可能性);

PreparedStatement中的SQL语句是可以带参数的,避免了用字符串连接拼接SQL语句的麻烦和不安全;

③当批量处理SQL或频繁执行相同的查询时,PreparedStatement有明显的性能上的优势,由于数据库可以将编译优化后的SQL语句缓存起来,下次执行相同结构的语句时就会很快(不用再次编译和生成执行计划)。

91、使用JDBC操作数据库时,如何提升读取数据的性能?如何提升更新数据的性能?

答:

a.要提升读取数据的性能,可以指定通过结果集(ResultSet)对象的setFetchSize()方法指定每次抓取的记录数(典型的空间换时间策略);

b.要提升更新数据的性能可以使用PreparedStatement语句构建批处理,将若干SQL语句置于一个批处理中执行。

 

92、在进行数据库编程时,连接池有什么作用?

答:

a.由于创建连接和释放连接都有很大的开销(尤其是数据库服务器不在本地时,每次建立连接都需要进行TCP的三次握手,释放连接需要进行TCP四次握手,造成的开销是不可忽视的),

b.为了提升系统访问数据库的性能,可以事先创建若干连接置于连接池中,需要时直接从连接池获取,使用结束时归还连接池而不必关闭连接,从而避免频繁创建和释放连接所造成的开销,这是典型的用空间换取时间的策略(浪费了空间存储连接,但节省了创建和释放连接的时间)。

c.池化技术在Java开发中是很常见的,在使用线程时创建线程池的道理与此相同。基于Java的开源数据库连接池主要有:C3P0ProxoolDBCPBoneCPDruid等。

 

93、什么是DAO模式?

答:

a.DAOData Access Object)顾名思义是一个为数据库或其他持久化机制提供了抽象接口的对象,在不暴露底层持久化方案实现细节的前提下提供了各种数据访问操作。

b.在实际的开发中,应该将所有对数据源的访问操作进行抽象化后封装在一个公共API中。用程序设计语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口,在逻辑上该类对应一个特定的数据存储。

c.DAO模式实际上包含了两个模式,一是Data Accessor(数据访问器),二是Data Object(数据对象),前者要解决如何访问数据的问题,而后者要解决的是如何用对象封装数据。

 

94、事务的ACID是指什么?

 

答:

- 原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败;

- 一致性(Consistent):事务结束后系统状态是一致的;

- 隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;

- 持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。通过日志和同步备份可以在故障发生后重建数据。

 

补充:关于事务,在面试中被问到的概率是很高的,可以问的问题也是很多的。首先需要知道的是,只有存在并发数据访问时才需要事务。当多个事务访问同一数据时,可能会存在5类问题,包括3类数据读取问题(脏读、不可重复读和幻读)和2类数据更新问题(第1类丢失更新和第2类丢失更新)。

脏读(Dirty Read):A事务读取B事务尚未提交的数据并在此基础上操作,而B事务执行回滚,那么A读取到的数据就是脏数据。

 

时间 转账事务A 取款事务B

T1 开始事务

T2 开始事务

T3 查询账户余额为1000

T4 取出500元余额修改为500

T5 查询账户余额为500元(脏读)

T6 撤销事务余额恢复为1000

T7 汇入100元把余额修改为600

T8 提交事务

不可重复读(Unrepeatable Read):事务A重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务B修改过了。

 

时间 转账事务A 取款事务B

T1 开始事务

T2 开始事务

T3 查询账户余额为1000

T4 查询账户余额为1000

T5 取出100元修改余额为900

T6 提交事务

T7 查询账户余额为900元(不可重复读)

幻读(Phantom Read):事务A重新执行一个查询,返回一系列符合查询条件的行,发现其中插入了被事务B提交的行。

 

时间 统计金额事务A 转账事务B

T1 开始事务

T2 开始事务

T3 统计总存款为10000

T4 新增一个存款账户存入100

T5 提交事务

T6 再次统计总存款为10100元(幻读)

1类丢失更新:事务A撤销时,把已经提交的事务B的更新数据覆盖了。

 

时间 取款事务A 转账事务B

T1 开始事务

T2 开始事务

T3 查询账户余额为1000

T4 查询账户余额为1000

T5 汇入100元修改余额为1100

T6 提交事务

T7 取出100元将余额修改为900

T8 撤销事务

T9 余额恢复为1000元(丢失更新)

2类丢失更新:事务A覆盖事务B已经提交的数据,造成事务B所做的操作丢失。

 

时间 转账事务A 取款事务B

T1 开始事务

T2 开始事务

T3 查询账户余额为1000

T4 查询账户余额为1000

T5 取出100元将余额修改为900

T6 提交事务

T7 汇入100元将余额修改为1100

T8 提交事务

T9 查询账户余额为1100元(丢失更新)

数据并发访问所产生的问题,在有些场景下可能是允许的,但是有些场景下可能就是致命的,数据库通常会通过锁机制来解决数据并发访问问题,按锁定对象不同可以分为表级锁和行级锁;按并发事务锁定关系可以分为共享锁和独占锁,具体的内容大家可以自行查阅资料进行了解。

直接使用锁是非常麻烦的,为此数据库为用户提供了自动锁机制,只要用户指定会话的事务隔离级别,数据库就会通过分析SQL语句然后为事务访问的资源加上合适的锁,此外,数据库还会维护这些锁通过各种手段提高系统的性能,这些对用户来说都是透明的(就是说你不用理解,事实上我确实也不知道)。ANSI/ISO SQL 92标准定义了4个等级的事务隔离级别,如下表所示:

 

隔离级别   脏读  不可重复读   幻读   第一类丢失更新     第二类丢失更新

READ UNCOMMITED 允许 允许 允许 不允许                  允许

READ COMMITTED 不允许   允许    允许      不允许                   允许

REPEATABLE READ 不允许  不允许    允许     不允许                  不允许

SERIALIZABLE 不允许      不允许      不允许   不允许               不允许

需要说明的是,事务隔离级别和数据访问的并发性是对立的,事务隔离级别越高并发性就越差。所以要根据具体的应用来确定合适的事务隔离级别,这个地方没有万能的原则。

 

81JDBC中如何进行事务处理?

答:

Connection提供了事务处理的方法,通过调用setAutoCommit(false)可以设置手动提交事务;

当事务完成后用commit()显式提交事务;如果在事务处理过程中发生异常则通过rollback()进行事务回滚。

除此之外,从JDBC 3.0中还引入了Savepoint(保存点)的概念,允许通过代码设置保存点并让事务回滚到指定的保存点。

 

82JDBC能否处理BlobClob

答: Blob是指二进制大对象(Binary Large Object),而Clob是指大字符对象(Character Large Objec),因此其中Blob是为存储大的二进制数据而设计的,而Clob是为存储大的文本数据而设计的。JDBCPreparedStatementResultSet都提供了相应的方法来支持BlobClob操作。

 

83、简述正则表达式及其用途。

答:在编写处理字符串的程序时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。

 

说明:计算机诞生初期处理的信息几乎都是数值,但是时过境迁,今天我们使用计算机处理的信息更多的时候不是数值而是字符串,正则表达式就是在进行字符串匹配和处理的时候最为强大的工具,绝大多数语言都提供了对正则表达式的支持。

 

84Java中是如何支持正则表达式操作的?

答:Java中的String类提供了支持正则表达式操作的方法,

包括:matches()replaceAll()replaceFirst()split()

 

补充:

面试题: - 如果要从字符串中截取第一个英文左括号之前的字符串,例如:北京市(朝阳区)(西城区)(海淀区),截取结果为:北京市,那么正则表达式怎么写?

import java.util.regex.Matcher;

import java.util.regex.Pattern;

 

class RegExpTest {

 

    public static void main(String[] args) {

        String str = "北京市(朝阳区)(西城区)(海淀区)";

        Pattern p = Pattern.compile(".*?(?=\\()");

        Matcher m = p.matcher(str);

        if(m.find()) {

            System.out.println(m.group());

        }

    }

}

说明:上面的正则表达式中使用了懒惰匹配和前瞻,如果不清楚这些内容,推荐读一下网上很有名的《正则表达式30分钟入门教程》

 

 

 

85、获得一个类的类对象有哪些方式?

答:

a.类型.class,例如:String.class

b.对象.getClass(),例如:"hello".getClass()

c.Class.forName(),例如:Class.forName("java.lang.String")

 

86、如何通过反射创建对象?

答:

- 方法1:通过类对象调用newInstance()方法,例如:String.class.newInstance()

- 方法2:通过类对象的getConstructor()getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象,例如:String.class.getConstructor(String.class).newInstance("Hello");

 

87、如何通过反射获取和设置对象私有字段的值?

答:

可以通过类对象的getDeclaredField()方法字段(Field)对象,然后再通过字段对象的setAccessible(true)将其设置为可以访问,接下来就可以通过get/set方法来获取/设置字段的值了。

88、如何通过反射调用对象的方法?

        String str = "hello";

        Method m = str.getClass().getMethod("toUpperCase");

        System.out.println(m.invoke(str));  // HELLO

 

89、简述一下面向对象的"六原则一法则"

答:

单一职责原则:一个类只做它该做的事情。

开闭原则:软件实体应当对扩展开放,对修改关闭

依赖倒转原则:面向接口编程

里氏替换原则:任何时候都可以用子类型替换掉父类型

接口隔离原则:接口要小而专,绝不能大而全。

合成聚合复用原则:优先使用聚合或合成关系复用代码。

迪米特法则:迪米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。

90、简述一下你了解的设计模式。

答:

设计模式,就是一套被反复使用的代码设计经验的总结(情境中一个问题经过证实的一个解决方案)。

- 工厂模式:工厂类可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作(多态方法)。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。

- 代理模式:给一个对象提供一个代理对象,并由代理对象控制原对象的引用。实际开发中,按照使用目的的不同,代理可以分为:远程代理、虚拟代理、保护代理、Cache代理、防火墙代理、同步化代理、智能引用代理。

- 适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起使用的类能够一起工作。

- 单例模式

 

91、用Java写一个单例类。

 

答:

- 饿汉式单例

 

public class Singleton {

    private Singleton(){}

    private static Singleton instance = new Singleton();

    public static Singleton getInstance(){

        return instance;

    }

}

懒汉式单例

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {}

    public static synchronized Singleton getInstance(){

        if (instance == null) instance new Singleton();

        return instance;

    }

}

注意:实现一个单例有两点注意事项,①将构造器私有,不允许外界通过构造器创建对象;②通过公开的静态方法向外界返回类的唯一实例。

92、什么是UML

答:UML是统一建模语言(Unified Modeling Language)的缩写,它发表于1997年,综合了当时已经存在的面向对象的建模语言、方法和过程,是一个支持模型化和软件系统开发的图形化语言,为软件开发的所有阶段提供模型化和可视化支持。使用UML可以帮助沟通与交流,辅助应用设计和文档的生成,还能够阐释系统的结构和行为。

93UML中有哪些常用的图?

答:UML定义了多种图形化的符号来描述软件系统部分或全部的静态结构和动态结构,包括:用例图(use case diagram)、类图(class diagram)、时序图(sequence diagram)、协作图(collaboration diagram)、状态图(statechart diagram)、活动图(activity diagram)、构件图(component diagram)、部署图(deployment diagram)等。在这些图形化符号中,有三种图最为重要,分别是:用例图(用来捕获需求,描述系统的功能,通过该图可以迅速的了解系统的功能模块及其关系)、类图(描述类以及类与类之间的关系,通过该图可以快速了解系统)、时序图(描述执行特定任务时对象之间的交互关系以及执行顺序,通过该图可以了解对象能接收的消息也就是说对象能够向外界提供的服务)。

94、用Java写一个冒泡排序。

import java.util.Comparator;

 

/**

 * 排序器接口(策略模式: 将算法封装到具有共同接口的独立的类中使得它们可以相互替换)

 * @author骆昊

 *

 */

public interface Sorter {

 

   /**

    * 排序

    * @param list 待排序的数组

    */

   public <T extends Comparable<T>> void sort(T[] list);

 

   /**

    * 排序

    * @param list 待排序的数组

    * @param comp 比较两个对象的比较器

    */

   public <T> void sort(T[] list, Comparator<T> comp);

}

import java.util.Comparator;

 

/**

 * 冒泡排序

 *

 * @author骆昊

 *

 */

public class BubbleSorter implements Sorter {

 

    @Override

    public <T extends Comparable<T>> void sort(T[] list) {

        boolean swapped = true;

        for (int i = 1, len = list.length; i < len && swapped; ++i) {

            swapped = false;

            for (int j = 0; j < len - i; ++j) {

                if (list[j].compareTo(list[j + 1]) > 0) {

                    T temp = list[j];

                    list[j] = list[j + 1];

                    list[j + 1] = temp;

                    swapped = true;

                }

            }

        }

    }

 

    @Override

    public <T> void sort(T[] list, Comparator<T> comp) {

        boolean swapped = true;

        for (int i = 1, len = list.length; i < len && swapped; ++i) {

            swapped = false;

            for (int j = 0; j < len - i; ++j) {

                if (comp.compare(list[j], list[j + 1]) > 0) {

                    T temp = list[j];

                    list[j] = list[j + 1];

                    list[j + 1] = temp;

                    swapped = true;

                }

 

 

95、用Java写一个折半查找。

答:折半查找,也称二分查找、二分搜索,是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组已经为空,则表示找不到指定的元素。

import java.util.Comparator;

 

public class MyUtil {

 

   public static <T extends Comparable<T>> int binarySearch(T[] x, T key) {

      return binarySearch(x, 0, x.length- 1, key);

   }

 

   // 使用循环实现的二分查找

   public static <T> int binarySearch(T[] x, T key, Comparator<T> comp) {

      int low = 0;

      int high = x.length - 1;

      while (low <= high) {

          int mid = (low + high) >>> 1;

          int cmp = comp.compare(x[mid], key);

          if (cmp < 0) {

            low= mid + 1;

          }

          else if (cmp > 0) {

            high= mid - 1;

          }

          else {

            return mid;

          }

      }

      return -1;

   }

 

   // 使用递归实现的二分查找

   private static<T extends Comparable<T>> int binarySearch(T[] x, int low, int high, T key) {

      if(low <= high) {

        int mid = low + ((high -low) >> 1);

        if(key.compareTo(x[mid])== 0) {

           return mid;

        }

        else if(key.compareTo(x[mid])< 0) {

           return binarySearch(x,low, mid - 1, key);

        }

        else {

           return binarySearch(x,mid + 1, high, key);

        }

      }

      return -1;

   }

}

 

 

 

 

96Java 代码查错

1.

 abstract class Name {

private String name;

public abstract boolean isStupidName(String name) {}

}

大侠们,这有何错误?

答案: 错。abstract method 必须以分号结尾,且不带花括号。 2.

public class Something {

void doSomething () { private String s = ""; int l = s.length();

} }

有错吗?

答案: 错。局部变量前不能放置任何访问修饰符 (private,public,protected)final 可以 用来修饰局部变量

(final 如同 abstract strictfp,都是非访问修饰符,strictfp 只能修饰 class method 而非 variable)

3.

abstract class Something {

private abstract String doSomething (); }

这好像没什么错吧?

答案: 错。abstractmethods不能以private修饰。abstractmethods就是让子类implement(实 现)具体细节的,怎么可以用 private abstract

method 封锁起来呢? (同理,abstract method 前不能加 final)

4.

public class Something {

public int addOne(final int x) { return ++x;

} }

这个比较明显。

答案: 错。int x 被修饰成 final,意味着 x 不能在 addOne method 中被修改。 5.

public class Something {

public static void main(String[] args) { Other o = new Other();

new Something().addOne(o);

}

public void addOne(final Other o) {

o.i++; }

}

 class Other { public int i;

}

和上面的很相似,都是关于 final 的问题,这有错吗?

答案: 正确。在 addOne method ,参数 o 被修饰成 final。如果在 addOne method 里我们修 改了 o reference

(比如: o = new Other();),那么如同上例这题也是错的。但这里修改的是 o member vairable (成员变量),o reference 并没有改变。

6.

class Something {

int i;

public void doSomething() {

System.out.println("i = " + i); }

}

有什么错呢? 看不出来啊。

答案: 正确。输出的是"i = 0"int i 属於 instant variable (实例变量,或叫成员变量)instant variable default valueint default value 0

7.

class Something {

final int i;

public void doSomething() {

System.out.println("i = " + i); }

}

和上面一题只有一个地方不同,就是多了一个 final。这难道就错了吗?

答案: 错。final int i 是个 final instant variable (实例变量,或叫成员变量)final instant variable 没有 default value,必须在 constructor (构造器)结束之前被赋予一个明确的值。可以 修改为"final int i = 0;"

8.

public class Something {

public static void main(String[] args) {

Something s = new Something(); System.out.println("s.doSomething() returns " + doSomething());

}

public String doSomething() {

return "Do something ..."; }

}

看上去很完美。

答案: 错。看上去在 main call doSomething 没有什么问题,毕竟两个 methods 都在同一个 class 里。但仔细看,main static 的。static method 不能直接 call non-static methods。可改 成"System.out.println("s.doSomething() returns " + s.doSomething());"。同理,static method 不 能访问 non-static instant variable

 9.

此处,Something 类的文件名叫 OtherThing.java class Something {

private static void main(String[] something_to_do) { System.out.println("Do something ...");

} }

这个好像很明显。

答案: 正确。从来没有人说过 Java Class 名字必须和其文件名相同。但 public class 的名字 必须和文件名相同。

10.

interface A{

int x = 0; }

class B{ int x =1;

}

class C extends B implements A {

public void pX(){ System.out.println(x);

}

public static void main(String[] args) {

new C().pX(); }

}

答案:错误。在编译时会发生错误(错误 述不同的 JVM 有不同的信息,意思就是未明确的 x 调用,两个 x 都匹配(就象在同时 import java.util java.sql 两个包时直接声明 Date 一样)。 对于父类的变量,可以用 super.x 来明确,而接口的属性默认隐含为 public static final.所以可 以通过 A.x 来明确。

11.

interface Playable {

void play(); }

interface Bounceable { void play();

}

interface Rollable extends Playable, Bounceable {

Ball ball = new Ball("PingPang"); }

class Ball implements Rollable { private String name;

public String getName() {

return name; }

public Ball(String name) { this.name = name;

}

public void play() {

ball = new Ball("Football");

System.out.println(ball.getName()); }

}

这个错误不容易发现。

答案: 错。"interface Rollable extends Playable, Bounceable"没有问题。interface 可继承多个 interfaces,所以这里没错。问题出在 interface Rollable 里的"Ball ball = new Ball("PingPang");"。 任何在 interface 里声明的 interface variable (接口变量,也可称成员变量),默认为 public static final。也就是说"Ball ball = new Ball("PingPang");"实际上是"public static final Ball ball = new Ball("PingPang");"。在Ball类的Play()方法中,"ball = new Ball("Football");"改变了ballreference,而这里的 ball 来自 Rollable interface,Rollable interface 里的 ball public static final ,final object 是不能被改变 reference 的。因此编译器将在"ball = new Ball("Football");" 这里显示有错。

 

三、html&JavaScript&ajax

1. 判断第二个日期比第一个日期大

//实现比较

function compareDate(d1,d2) {

var arrayD1 = d1.split("-");

var date1 = new Date(arrayD1[0],arrayD1[1],arrayD1[2]); var arrayD2 = d2.split("-");

var date2 = new Date(arrayD2[0],arrayD2[1],arrayD2[2]); if(date1 > date2) return false;

return true;

}

//判断格式是否正确

function verifyDate(d) {

var datePattern = /^\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2]\d|3[0-1])$/;

return datePattern.test(d); }

 

 

2. table 显示 n 条记录,3 行换一次颜色,1,2,3 用红色字体,4,5,6 用绿色字体,7,8,9 用红颜色字体。

window.οnlοad=function()

{

var tbl = document.getElementById("tbl"); rows = tbl.getElementsByTagName("tr"); for(i=0;i<rows.length;i++)

{

var j = parseInt(i/3);

if(j%2==0) rows[i].style.backgroundColor="#f00"; else rows[i].style.backgroundColor="#0f0";

} }

 

3HTML form  交之前如何验证数值文本框的内容全 部为数字? 否则的话 示用户并终止 交?

<form οnsubmit=return chkForm(this)> <input type="text" name="d1"/>

<input type="submit"/>

</form>

<script type=text/javascript/> function chkForm(this)

{

var value = thist.d1.value; var len = value.length; for(var i=0;i<len;i++)

{

if(value.charAt(i)>"9" || value.charAt(i)<"0") {

alert("含有非数字字符");

return false; }

}

return true; }

</script>

4、请写出用于校验 HTML 文本框中输入的内容全部为数字 的 javascript 代码

失去焦点事件

<input type="text" id="d1" οnblur=" chkNumber (this)"/> <script type=text/javascript/>

function chkNumber(eleText)

{

var value = eleText.value; var len = value.length; for(var i=0;i<len;i++)

{

if(value.charAt(i)>"9" || value.charAt(i)<"0") {

alert("含有非数字字符");

eleText.focus();

break; }

} }

</script>

 

5、说说你用过那些 ajax 技术和框架,说说它们的区别

百度一下

答:jQuery

       EasyUI

       DWR

       Vue

 

四、Java web 部分

1Tomcat 的优化经验

去掉对 web.xml 的监视,jsp  前编辑成 Servlet

有富余物理内存的情况,加大 tomcat 使用的 jvm 的内存

2HTTP 请求的 GET POST 方式的区别

get请求用来从服务器上获得资源,而post是用来向服务器提交数据; 
②get将表单中数据按照name=value的形式,添加到action 所指向的URL 后面,并且两者使用"?"连接,而各个变量之间使用"&"连接;post是将表单中的数据放在HTTP协议的请求头或消息体中,传递到action所指向URL 
③get传输的数据要受到URL长度限制(1024字节);而post可以传输大量的数据,上传文件通常要使用post方式; 

④使用get时参数会显示在地址栏上,如果这些数据不是敏感数据,那么可以使用get;对于敏感数据还是应用使用post 
⑤get使用MIME类型application/x-www-form-urlencodedURL编码(也叫百分号编码)文本的格式传递参数,保证被传送的参数由遵循规范的文本组成,例如一个空格的编码是"%20"

3、解释一下什么是 servlet;

答:Servlet是一个特殊的Java程序,它运行于服务器的JVM中,能够依靠服务器的支持向浏览器提供显示内容。

4、说一说 Servlet 的生命周期?

:包括加载和实例化、初始化、处理请求以及服务结束。

这个生存期由 javax.servlet.Servlet 接口的 init,service destroy 方法表达。

Servlet 被服务器实例化后,容器运行其 init 方法,请求到达时运行其 service 方法,service 方法自动派遣运行与请求对应的 doXXX 方法(doGet,doPost),当服务器决定将实例销 毁的时候调用其 destroy 方法。

5Servlet 的基本架构

public class ServletName extends HttpServlet {

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

}

6SERVLET API forward() redirect()的区别?

答:forward是容器中控制权的转向,是服务器请求资源,服务器直接访问目标地址的URL,把那个URL 的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。redirect就是服务器端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,因此从浏览器的地址栏中可以看到跳转后的链接地址,很明显redirect无法访问到服务器保护起来资源,但是可以从一个网站redirect到其他网站。forward更加高效,所以在满足需要时尽量使用forward(通过调用RequestDispatcher对象的forward()方法,该对象可以通过ServletRequest对象的getRequestDispatcher()方法获得),并且这样也有助于隐藏实际的链接;在有些情况下,比如需要访问一个其它服务器上的资源,则必须使用重定向(通过HttpServletResponse对象调用其sendRedirect()方法实现)。

7、什么情况下调用 doGet()doPost()?

Jsp 页面中的 FORM 标签里的 method 属性为 get 时调用 doGet(),post 时调用

doPost()。所有的超链接是调doGet();

8Request 对象的主要方法:

setAttribute(String name,Object):设置名字为 name request 的参数值 getAttribute(String name):返回由 name 指定的属性值

getCookies():返回客户端的所有 Cookie 对象,结果是一个 Cookie 数组

getCharacterEncoding():返回请求中的字符编码方式 getContentLength():返回请求的 Body 的长度

getMethod():获得客户端向服务器端传送数据的方法

getParameter(String name):获得客户端传送给服务器端的有 name 指定的参数值 getParameterNames():获得客户端传送给服务器端的所有参数的名字,结果是一个枚

举的实例

getParametervalues(String name):获得有 name 指定的参数的所有值

removeAttribute(String name):删除请求中的一个属性

9request.getAttribute() request.getParameter() 有何 区别?

getParameter 是用来接受用postget方法传递过来的参数的.

getAttribute 必须先setAttribute.

1request.getParameter() 取得是通过容器的实现来取得通过类似postget等方式传入的数据,request.setAttribute()getAttribute()只是在web容器内部流转,仅仅是请求处理阶段。

2request.getParameter() 方法传递的数据,会从Web客户端传到Web服务器端,代表HTTP请求数据。request.getParameter()方法返回String类型的数据。

request.setAttribute() getAttribute() 方法传递的数据只会存在于Web容器内部

还有一点就是,HttpServletRequest 类有 setAttribute() 方法,而没有setParameter() 方法。

10. jsp 有哪些内置对象?作用分别是什么? 分别有什么方 法?

:JSP 共有以下 9 个内置的对象:

request 用户端请求,此请求会包含来自 GET/POST 请求的参数 response 网页传回用户端的回应

pageContext 网页的属性是在这里管理

session 与请求有关的会话期

application servlet 正在执行的内容

out 用来传送回应的输出

config servlet 的构架部件

page JSP 网页本身

exception 针对错误网页,未捕捉的例外

11. jsp 有哪些动作?作用分别是什么?

:JSP 共有以下 7 种基本动作

jsp:param指令用于设置参数值,单独使用没有意义

jsp:include:在页面被请求的时候引入一个文件。

jsp:useBean:寻找或者实例化一个 JavaBean

jsp:setProperty:设置 JavaBean 的属性。

jsp:getProperty:输出某个 JavaBean 的属性。

jsp:forward:把请求转到一个新的页面。

jsp:plugin:根据浏览器类型为 Java 插件生成 OBJECT EMBED 标记

12JSP 的常用指令

三个编译指令为:pageincludetaglib

七个动作指令为:jsp:forwardjsp:paramjsp:includejsp:pluginjsp:useBeanjsp:setPropertyjsp:getProperty

 

13. JSP 中动态 INCLUDE 与静态 INCLUDE 的区别?

JSP中的静态包含和动态包含有什么区别

答:静态包含是通过JSPinclude指令包含页面,动态包含是通过JSP标准动作<jsp:forward>包含页面。静态包含是编译时包含,如果包含的页面不存在则会产生编译错误,而且两个页面的"contentType"属性应保持一致,因为两个页面会合二为一,只产生一个class文件,因此被包含页面发生的变动再包含它的页面更新前不会得到更新。动态包含是运行时包含,可以向被包含的页面传递参数,包含页面和被包含页面是独立的,会编译出两个class文件,如果被包含的页面不存在,不会产生编译错误,也不影响页面其他部分的执行。

 

14、页面间对象传递的方法

request,session,application,cookie

15JSP Servlet 有哪些相同点和不同点,他们之间的联 系是什么?

Servlet是一个特殊的Java程序,它运行于服务器的JVM中,能够依靠服务器的支持向浏览器提供显示内容。JSP本质上是Servlet的一种简易形式,JSP会被服务器处理成一个类似于ServletJava程序,可以简化页面内容的生成。ServletJSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML分离开来。而JSP的情况是JavaHTML可以组合成一个扩展名为.jsp的文件。Servlet就是在Java中写HTML,而JSP就是在HTML中写Java代码。JSP侧重于视图,Servlet更侧重于控制逻辑,在MVC架构模式中,JSP适合充当视图(view)而Servlet适合充当控制器(controller)。

16MVC 的各个部分都有那些技术来实现?如何实现?

:MVC Model-View-Controller 的简写。Model 代表的是应用的业务逻辑(通过 JavaBean,EJB 组件实现), View 是应用的表示面(JSP 页面产生),Controller 是 供 应用的处理过程控制(一般是一个 Servlet),通过这种设计模型把应用逻辑,处理过程和显 示逻辑分成不同的组件实现。这些组件可以进行交互和重用。

17、我们在 web 应用开发过程中经常遇到输出某种编码的字 符,iso8859-1 ,如何输出一个某种编码的字符串?

tempStr = new String(str.getBytes("ISO-8859-1"), UTF-8);

 

18、阐述ServletCGI的区别

答:ServletCGI的区别在于Servlet处于服务器进程中,它通过多线程方式运行其service()方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于Servlet

19、常用的Web服务器有哪些?

免费HTTP服务器是Apache服务器,而Windows平台的服务器通常使用IIS作为Web服务器。选择Web服务器应考虑的因素有:性能、安全性、日志和统计、虚拟主机、代理服务器、缓冲服务和集成应用程序等。

IISMicrosoftWeb服务器产品

WebSphereIBM

WebLogicOracle

Apache:目前Apache仍然是世界上用得最多的Web服务器

TomcatTomcat是一个开放源代码、运行ServletJSP的容器

Nginx:高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP代理服务器

20、如何实现JSPServlet的单线程模式? 

答: 对于JSP页面,可以通过page指令进行设置。

<%@page isThreadSafe=false%>

对于Servlet,可以让自定义的Servlet实现SingleThreadModel标识接口。

说明:如果将JSPServlet设置成单线程工作模式,会导致每个请求创建一个Servlet实例,这种实践将导致严重的性能问题(服务器的内存压力很大,还会导致频繁的垃圾回收),所以通常情况下并不会这么做。

21、实现会话跟踪的技术有哪些?

答:由于HTTP协议本身是无状态的,服务器为了区分不同的用户,就需要对用户会话进行跟踪,简单的说就是为用户进行登记,为用户分配唯一的ID,下一次用户在请求中包含此ID,服务器据此判断到底是哪一个用户。 

URL 重写:在URL中添加用户会话的信息作为请求的参数,或者将唯一的会话ID添加到URL结尾以标识一个会话。 

②设置表单隐藏域:将和会话跟踪相关的字段添加到隐式表单域中,这些信息不会在浏览器中显示但是提交表单时会提交给服务器。 

cookie:属于客户端技术,cookie有两种,一种是基于窗口的,浏览器窗口关闭后,cookie就没有了;另一种是将信息存储在一个临时文件中,并设置存在的时间。

在使用cookie时要注意几点:首先不要在cookie中存放敏感信息;其次cookie存储的数据量有限(4k),不能将过多的内容存储cookie中;再者浏览器通常只允许一个站点最多存放20cookie

HttpSession:属于服务端技术,在所有会话跟踪技术中,HttpSession对象是最强大也是功能最多的。当一个用户第一次访问某个网站时会自动创建HttpSession,每个用户可以访问他自己的HttpSession

22、过滤器有哪些作用和用法? 

Java Web开发中的过滤器(filter)是从Servlet 2.3规范开始增加的功能,并在Servlet 2.4规范中得到增强。对Web应用来说,过滤器是一个驻留在服务器端的Web组件,它可以截取客户端和服务器之间的请求与响应信息,并对这些信息进行过滤。

常见的过滤器用途主要包括:对用户请求进行统一认证、对用户的访问请求进行记录和审核、对用户发送的数据进行过滤或替换、转换图象格式、对响应内容进行压缩以减少传输量、对请求或响应进行加解密处理、触发资源访问事件、对XML的输出应用XSLT等。

23、监听器有哪些作用和用法? 

答:Java Web开发中的监听器(listener)就是applicationsessionrequest三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件,如下所示: 
①ServletContextListener:对Servlet上下文的创建和销毁进行监听。 
②ServletContextAttributeListener:监听Servlet上下文属性的添加、删除和替换。 
③HttpSessionListener:对Session的创建和销毁进行监听。

补充:session的销毁有两种情况:1). session超时(可以在web.xml中通过<session-config>/<session-timeout>标签配置超时时间);2). 通过调用session对象的invalidate()方法使session失效。

HttpSessionAttributeListener:对Session对象中属性的添加、删除和替换进行监听。 
⑤ServletRequestListener:对请求对象的初始化和销毁进行监听。 
⑥ServletRequestAttributeListener:对请求对象属性的添加、删除和替换进行监听。

 

24web.xml文件中可以配置哪些内容? 

答:web.xml用于配置Web应用的相关信息,如:监听器(listener)、过滤器(filter)、 Servlet、相关参数、会话超时时间、安全验证方式、错误页面等

Servlet 3规范提供了基于注解的配置方式,可以分别使用@WebServlet@WebListener@WebFilter注解进行配置。 

认证的方式非常多,简单说来可以分为三类: A. What you know? — 口令 B. What you have? — 数字证书(U盾、密保卡) C. Who you are? — 指纹识别、虹膜识别 

 

25、你的项目中使用过哪些JSTL标签?

答:项目中主要使用了JSTL的核心标签库,包括<c:if><c:choose><c: when><c: otherwise><c:forEach>等,主要用于构造循环和分支结构以控制显示逻辑。

说明:虽然JSTL标签库提供了coresqlfmtxml等标签库,但是实际开发中建议只使用核心标签库(core),而且最好只使用分支和循环标签并辅以表达式语言(EL),这样才能真正做到数据显示和业务逻辑的分离,这才是最佳实践。

26、使用标签库有什么好处?如何自定义JSP标签? 

答:使用标签库的好处包括以下几个方面: - 分离JSP页面的内容和逻辑,简化了Web开发; - 开发者可以创建自定义标签来封装业务逻辑和显示逻辑; - 标签具有很好的可移植性、可维护性和可重用性; - 避免了对Scriptlet(小脚本)的使用(很多公司的项目开发都不允许在JSP中书写小脚本)

自定义JSP标签包括以下几个步骤: - 编写一个Java类实现实现Tag/BodyTag/IterationTag接口(开发中通常不直接实现这些接口而是继承TagSupport/BodyTagSupport/SimpleTagSupport类,这是对缺省适配模式的应用),重写doStartTag()doEndTag()等方法,定义标签要完成的功能 - 编写扩展名为tld的标签描述文件对自定义标签进行部署,tld文件通常放在WEB-INF文件夹下或其子目录中 

27、说一下表达式语言(EL)的隐式对象及其作用。 

答:EL的隐式对象包括:pageContextinitParam(访问上下文参数)、param(访问请求参数)、paramValuesheader(访问请求头)、headerValuescookie(访问cookie)、applicationScope(访问application作用域)、sessionScope(访问session作用域)、requestScope(访问request作用域)、pageScope(访问page作用域)。

用法如下所示:

${pageContext.request.method}

${pageContext["request"]["method"]}

${pageContext.request["method"]}

${pageContext["request"].method}

${initParam.defaultEncoding}

${header["accept-language"]}

${headerValues["accept-language"][0]}

${cookie.jsessionid.value}

${sessionScope.loginUser.username}

补充:表达式语言的.[]运算作用是一致的,唯一的差别在于如果访问的属性名不符合Java标识符命名规则,例如上面的accept-language就不是一个有效的Java标识符,那么这时候就只能用[]运算符而不能使用.运算符获取它的值

28、表达式语言(EL)支持哪些运算符?

答:除了.[]运算符,EL还提供了: - 算术运算符:+-*/div%mod - 关系运算符:==eq!=ne>gt>=ge<lt<=le - 逻辑运算符:&&and||or!not - 条件运算符:${statement? A : B}(跟Java的条件运算符类似) - empty运算符:检查一个值是否为null或者空(数组长度为0或集合中没有元素也返回true

29Java Web开发的Model 1Model 2分别指的是什么? 

答:Model 1是以页面为中心的Java Web开发,使用JSP+JavaBean技术将页面显示逻辑和业务逻辑处理分开,JSP实现页面显示,JavaBean对象用来保存数据和实现业务逻辑。Model 2是基于MVC(模型-视图-控制器,Model-View-Controller)架构模式的开发模型,实现了模型和视图的彻底分离,利于团队开发和代码复用。

30Servlet 3中的异步处理指的是什么?

答:在Servlet 3中引入了一项新的技术可以让Servlet异步处理请求。

异步特性可以帮助应用节省容器中的线程,特别适合执行时间长而且用户需要得到结果的任务,如果用户不需要得到结果则直接将一个Runnable对象交给Executor并立即返回即可。

31、如何在基于JavaWeb项目中实现文件上传和下载? 

答:在Sevlet 3 以前,Servlet API中没有支持上传功能的API,因此要实现上传功能需要引入第三方工具从POST请求中获得上传的附件或者通过自行处理输入流来获得上传的文件,我们推荐使用Apachecommons-fileupload

Servlet 3开始,文件上传变得无比简单

上传页面index.jsp

<%@ page pageEncoding="utf-8"%>

<!DOCTYPE html>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Photo Upload</title>

</head>

<body>

<h1>Select your photo and upload</h1>

<hr/>

<div style="color:red;font-size:14px;">${hint}</div>

<form action="UploadServlet" method="post" enctype="multipart/form-data">

    Photo file: <input type="file" name="photo" />

    <input type="submit" value="Upload" />

</form>

</body>

</html>

支持上传的Servlet

package com.jackfrued.servlet;

 

import java.io.IOException;

 

import javax.servlet.ServletException;

import javax.servlet.annotation.MultipartConfig;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.Part;

 

@WebServlet("/UploadServlet")

@MultipartConfig

public class UploadServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

 

    protected void doPost(HttpServletRequest request,

            HttpServletResponse response) throws ServletException, IOException {

        // 可以用request.getPart()方法获得名为photo的上传附件

        // 也可以用request.getParts()获得所有上传附件(多文件上传)

        // 然后通过循环分别处理每一个上传的文件

        Part part = request.getPart("photo");

        if (part != null && part.getSubmittedFileName().length() > 0) {

            // ServletContext对象的getRealPath()方法获得上传文件夹的绝对路径

            String savePath = request.getServletContext().getRealPath("/upload");

            // Servlet 3.1规范中可以用Part对象的getSubmittedFileName()方法获得上传的文件名

            // 更好的做法是为上传的文件进行重命名(避免同名文件的相互覆盖)

            part.write(savePath + "/" + part.getSubmittedFileName());

            request.setAttribute("hint", "Upload Successfully!");

        } else {

            request.setAttribute("hint", "Upload failed!");

        }

        // 跳转回到上传页面

        request.getRequestDispatcher("index.jsp").forward(request, response);

    }

 

}

32Servlet中如何获取用户提交的查询参数或表单数据? 
答:可以通过请求对象(HttpServletRequest)的getParameter()方法通过参数名获得参数值。如果有包含多个值的参数(例如复选框),可以通过请求对象的getParameterValues()方法获得。当然也可以通过请求对象的getParameterMap()获得一个参数名和参数值的映射(Map)。

 

33Servlet中如何获取用户配置的初始化参数以及服务器上下文参数? 
答:可以通过重写Servlet接口的init(ServletConfig)方法并通过ServletConfig对象的getInitParameter()方法来获取Servlet的初始化参数。可以通过ServletConfig对象的getServletContext()方法获取ServletContext对象,并通过该对象的getInitParameter()方法来获取服务器上下文参数。当然,ServletContext对象也在处理用户请求的方法(如doGet()方法)中通过请求对象的getServletContext()方法来获得。

 

34、如何设置请求的编码以及响应内容的类型? 
答:通过请求对象(ServletRequest)的setCharacterEncoding(String)方法可以设置请求的编码,其实要彻底解决乱码问题就应该让页面、服务器、请求和响应、Java程序都使用统一的编码,最好的选择当然是UTF-8;通过响应对象(ServletResponse)的setContentType(String)方法可以设置响应内容的类型,当然也可以通过HttpServletResponsed对象的setHeader(String, String)方法来设置

 

35、解释一下网络应用的模式及其特点。

答:典型的网络应用模式大致有三类:B/SC/SP2P。其中B代表浏览器(Browser)、C代表客户端(Client)、S代表服务器(Server),P2P是对等模式,不区分客户端和服务器。B/S应用模式中可以视为特殊的C/S应用模式,只是将C/S应用模式中的特殊的客户端换成了浏览器,因为几乎所有的系统上都有浏览器,那么只要打开浏览器就可以使用应用,没有安装、配置、升级客户端所带来的各种开销。

 

补充:此题要跟"电子商务模式"区分开,因为有很多人被问到这个问题的时候马上想到的是B2B(如阿里巴巴)也有写成 BTB,是Business-to-Business的缩写、B2C(如当当、亚马逊、京东)Business-to-CustomerC2C(如淘宝、拍拍CustomerCustomerto ConsumerConsumer))、C2B(如威客)Customer to Business,即消费者到企业、O2O(如美团、饿了么)即Online To Offline(在线离线/线上到线下)。

 

36、什么是Web ServiceWeb服务)? 

答:从表面上看,Web Service就是一个应用程序,它向外界暴露出一个能够通过Web进行调用的API。如聚合数据。

补充:这里必须要提及的一个概念是SOAService-Oriented Architecture,面向服务的架构),SOA是一种思想,它将应用程序的不同功能单元通过中立的契约联系起来,独立于硬件平台、操作系统和编程语言,使得各种形式的功能单元能够更好的集成。显然,Web ServiceSOA的一种较好的解决方案,它更多的是一种标准,而不是一种具体的技术。

37、概念解释:SOAPWSDLUDDI 

答: - SOAP:简单对象访问协议(Simple Object Access Protocol),是Web Service中交换数据的一种协议规范。 - WSDLWeb服务描述语言(Web Service Description Language),它描述了Web服务的公共接口。这是一个基于XML的关于如何与Web服务通讯和使用的服务描述;也就是描述与目录中列出的Web服务进行交互时需要绑定的协议和信息格式。通常采用抽象语言描述该服务支持的操作和信息,使用的时候再将实际的网络协议和信息格式绑定给该服务。 - UDDI:统一描述、发现和集成(Universal Description, Discovery and Integration),它是一个基于XML的跨平台的描述规范,可以使世界范围内的企业在互联网上发布自己所提供的服务。简单的说,UDDI是访问各种WSDL的一个门面(可以参考设计模式中的门面模式)。

38Java规范中和Web Service相关的规范有哪些? 

答:Java规范中和Web Service相关的有三个: - JAX-WS(JSR 224):这个规范是早期的基于SOAPWeb Service规范JAX-RPC的替代版本,它并不提供向下兼容性,因为RPC样式的WSDL以及相关的API已经在Java EE5中被移除了。WS-MetaDataJAX-WS的依赖规范,提供了基于注解配置Web ServiceSOAP消息的相关API - JAXM(JSR 67):定义了发送和接收消息所需的API,相当于Web Service的服务器端。 - JAX-RS(JSR 311 & JSR 339 & JSR 370):是Java针对RESTRepresentation State Transfer)架构风格制定的一套Web Service规范。REST是一种软件架构模式,是一种风格,它不像SOAP那样本身承载着一种消息协议, (两种风格的Web Service均采用了HTTP做传输协议,因为HTTP协议能穿越防火墙,Java的远程方法调用(RMI)等是重量级协议,通常不能穿越防火墙),因此可以将REST视为基于HTTP协议的软件架构。REST中最重要的两个概念是资源定位和资源操作,而HTTP协议恰好完整的提供了这两个点。HTTP协议中的URI可以完成资源定位,而GETPOSTOPTIONDELETE方法可以完成资源操作。因此REST完全依赖HTTP协议就可以完成Web Service,而不像SOAP协议那样只利用了HTTP的传输特性,定位和操作都是由SOAP协议自身完成的,也正是由于SOAP消息的存在使得基于SOAPWeb Service显得笨重而逐渐被淘汰。

39、介绍一下你了解的Java领域的Web Service框架。

答:Java领域的Web Service框架很多,包括Axis2Axis的升级版本)、JerseyRESTfulWeb Service框架)、CXFXFire的延续版本)、JBoss SOA等,其中绝大多数都是开源框架。

五、数据库

1、用两种方式根据部门号从高到低,工资从低到高列出每

个员工的信息。

employee: eid,ename,salary,deptid;

select * from employee order by deptid desc,salary

2、列出各个部门中工资高于本部门的平均工资的员工数和 部门号,并按部门号排序

创建表:

mysql> create table employee921(id int primary key auto_increment,name varchar(5 0),salary bigint,deptid int);

插入实验数据:

mysql> insert into employee921 values(null,'zs',1000,1),(null,'ls',1100,1),(null ,'ww',1100,1),(null,'zl',900,1) ,(null,'zl',1000,2), (null,'zl',900,2) ,(null,'z l',1000,2) , (null,'zl',1100,2);

编写 sql 语句:

()select avg(salary) from employee921 group by deptid;

()mysql> select employee921.id,employee921.name,employee921.salary,employee921.dep

tid tid from employee921 where salary > (select avg(salary) from employee921 where deptid = tid);

效率低的一个语句,仅供学习参考使用(group by 之后不能使用 where,只能使用 having,group by 之前可以使用 where,即表示对过滤后的结果分组):

mysql> select employee921.id,employee921.name,employee921.salary,employee921.dep

tid tid from employee921 where salary > (select avg(salary) from employee921 group by deptid

having deptid = tid); ()select count(*) ,tid

from (

select employee921.id,employee921.name,employee921.salary,employee921.deptid tid from employee921

where salary >

(select avg(salary) from employee921 where group by tid ;

另外一种方式:关联查询

select a.ename,a.salary,a.deptid from emp a,

deptid = tid)

) as t

(select deptd,avg(salary) avgsal from emp group by deptid ) b where a.deptid=b.deptid and a.salary>b.avgsal;

 

3、存储过程与触发器必须讲,经常被面试到?

create procedure insert_Student (_name varchar(50),_age int ,out _id int) begin

insert into student value(null,_name,_age);

select max(stuId) into _id from student; end;

call insert_Student('wfz',23,@id); select @id;

mysql> create trigger update_Student BEFORE update on student FOR EACH ROW -> select * from student;

触发器不允许返回结果

create trigger update_Student BEFORE update on student FOR EACH ROW insert into student value(null,'zxx',28);

mysql 的触发器目前不能对当前表进行操作

create trigger update_Student BEFORE update on student FOR EACH ROW delete from articles where id=8; 这个例子不是很好,最好是用删除一个用户时,顺带删除该用户的所有帖子 这里要注意使用 OLD.id

触发器用处还是很多的,比如校内网、开心网、Facebook,你发一个日志,自动通知好 友,其实就是在增加日志时做一个后触发,再向通知表中写入条目。因为触发器效率高。而 UCH 没有用触发器,效率和数据处理能力都很低。

存储过程的实验步骤:

 mysql> delimiter |

mysql> create procedure insertArticle_Procedure (pTitle varchar(50),pBid int,out

pId int)

-> begin

-> insert into article1 value(null,pTitle,pBid); -> select max(id) into pId from article1;

-> end;

-> |

Query OK, 0 rows affected (0.05 sec)

mysql> call insertArticle_Procedure('传智播客',1,@pid); -> |

Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ; mysql> select @pid; +------+

| @pid |

+------+

|3|

+------+

1 row in set (0.00 sec)

mysql> select * from article1; +----+--------------+------+ |id|title |bid | +----+--------------+------+ |1|test |1 |

| 2 | chuanzhiboke | 1 | |3 |传智播客 |1 | +----+--------------+------+

3 rows in set (0.00 sec)

触发器的实验步骤:

create table board1(id int primary key auto_increment,name varchar(50),ar ticleCount int);

create table article1(id int primary key auto_increment,title varchar(50) ,bid int references board1(id));

delimiter |

create trigger insertArticle_Trigger after insert on article1 for each ro w begin

-> update board1 set articleCount=articleCount+1 where id= NEW.bid; -> end;

-> |

delimiter ;

insert into board1 value (null,'test',0);

insert into article1 value(null,'test',1);

还有,每插入一个帖子,都希望将版面表中的最后发帖时间,帖子总数字段进行同步 更新,用触发器做效率就很高。下次课设计这样一个案例,写触发器时,对于最后发帖时间 可能需要用 declare 方式声明一个变量,或者是用 NEW.posttime 来生成。

4、数据库三范式是什么?

第一范式(1NF):字段具有原子性,不可再分。所有关系型数据库系统都满足第一范式) 数据库表中的字段都是单一属性的,不可再分。例如,姓名字段,其中的姓和名必须作 为一个整体,无法区分哪部分是姓,哪部分是名,如果要区分出姓和名,必须设计成两个独

立的字段。

第二范式(2NF): 第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必 须先满足第一范式(1NF)。 要求数据库表中的每个实例或行必须可以被惟一地区分。通常需要为表加上一个列,以存储 各个实例的惟一标识。这个惟一属性列被称为主关键字或主键。

第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖 主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成 一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列, 以存储各个实例的惟一标识。简而言之,第二范式就是非主属性非部分依赖于主关键字。

第三范式的要求如下: 满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个 数据库表中不包含已在其它表中已包含的非主关键字信息。

所以第三范式具有如下特征:

1,每一列只有一个值

2,每一行都能区分。 3,每一个表都不包含其他表已经包含的非主关键字信息。

例如,帖子表中只能出现发帖人的 id,而不能出现发帖人的 id,还同时出现发帖人姓名, 否则,只要出现同一发帖人 id 的所有记录,它们中的姓名部分都必须严格保持一致,这就 是数据冗余。

5、说出一些数据库优化方面的经验?

PreparedStatement 一般来说比Statement性能高:一个sql 发给服务器去执行,涉及步骤: 语法检查、语义分析, 编译,缓存

inert into user values(1,1,1)- 二进制

inert into user values(2,2,2)- 二进制

inert into user values(?,?,?)- 二进制

有外键约束会影响插入和删除性能,如果程序能够保证数据的完整性,那在设计数据库时就 去掉外键。(比喻:就好比免检产品,就是为了 高效率,充分相信产品的制造商) (对于 hibernate 来说,就应该有一个变化:empleyee->Deptment 对象,现在设计时就成了 employee deptid)

mysql 帮助文档子查询章节的最后部分,例如,根据扫 的原理,下面的子查询语句要比 第二条关联查询的效率高:

1. select e.name,e.salary where e.managerid=(select id from employee where name='zxx');

2. select e.name,e.salary,m.name,m.salary from employees e,employees m where e.managerid = m.id and m.name='zxx';

表中允许适当冗余,譬如,主题帖的回复数量和最后回复时间等 将姓名和密码单独从用户表中独立出来。这可以是非常好的一对一的案例哟!

sql 语句全部大写,特别是列名和表名都大写。特别是 sql 命令的缓存功能,更加需要统一 大小写,sql 语句 发给 oracle 服务器 语法检查和编译成为内部指令 缓存和执行指令。 根据缓存的特点,不要拼凑条件,而是用?PreparedStatment

还有索引对查询性能的改进也是值得关注的。 备注:下面是关于性能的讨论举例

4航班 3个城市

m*n

select * from flight,city where flight.startcityid=city.cityid and city.name='beijing'; m+n

select * from flight where startcityid = (select cityid from city where cityname='beijing');

select flight.id,'beijing',flight.flightTime from flight where startcityid = (select cityid from city where cityname='beijing')

 

6union union all 有什么不同?

假设我们有一个表 Student,包括以下字段与数据: drop table student;

create table student

(

id int primary key,

name nvarchar2(50) not null,

score number not null

);

insert into student values(1,'Aaron',78);

insert into student values(2,'Bill',76);

insert into student values(3,'Cindy',89);

insert into student values(4,'Damon',90);

insert into student values(5,'Ella',73);

insert into student values(6,'Frado',61);

insert into student values(7,'Gill',99);

insert into student values(8,'Hellen',56);

insert into student values(9,'Ivan',93);

insert into student values(10,'Jay',90);

commit;

Union Union All 的区别。

select *

from student

where id < 4

union

select *

from student

where id > 2 and id < 6

结果将是

1 Aaron 78

2 Bill 76

3 Cindy 89

4 Damon 90

5 Ella 73

如果换成 Union All 连接两个结果集,则返回结果是: 1 Aaron 78

2 Bill 76

3 Cindy 89

3 Cindy 89

4 Damon 90

5 Ella 73

可以看到,Union Union All 的区别之一在于对重复结果的处理。

UNION 在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进 行排序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录,最常 见的是过程表与历史表 UNION。如:

select * from gc_dfys

union

select * from ls_jg_dfys

这个 SQL 在运行时先取出两个表的结果,再用排序空间进行排序删除重复的记录,最 后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。

UNION ALL 只是简单的将两个结果合并后就返回。这样,如果返回的两个结果集中有 重复的数据,那么返回的结果集就会包含重复的数据了。

从效率上说,UNION ALL 要比 UNION 快很多,所以,如果可以确认合并的两个结果集 中不包含重复的数据的话,那么就使用 UNION ALL,

7.分页语句

取出 sql 表中第 31 40 的记录(以自动增长 ID 为主键)

sql server 方案 1:

select top 10 * from t where id not in (select top 30 id from t order by id )

orde by id

sql server 方案 2:

select top 10 * from t where id in (select top 40 id from t order by id) order by id desc

mysql 方案:select * from t order by id limit 30,10

oracle 方案:select * from (select rownum r,* from t where r<=40) where r>30

--------------------待整理进去的内容------------------------------------- pageSize=20;

pageNo = 5;

1.分页技术 1(直接利用 sql 语句进行分页,效率最高和最推荐的) mysql:sql = "select * from articles limit " + (pageNo-1)*pageSize + "," + pageSize;

 oracle: sql = "select * from " +

"(select rownum r,* from " +

"(select * from articles order by postime desc)" +

"where rownum<= " + pageNo*pageSize +") tmp " + "where r>" + (pageNo-1)*pageSize;

注释:7 行保证 rownum 的顺序是确定的,因为 oracle 的索引会造成 rownum 返回不同的 值

 简洋 :没有 order by ,rownum 按顺序输出,一旦有了 order by,rownum 不按顺序输 出了,这说明 rownum 是排序前的编号。如果对 order by 从句中的字段建立了索引,那么, rownum 也是按顺序输出的,因为这时候生成原始的查询结果集时会参照索引表的顺序来构 建。

sqlserver:sql = "select top 10 * from id not id(select top " + (pageNo-1)*pageSize + "id from articles)"

DataSource ds = new InitialContext().lookup(jndiurl); Connection cn = ds.getConnection();

//"select * from user where id=?" --->binary directive PreparedStatement pstmt = cn.prepareSatement(sql); ResultSet rs = pstmt.executeQuery()

while(rs.next()) {

out.println(rs.getString(1)); }

2.不可滚动的游标 pageSize=20; pageNo = 5;

cn = null

stmt = null;

rs = null;

try

{

sqlserver:sql = "select

* from articles";

DataSource ds = new InitialContext().lookup(jndiurl); Connection cn = ds.getConnection();

//"select * from user where id=?" --->binary directive PreparedStatement pstmt = cn.prepareSatement(sql); ResultSet rs = pstmt.executeQuery()

for(int j=0;j<(pageNo-1)*pageSize;j++) {

rs.next(); }

int i=0;

while(rs.next() && i<10) {

i++; out.println(rs.getString(1));

 }

} cacth(){} finnaly

{

if(rs!=null)try{rs.close();}catch(Exception e){} if(stm.........

if(cn............

}

3.可滚动的游标 pageSize=20; pageNo = 5;

cn = null

stmt = null;

rs = null;

try

{

sqlserver:sql = "select

* from articles";

DataSource ds = new InitialContext().lookup(jndiurl);

Connection cn = ds.getConnection();

//"select * from user where id=?" --->binary directive

PreparedStatement

cn.prepareSatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,...); //根据上面这行代码的异常 SQLFeatureNotSupportedException,就可判断驱动是否支持可滚 动游标

ResultSet rs = pstmt.executeQuery() rs.absolute((pageNo-1)*pageSize) int i=0;

while(rs.next() && i<10)

{

i++;

out.println(rs.getString(1)); }

} cacth(){} finnaly

{

if(rs!=null)try{rs.close();}catch(Exception e){} if(stm.........

if(cn............

}

pstmt =

 8.用一条 SQL 语句 查询出每门课都大于 80 分的学生姓名

name kecheng fenshu 张三 语文 81 张三 数学 75 李四 语文 76 李四 数学 90 王五 语文 81 王五 数学 100 王五 英语 90

准备数据的 sql 代码:

create table score(id int primary key auto_increment,name varchar(20),subject varchar(20),score int);

insert into score values

(null,'张三','语文',81),

(null,'张三','数学',75),

(null,'李四','语文',76),

(null,'李四','数学',90),

(null,'王五','语文',81),

(null,'王五','数学',100),

(null,'王五 ','英语',90);

 :当百思不得其解时,请理想思维,把小变成大做,把大变成小做,

答案:

A: select distinct name from score where name not in (select distinct name from score where score<=80)

B:select distince name t1 from score where 80< all (select score from score where name=t1);

9.所有部门之间的比赛组合

一个叫 department 的表,里面只有一个字段 name,一共有 4 条纪录,分别是 a,b,c,d,对应

四个球对,现在四个球对进行比赛,用一条 sql 语句显示所有可能的比赛组合.

:select a.name, b.name from team a, team b where a.name < b.name

 10.每个月份的发生额都比 101 科目多的科目

请用 SQL 语句实现:TestDB 数据表中查询出所有月份的发生额都比 101 科目相应月份的 发生额高的科目。请注意:TestDB 中有很多科目,都有 1-12 月份的发生额。 AccID:科目代码,Occmonth:发生额月份,DebitOccur:发生额。 数据库名:JcyAudit,数据集:Select * from TestDB

准备数据的 sql 代码:

drop table if exists TestDB;

create table TestDB(id int primary key auto_increment,AccID varchar(20), Occmonth date, DebitOccur bigint);

insert into TestDB values

(null,'101','1988-1-1',100),

(null,'101','1988-2-1',110),

(null,'101','1988-3-1',120),

(null,'101','1988-4-1',100),

(null,'101','1988-5-1',100),

(null,'101','1988-6-1',100),

(null,'101','1988-7-1',100),

(null,'101','1988-8-1',100);

--复制上面的数据,故意把第一个月份的发生额数字改小一点

insert into TestDB values

(null,'102','1988-1-1',90),

(null,'102','1988-2-1',110),

(null,'102','1988-3-1',120),

(null,'102','1988-4-1',100),

(null,'102','1988-5-1',100),

(null,'102','1988-6-1',100),

(null,'102','1988-7-1',100),

(null,'102','1988-8-1',100);

--复制最上面的数据,故意把所有发生额数字改大一点

insert into TestDB values

(null,'103','1988-1-1',150),

(null,'103','1988-2-1',160),

(null,'103','1988-3-1',180),

(null,'103','1988-4-1',120),

(null,'103','1988-5-1',120),

(null,'103','1988-6-1',120),

(null,'103','1988-7-1',120),

(null,'103','1988-8-1',120);

--复制最上面的数据,故意把所有发生额数字改大一点

insert into TestDB values

(null,'104','1988-1-1',130),

(null,'104','1988-2-1',130),

(null,'104','1988-3-1',140),

 (null,'104','1988-4-1',150),

(null,'104','1988-5-1',160),

(null,'104','1988-6-1',170),

(null,'104','1988-7-1',180),

(null,'104','1988-8-1',140); --复制最上面的数据,故意把第二个月份的发生额数字改小一点 insert into TestDB values

(null,'105','1988-1-1',100), (null,'105','1988-2-1',80), (null,'105','1988-3-1',120), (null,'105','1988-4-1',100), (null,'105','1988-5-1',100), (null,'105','1988-6-1',100), (null,'105','1988-7-1',100), (null,'105','1988-8-1',100); 答案:

select distinct AccID from TestDB where AccID not in

(select TestDB.AccIDfrom TestDB,

(select * from TestDB where AccID='101') as db101

where TestDB.Occmonth=db101.Occmonth and TestDB.DebitOccur<=db101.DebitOccur );

11.统计每年每月的信息

year month amount 1991 1 1.1 1991 2 1.2 1991 3 1.3

1991 4 1.4

1992 1 2.1

1992 2 2.2 1992 3 2.3 1992 4 2.4 查成这样一个结果

year m1    m2    m3    m4

1991 1.1 1.2 1.3 1.4

1992 2.1 2.2 2.3 2.4

 :这个与工资条非常类似,与学生的科目成绩也很相似。

准备 sql 语句:

drop table if exists sales;

 create table sales(id int auto_increment primary key,year varchar(10), month varchar(10), amount float(2,1));

insert into sales values

(null,'1991','1',1.1),

(null,'1991','2',1.2),

(null,'1991','3',1.3),

(null,'1991','4',1.4),

(null,'1992','1',2.1),

(null,'1992','2',2.2),

(null,'1992','3',2.3),

(null,'1992','4',2.4);

答案一、

select sales.year ,

(select t.amount from sales t where t.month='1' and t.year= sales.year) '1', (select t.amount from sales t where t.month='1' and t.year= sales.year) '2', (select t.amount from sales t where t.month='1' and t.year= sales.year) '3', (select t.amount from sales t where t.month='1' and t.year= sales.year) as '4' from sales group by year;

12.显示文章标题,发帖人、最后回复时间

:id,title,postuser,postdate,parentid

准备 sql 语句:

drop table if exists articles;

create table articles(id int auto_increment primary key,title varchar(50), postuser varchar(10), postdate datetime,parentid int references articles(id));

insert into articles values (null,'第一条','张三','1998-10-10 12:32:32',null), (null,'第二条','张三','1998-10-10 12:34:32',null), (null,'第一条回复 1','李四','1998-10-10 12:35:32',1), (null,'第二条回复 1','李四','1998-10-10 12:36:32',2), (null,'第一条回复 2','王五','1998-10-10 12:37:32',1), (null,'第一条回复 3','李四','1998-10-10 12:38:32',1), (null,'第二条回复 2','李四','1998-10-10 12:39:32',2), (null,'第一条回复 4','王五','1998-10-10 12:39:40',1);

答案:

select a.title,a.postuser,

(select max(postdate) from articles where parentid=a.id) reply

from articles a where a.parentid is null;

注释:子查询可以用在选择列中,也可用于 where 的比较条件中,还可以用于 from 从句中。

 13.删除除了 id 号不同,其他都相同的学生冗余信息

2.学生表 如下:

id号 学号 姓名课程编号课程名称分数

1 2005001 张三 0001 数学 69

2 2005002 李四 0001 数学 89

3 2005001 张三 0001 数学 69

A: delete from tablename where id not in(select min(id ) from tablename group by 学号,姓 名,课程编号,课程名称,分数)

实验:

create table student2(id int auto_increment primary key,code varchar(20),name varchar(20)); insert into student2 values(null,'2005001','张三'),(null,'2005002','李四'),(null,'2005001','张三');

//如下语句,mysql 报告错误,可能删除依赖后面统计语句,而删除又导致统计语句结果不 一致。

delete from student2 where id not in(select min(id) from student2 group by name); //但是,如下语句没有问题:

select * from student2 where id not in(select min(id) from student2 group by name); //于是,我想先把分组的结果做成虚表,然后从虚表中选出结果,最后再将结果作为删除的 条件数据。

delete from student2 where id not in(select mid from (select min(id) mid from student2 group by name) as t);

或者:

delete from student2 where id not in(select min(id) from (select * from s tudent2) as t group by t.name);

14.航空网的几个航班查询题:

表结构如下:

flight{flightID,StartCityID ,endCityID,StartTime}

city{cityID, CityName)

实验环境:

create table city(cityID int auto_increment primary key,cityName varchar(20)); create table flight (flightID int auto_increment primary key,

StartCityID int references city(cityID), endCityID int references city(cityID), StartTime timestamp);

//航班本来应该没有日期部分才好,但是下面的题目当中涉及到了日期 insert into city values(null,'北京'),(null,'上海'),(null,'广州');

insert into flight values

(null,1,2,'9:37:23'),(null,1,3,'9:37:23'),(null,1,2,'10:37:23'),(null,2,3,'10:37:23');

 1、查询起飞城市是北京的所有航班,按到达城市的名字排序

参与运算的列是我起码能够显示出来的那些列,但最终我不一定把它们显示出来。各个表组 合出来的中间结果字段中必须包含所有运算的字段。

select * from flight f,city c

where f.endcityid = c.cityid and startcityid =

(select c1.cityid from city c1 where c1.cityname = "北京") order by c.cityname asc;

mysql> select flight.flightid,'北京' startcity, e.cityname from flight,city e wh ere flight.endcityid=e.cityid and flight.startcityid=(select cityid from city wh ere cityname='北京');

mysql> select flight.flightid,s.cityname,e.cityname from flight,city s,city e wh ere flight.startcityid=s.cityid and s.cityname='北京' and flight.endCityId=e.cit yID order by e.cityName desc;

2、查询北京到上海的所有航班纪录(起飞城市,到达城市,起飞时间,航班号) select c1.CityName,c2.CityName,f.StartTime,f.flightID

from city c1,city c2,flight f

where f.StartCityID=c1.cityID

and f.endCityID=c2.cityID

and c1.cityName='北京'

and c2.cityName='上海' 3、查询具体某一天(2005-5-8)的北京到上海的的航班次数 select count(*) from

(select c1.CityName,c2.CityName,f.StartTime,f.flightID from city c1,city c2,flight f

where f.StartCityID=c1.cityID

and f.endCityID=c2.cityID

and c1.cityName='北京'

and c2.cityName='上海'

and 查帮助获得的某个日期处理函数(startTime) like '2005-5-8%'

mysql 中 取日期部分进行比较的示例代码如下:

select * from flight where date_format(starttime,'%Y-%m-%d')='1998-01-02'

15.查出比经理薪水还高的员工信息: Drop table if not exists employees;

 create table employees(id int primary key auto_increment,name varchar(50) ,salary int,managerid int references employees(id));

insert into employees values (null,' lhm',10000,null), (null,' zxx',15000,1 ),(null,'flx',9000,1),(null,'tg',10000,2),(null,'wzg',10000,3);

Wzg 大于 flx,lhm 大于 zxx

解题思路:

根据 sql 语句的查询特点,是逐行进行运算,不可能两行同时参与运算。

涉及了员工薪水和经理薪水,所有,一行记录要同时包含两个薪水,所有想到要把这个表自 关联组合一下。

首先要组合出一个包含有各个员工及该员工的经理信息的长记录,譬如,左半部分是 员工,右半部分是经理。而迪卡尔积会组合出很多垃圾信息,先去除这些垃圾信息。

select e.* from employees e,employees m where e.managerid=m.id and e.sala ry>m.salary;

16、求出小于 45 岁的各个老师所带的大于 12 岁的学生人数

数据库中有 3 个表 teacher ,student ,tea_stu 关系表。 teacher teaID name age

student stuID name age

teacher_student teaID stuID

要求用一条 sql 查询出这样的结果

1.显示的字段要有老师 name, age 每个老师所带的学生人数 2 只列出老师 age 40 以下,学生 age 12 以上的记录

预备知识:

1.sql 语句是对每一条记录依次处理,条件为真则执行动作(select,insert,delete,update)

2.只要是迪卡尔积,就会产生“垃圾”信息,所以,只要迪卡尔积了,我们首先就要想到清除“垃圾”信息 实验准备:

drop table if exists tea_stu; drop table if exists teacher; drop table if exists student;

create table teacher(teaID int primary key,name varchar(50),age int);

create table student(stuID int primary key,name varchar(50),age int);

create table tea_stu(teaID int references teacher(teaID),stuID int references student(stuID));

insert into teacher values(1,'zxx',45), (2,'lhm',25) , (3,'wzg',26) , (4,'tg',27); insert into student values(1,'wy',11), (2,'dh',25) , (3,'ysq',26) , (4,'mxc',27); insert into tea_stu values(1,1), (1,2), (1,3);

insert into tea_stu values(2,2), (2,3), (2,4);

insert into tea_stu values(3,3), (3,4), (3,1); insert into tea_stu values(4,4), (4,1), (4,2) , (4,3);

结果:2 3,3 2,4 3

 解题思路:(真实面试答题时,也要写出每个分析步骤,如果纸张不够,就找别人要) 1 要会统计分组信息,统计信息放在中间表中:

select teaid,count(*) from tea_stu group by teaid;

2 接着其实应该是筛除掉小于 12 岁的学生,然后再进行统计,中间表必须与 student 关联才能得到 12 岁以下学 生和把该学生记录从中间表中剔除,代码是:

select tea_stu.teaid,count(*) total from student,tea_stu

where student.stuid=tea_stu.stuid and student.age>12 group by tea_stu.teaid

3.接着把上面的结果做成虚表与 teacher 进行关联,并筛除大于 45 的老师

select teacher.teaid,teacher.name,total from teacher ,(select tea_stu.tea

id,count(*) total from student,tea_stu where student.stuid=tea_stu.stuid and stu dent.age>12 group by tea_stu.teaid) as tea_stu2 where teacher.teaid=tea_stu2.tea id and teacher.age<45;

17.求出发帖最多的人:

select authorid,count(*) total from articles group by authorid

having total=

(select max(total2) from (select count(*) total2 from articles group by authorid) as t);

select t.authorid,max(t.total) from

(select authorid,count(*) total from articles )as t 这条语句不行,因为 max 只有一列,不能与其他列混淆。

select authorid,count(*) total from articles

group by authorid having total=max(total)也不行。

18、一个用户表中有一个积分字段,假如数据库中有 100 多 万个用户,若要在每年第一天凌晨将积分清零,你将考虑什 么,你将想什么办法解决?

alter table drop column score;

alter table add colunm score int; 可能会很快,但是需要试验,试验不能拿真实的环境来操刀,并且要注意, 这样的操作时无法回滚的,在我的印象中,只有 inert update delete DML 语句才能回滚,

 对于 create table,drop table ,alter table DDL 语句是不能回滚。

解决方案一,update user set score=0; 解决方案二,假设上面的代码要执行好长时间,超出我们的容忍范围,那我就 alter table user drop column score;alter table user add column score int

下面代码实现每年的那个凌晨时刻进行清零。

Runnable runnable = new Runnable(){

public void run(){ clearDb();

schedule(this,new Date(new Date().getYear()+1,0,0)); }

};

schedule(runnable,

new Date(new Date().getYear()+1,0,1));

19、一个用户具有多个角色,请查询出该表中具有该用户的 所有角色的其他用户。

select count(*) as num,tb.id from

tb,

(select role from tb where id=xxx) as t1 where

tb.role = t1.role and tb.id != t1.id group by tb.id

having

num = select count(role) from tb where id=xxx;

20. xxx 公司的 sql 面试 Table EMPLOYEES Structure:

EMPLOYEE_ID FIRST_NAME LAST_NAME

Salary number(8,2), HiredDate DATE, Departmentid number(2)

Table Departments Structure:

Departmentid number(2) Primary Key,

NUMBER VARCHAR2(25),

VARCHAR2(25),

Primary Key,

DepartmentName VARCHAR2(25).

(2)基于上述 EMPLOYEES 表写出查询:写出雇用日期在今年的,或者工资在[1000,2000] 之间的,或者员工姓名(last_name)以’Obama’打头的所有员工,列出这些员工的全部个人

信息。(4 )

select * from employees

where Year(hiredDate) = Year(date())

or (salary between 1000 and 200) or left(last_name,3)='abc';

(3) 基于上述 EMPLOYEES 表写出查询:查出部门平均工资大于 1800 元的部门的所有员工, 列出这些员工的全部个人信息。(4 )

mysql> select id,name,salary,deptid did from employee1 where (select avg(salary)

from employee1 where deptid = did) > 1800;

(4) 基于上述 EMPLOYEES 表写出查询:查出个人工资高于其所在部门平均工资的员工, 列出这些员工的全部个人信息及该员工工资高出部门平均工资百分比。(5 )

select employee1.*,(employee1.salary-t.avgSalary)*100/employee1.salary from employee1,

(select deptid,avg(salary) avgSalary from employee1 group by deptid) as t where employee1.deptid = t.deptid and employee1.salary>t.avgSalary;

21、注册 Jdbc 驱动程序的三种方式

22、用 JDBC 如何调用存储过程 代码如下:

package com.huawei.interview.lym;

import java.sql.CallableStatement; import java.sql.Connection;

import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Types;

public class JdbcTest {

/**

* @param args */

public static void main(String[] args) { // TODO Auto-generated method stub Connection cn = null; CallableStatement cstmt = null;

 try {

//这里最好不要这么干,因为驱动名写死在程序中了 Class.forName("com.mysql.jdbc.Driver"); //实际项目中,这里应用DataSource数据,如果用框架, //这个数据源不需要我们编码创建,我们只需Datasource ds =

context.lookup()

           //cn = ds.getConnection();

cn = DriverManager.getConnection("jdbc:mysql:///test","root","root");

cstmt = cn.prepareCall("{call insert_Student(?,?,?)}"); cstmt.registerOutParameter(3,Types.INTEGER); cstmt.setString(1, "wangwu");

cstmt.setInt(2, 25);

cstmt.execute(); //get第几个,不同的数据库不一样,建议不写 System.out.println(cstmt.getString(3));

} catch (Exception e) {

// TODO Auto-generated catch block e.printStackTrace();

}

finally

{

/*try{cstmt.close();}catch(Exception e){} try{cn.close();}catch(Exception e){}*/ try {

if(cstmt != null) cstmt.close();

if(cn != null) cn.close();

} catch (SQLException e) {

// TODO Auto-generated catch block e.printStackTrace();

} }

}

23JDBC 中的 PreparedStatement 相比 Statement 的好处

:一个 sql 命令发给服务器去执行的步骤为:语法检查,语义分析,编译成内部指令,缓 存指令,执行指令等过程。

select * from student where id =3----缓存-- xxxxx 二进制命令

select * from student where id =3----直接取- xxxxx 二进制命令

select * from student where id =4--- - 会怎么干?

 如果当初是 select * from student where id =?--- - 又会怎么干? 上面说的是性能 高

可以防止 sql 注入。

24. 写一个用 jdbc 连接并访问 oracle 数据的程序代码

25Class.forName 的作用?为什么要用?

:按参数中指定的字符串形式的类名去搜索并加载相应的类,如果该类字节码已经被加载 过,则返回代表该字节码的 Class 实例对象,否则,按类加载器的委托机制去搜索和加载该 类,如果所有的类加载器都无法加载到该类,则抛出 ClassNotFoundException。加载完这个 Class 字节码后,接着就可以使用 Class 字节码的 newInstance 方法去创建该类的实例对象了。 有时候,我们程序中所有使用的具体类名在设计时(即开发时)无法确定,只有程序运行时 才能确定,这时候就需要使用 Class.forName 去动态加载该类,这个类名通常是在配置文件 中配置的,例如,spring ioc 中每次依赖注入的具体类就是这样配置的,jdbc 的驱动类名 通常也是通过配置文件来配置的,以便在产品交付使用后不用修改源程序就可以更换驱动类 名。

26、大数据量下的分页解决方法。

:最好的办法是利用 sql 语句进行分页,这样每次查询出的结果集中就只包含某页的数据 内容。再 sql 语句无法实现分页的情况下,可以考虑对大的结果集通过游标定位方式来获取 某页的数据。

sql 语句分页,不同的数据库下的分页方案各不一样,下面是主流的三种数据库的分页 sql: sql server:

String sql =

"select top " + pageSize + " * from students where id not in" +

"(select top " + pageSize * (pageNumber-1) + " id from students order by id)" +

"order by id"; mysql:

String sql =

"select * from students order by id limit " + pageSize*(pageNumber-1) + "," + pageSize;

oracle:

String sql =

"select * from " +

(select *,rownum rid from (select * from students order by postime desc) where rid<=" +

 pagesize*pagenumber + ") as t" +

"where t>" + pageSize*(pageNumber-1);

27、用 JDBC 查询学生成绩单, 把主要代码写出来(考试概 率极大).

Connection cn = null; PreparedStatement pstmt =null; Resultset rs = null;

try

{

Class.forname(driveClassName);

cn = DriverManager.getConnection(url,username,password);

pstmt = cn.prepareStatement(select score.* from score ,student +

where score.stuId = student.id and student.name = ?); pstmt.setString(1,studentName);

Resultset rs = pstmt.executeQuery();

while(rs.next())

{

}

}catch(Exception e){e.printStackTrace();} finally

{

system.out.println(rs.getInt(subject)

+

+ rs.getFloat(score) );

if(rs != null) try{ rs.close() }catch(exception e){} if(pstmt != null) try{pstmt.close()}catch(exception e){} if(cn != null) try{ cn.close() }catch(exception e){}

}

28、这段代码有什么不足之处?

try {

Connection conn = ...;

Statement stmt = ...;

ResultSet rs = stmt.executeQuery("select * from table1");

while(rs.next()) {

}

} catch(Exception ex) {

}

:没有 finally 语句来关闭各个对象,另外,使用 finally 之后,要把变量的 定义放在 try 语句块的外面,以便在 try 语句块之外的 finally 块中仍可以访问 这些变量。

29、说出数据连接池的工作机制是什么?

J2EE 服务器启动时会建立一定数量的池连接,并一直维持不少于此数目的池连接。客 户端程序需要连接时,池驱动程序会返回一个未使用的池连接并将其表记为忙。如果 当前没有空闲连接,池驱动程序就新建一定数量的连接,新建连接的数量有配置参数 决定。当使用的池连接调用完成后,池驱动程序将此连接表记为空闲,其他调用就可 以使用这个连接。

实现方式,返回的 Connection 是原始 Connection 的代理,代理 Connection close 方法 不是真正关连接,而是把它代理的 Connection 对象还回到连接池中。

30、为什么要用 ORM? JDBC 有何不一样?

orm 是一种思想,就是把 object 转变成数据库中的记录,或者把数据库中的记录转变成 objecdt,我们可以用 jdbc 来实现这种思想,其实,如果我们的项目是严格按照 oop 方 式编写的话,我们的 jdbc 程序不管是有意还是无意,就已经在实现 orm 的工作了。

现在有许多 orm 工具,它们底层调用 jdbc 来实现了 orm 工作,我们直接使用这些工具, 就省去了直接使用 jdbc 的繁琐细节, 高了开发效率,现在用的较多的 orm 工具是 hibernate。也听说一些其他 orm 工具,toplink,ojb 等。

. XML 部分

1xml 有哪些解析技术?区别是什么?

:DOM,SAX,STAX

DOM:处理大型文件时其性能下降的非常厉害。这个问题是由 DOM 的树结构所造成的,这 种结构占用的内存较多,而且 DOM 必须在解析文件之前把整个文档装入内存,适合对 XML 的随机访问 SAX:不现于 DOM,SAX 是事件驱动型的 XML 解析方式。它顺序读取 XML 文 件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结 束时,它会触发一个事件,用户通过在其回调事件中写入处理代码来处理 XML 文件,适合 对 XML 的顺序访问

STAX:Streaming API for XML (StAX)

 讲解这些区别是不需要特别去比较,就像说传智播客与其他培训机构的区别时,我们只需说 清楚传智播客有什么特点和优点就行了,这就已经间接回答了彼此的区别。

2、你在项目中用到了 xml 技术的哪些方面?如何实现的?

:用到了数据存贮,信息配置两方面。在做数据交换平台时,将不能数据源的数据组装成 XML 文件,然后将 XML 文件压缩打包加密后通过网络传送给接收者,接收解密与解压缩 后再同 XML 文件中还原相关信息进行处理。在做软件配置时,利用 XML 可以很方便的进 行,软件的各种配置参数都存贮在 XML 文件中。

3、用 jdom 解析 xml 文件时如何解决中文问题?如何解析?

:看如下代码,用编码方式加以解决 package test;

import java.io.*;

public class DOMTest

{

private String inFile = "c:\\people.xml"

private String outFile = "c:\\people.xml"

public static void main(String args[])

{

new DOMTest();

}

public DOMTest()

{

try

{

javax.xml.parsers.DocumentBuilder builder = javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder(); org.w3c.dom.Document doc = builder.newDocument();

org.w3c.dom.Element root = doc.createElement("老师");

org.w3c.dom.Element wang = doc.createElement("");

org.w3c.dom.Element liu = doc.createElement(""); wang.appendChild(doc.createTextNode("我是王老师"));

root.appendChild(wang);

doc.appendChild(root);

javax.xml.transform.Transformer transformer = javax.xml.transform.TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(javax.xml.transform.OutputKeys.ENCODING, "gb2312"); transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes"); transformer.transform(new javax.xml.transform.dom.DOMSource(doc),

new

 javax.xml.transform.stream.StreamResult(outFile)); }

catch (Exception e)

{

System.out.println (e.getMessage()); }

}

}

4、编程用 JAVA 解析 XML 的方式.

:SAX 方式解析 XML,XML 文件如下:

<?xml version=1.0 encoding=gb2312?>

<person>

<name>王小明</name>

<college>信息学院</college> <telephone>6258113</telephone>

<notes>,1955 年生,博士,95 年调入海南大学</notes> </person>

事件回调类 SAXHandler.java import java.io.*;

import java.util.Hashtable; import org.xml.sax.*;

public class SAXHandler extends HandlerBase {

private Hashtable table = new Hashtable(); private String currentElement = null;

private String currentValue = null;

public void setTable(Hashtable table)

{

this.table = table;

}

public Hashtable getTable()

{

return table;

}

public void startElement(String tag, AttributeList attrs) throws SAXException

{

currentElement = tag;

}

public void characters(char[] ch, int start, int length) throws SAXException

{

 currentValue = new String(ch, start, length);

}

public void endElement(String name) throws SAXException {

if (currentElement.equals(name))

table.put(currentElement, currentValue);

}

}

JSP 内容显示源码,SaxXml.jsp:

<HTML>

<HEAD>

<TITLE>剖析 XML 文件 people.xml</TITLE>

</HEAD>

<BODY>

<%@ page errorPage=ErrPage.jsp

contentType=text/html;charset=GB2312 %>

<%@ page import=java.io.* %>

<%@ page import=java.util.Hashtable %>

<%@ page import=org.w3c.dom.* %>

<%@ page import=org.xml.sax.* %>

<%@ page import=javax.xml.parsers.SAXParserFactory %>

<%@ page import=javax.xml.parsers.SAXParser %>

<%@ page import=SAXHandler %>

<%

File file = new File(c:\people.xml);

FileReader reader = new FileReader(file);

Parser parser;

SAXParserFactory spf = SAXParserFactory.newInstance();

SAXParser sp = spf.newSAXParser();

SAXHandler handler = new SAXHandler();

sp.parse(new InputSource(reader), handler);

Hashtable hashTable = handler.getTable();

out.println(<TABLE BORDER=2><CAPTION>教师信息表</CAPTION>); out.println(<TR><TD>姓名</TD> + <TD> +

(String)hashTable.get(new String(name)) + </TD></TR>); out.println(<TR><TD>学院</TD> + <TD> +

(String)hashTable.get(new String(college))+</TD></TR>); out.println(<TR><TD>电话</TD> + <TD> +

(String)hashTable.get(new String(telephone)) + </TD></TR>); out.println(<TR><TD>备注</TD> + <TD> +

(String)hashTable.get(new String(notes)) + </TD></TR>); out.println(</TABLE>);

%>

</BODY> </HTML>

5XML 文档定义有几种形式?它们之间有何本质区别?解 析 XML 文档有哪几种方式?

a: 两种形式 dtd schema,b: 本质区别:schema 本身是 xml ,可以被 XML 解析器解 析(这也是从 DTD 上发展 schema 的根本目的),c:DOM,SAX,STAX

DOM:处理大型文件时其性能下降的非常厉害。这个问题是由 DOM 的树结构所造成 的,这种结构占用的内存较多,而且 DOM 必须在解析文件之前把整个文档装入内存, 适合对 XML 的随机访问

SAX:不现于 DOM,SAX 是事件驱动型的 XML 解析方式。它顺序读取 XML 文件,不需 要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束 时,它会触发一个事件,用户通过在其回调事件中写入处理代码来处理 XML 文件, 适合对 XML 的顺序访问

STAX:Streaming API for XML (StAX)

 

六、框架部分

1、什么是ORM

答:

a.对象关系映射(Object-Relational Mapping,简称ORM)是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术.

b.实体中的属性和数据库表中列通过xml或注解来完成映射。正向工程:根据实体生成表,逆向工程:根据表生成实体。

2、持久层设计要考虑的问题有哪些?你用过的持久层框架有哪些?

答:

a.所谓"持久"就是将数据保存到可掉电式存储设备中以便今后使用。就是将内存中的数据保存到关系型数据库、文件系统、消息队列等提供持久化支持的设备中。

b.持久层就是系统中专注于实现数据持久化的相对独立的层面。

持久层设计的目标包括: dao- 数据存储逻辑的分离,提供抽象化的数据访问接口。 - 数据访问底层实现的分离,可以在不修改代码的情况下切换底层实现。 - 资源管理和调度的分离,在数据访问层实现统一的资源调度(如缓存机制)。 - 数据抽象,提供更面向对象的数据操作。

 

持久层框架有:

Hibernate 

MyBatis 

Spring Data 

ActiveJDBC

 

3HibernateSessionFactory是线程安全的吗?Session是线程安全的吗(两个线程能够共享同一个Session吗)?

答:

a.SessionFactory对应Hibernate的一个数据存储的概念,它是线程安全的,可以被多个线程并发访问。SessionFactory一般只会在启动的时候构建。对于应用程序,最好将SessionFactory通过单例模式进行封装以便于访问。

Session是一个轻量级非线程安全的对象(线程间不能共享session),它表示与数据库进行交互的一个工作单元。Session是由SessionFactory创建的,在任务完成之后它会被关闭。Session是持久层服务对外提供的主要接口。Session会延迟获取数据库连接(也就是在需要的时候才会获取)。为了避免创建太多的session,可以使用ThreadLocalsession和当前线程绑定在一起,这样可以让同一个线程获得的总是同一个sessionHibernate 3SessionFactorygetCurrentSession()方法就可以做到。

 

4HibernateSessionloadget方法的区别是什么?

① 如果没有找到符合条件的记录,get方法返回nullload方法抛出异常。 
② get方法直接返回实体类对象,load方法返回实体类对象的代理。 
③ 在Hibernate 3之前,get方法只在一级缓存中进行数据查找,如果没有找到对应的数据则越过二级缓存,直接发出SQL语句完成数据读取;load方法则可以从二级缓存中获取数据;从Hibernate 3开始,get方法不再是对二级缓存只写不读,它也是可以访问二级缓存的。

 

说明:对于load()方法Hibernate认为该数据在数据库中一定存在可以放心的使用代理来实现延迟加载,如果没有数据就抛出异常,而通过get()方法获取的数据可以不存在。

 

5Sessionsave()update()merge()lock()saveOrUpdate()persist()方法分别是做什么的?有什么区别?

 

答:Hibernate的对象有三种状态:瞬时态(transient)、持久态(persistent)和游离态(detached

把图画出来。

 

瞬时态的实例可以通过调用save()persist()或者saveOrUpdate()方法变成持久态;

游离态的实例可以通过调用 update()saveOrUpdate()lock()或者replicate()变成持久态。save()persist()将会引发SQLINSERT语句,而update()merge()会引发UPDATE语句。save()update()的区别在于一个是将瞬时态对象变成持久态,一个是将游离态对象变为持久态。merge()方法可以完成save()update()方法的功能,它的意图是将新的状态合并到已有的持久化对象上或创建新的持久化对象。

对于persist()方法,按照官方文档的说明:① persist()方法把一个瞬时态的实例持久化,但是并不保证标识符被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时间;② persist()方法保证当它在一个事务外部被调用的时候并不触发一个INSERT语句,当需要封装一个长会话流程的时候,persist()方法是很有必要的;③ save()方法不保证第②条,它要返回标识符,所以它会立即执行INSERT语句,不管是在事务内部还是外部。至于lock()方法和update()方法的区别,update()方法是把一个已经更改过的脱管状态的对象变成持久状态;lock()方法是把一个没有更改过的脱管状态的对象变成持久状态。

 

6、阐述Session加载实体对象的过程。 

 

答:Session加载实体对象的步骤是: 
① Session在调用数据库查询功能之前,首先会在一级缓存中通过实体类型和主键进行查找,如果一级缓存查找命中且数据状态合法,则直接返回; 
② 如果一级缓存没有命中,接下来Session会在当前NonExists记录(相当于一个查询黑名单,如果出现重复的无效查询可以迅速做出判断,从而提升性能)中进行查找,如果NonExists中存在同样的查询条件,则返回null 
③ 如果一级缓存查询失败则查询二级缓存,如果二级缓存命中则直接返回; 
④ 如果之前的查询都未命中,则发出SQL语句,如果查询未发现对应记录则将此次查询添加到SessionNonExists中加以记录,并返回null 
⑤ 根据映射配置和SQL语句得到ResultSet,并创建对应的实体对象; 
⑥ 将对象纳入Session(一级缓存)的管理; 
⑦ 如果有对应的拦截器,则执行拦截器的onLoad方法; 
⑧ 如果开启并设置了要使用二级缓存,则将数据对象纳入二级缓存; 
⑨ 返回数据对象。

 

7Query接口的list方法和iterate方法有什么区别? 

答: 
① list()方法无法利用一级缓存和二级缓存(对缓存只写不读),它只能在开启查询缓存的前提下使用查询缓存;iterate()方法可以充分利用缓存,如果目标数据只读或者读取频繁,使用iterate()方法可以减少性能开销。 
② list()方法不会引起N+1查询问题,而iterate()方法可能引起N+1查询问题

 

8.什么是HibernateN+1问题

http://blog.csdn.net/xtayhicbladwin/article/details/4739852

 

9Hibernate如何实现分页查询? 

 

答:通过Hibernate实现分页查询,开发人员只需要提供HQL语句(调用SessioncreateQuery()方法)或查询条件(调用SessioncreateCriteria()方法)、设置查询起始行数(调用QueryCriteria接口的setFirstResult()方法)和最大查询行数(调用QueryCriteria接口的setMaxResults()方法),并调用QueryCriteria接口的list()方法,Hibernate会自动生成分页查询的SQL语句。

 

setFirstResult()设置查询起始行数

setMaxResults()最大查询行

 

10、锁机制有什么用?简述Hibernate的悲观锁和乐观锁机制。

答:有些业务逻辑在执行过程中要求对数据进行排他性的访问,于是需要通过一些机制保证在此过程中数据被锁住不会被外界修改,这就是所谓的锁机制。 

Hibernate支持悲观锁和乐观锁两种锁机制。

 

悲观锁,顾名思义悲观的认为在数据处理过程中极有可能存在修改数据的并发事务(包括本系统的其他事务或来自外部系统的事务),于是将处理的数据设置为锁定状态。悲观锁必须依赖数据库本身的锁机制才能真正保证数据访问的排他性。

 

乐观锁,顾名思义,对并发事务持乐观态度(认为对数据的并发操作不会经常性的发生),通过更加宽松的锁机制来解决由于悲观锁排他性的数据访问对系统性能造成的严重影响。最常见的乐观锁是通过数据版本标识来实现的,读取数据时获得数据的版本号,更新数据时将此版本号加1,然后和数据库表对应记录的当前版本号进行比较,如果提交的数据版本号大于数据库中此记录的当前版本号则更新数据,否则认为是过期数据无法更新。Hibernate中通过Sessionget()load()方法从数据库中加载对象时可以通过参数指定使用悲观锁;而乐观锁可以通过给实体类加整型的版本字段再通过XML@Version注解进行配置。

提示:使用乐观锁会增加了一个版本字段,很明显这需要额外的空间来存储这个版本字段,浪费了空间,但是乐观锁会让系统具有更好的并发性,这是对时间的节省。因此乐观锁也是典型的空间换时间的策略。

 

11、如何理解Hibernate的延迟加载机制?在实际应用中,延迟加载与Session关闭的矛盾是如何处理的? 

答:延迟加载就是并不是在读取的时候就把数据加载进来,而是等到使用时再加载。

Hibernate使用了虚拟代理机制实现延迟加载,我们使用Sessionload()方法加载数据或者一对多关联映射在使用延迟加载的情况下从一的一方加载多的一方,得到的都是虚拟代理,简单的说返回给用户的并不是实体本身,而是实体对象的代理。代理对象在用户调用getter方法时才会去数据库加载数据。但加载数据就需要数据库连接。而当我们把会话关闭时,数据库连接就同时关闭了。

 

延迟加载与session关闭的矛盾一般可以这样处理: 
① 关闭延迟加载特性。这种方式操作起来比较简单,因为Hibernate的延迟加载特性是可以通过映射文件或者注解进行配置的,但这种解决方案存在明显的缺陷。首先,出现"no session or session was closed"通常说明系统中已经存在主外键关联,如果去掉延迟加载的话,每次查询的开销都会变得很大。 
② 在session关闭之前先获取需要查询的数据,可以使用工具方法Hibernate.isInitialized()判断对象是否被加载,如果没有被加载则可以使用Hibernate.initialize()方法加载对象。 
③ 使用拦截器或过滤器延长Session的生命周期直到视图获得数据。Spring整合Hibernate提供的OpenSessionInViewFilterOpenSessionInViewInterceptor就是这种做法。

 

12、举一个多对多关联的例子,并说明如何实现多对多关联映射。

答:例如:商品和订单、学生和课程都是典型的多对多关系。可以在实体类上通过@ManyToMany注解配置多对多关联或者通过映射文件中的和标签配置多对多关联,但是实际项目开发中,很多时候都是将多对多关联映射转换成两个多对一关联映射来实现的。

 

13、谈一下你对继承映射的理解。

答:继承关系的映射策略有三种: 
① 每个继承结构一张表(table per class hierarchy),不管多少个子类都用一张表。 
② 每个子类一张表(table per subclass),公共信息放一张表,特有信息放单独的表。 
③ 每个具体类一张表(table per concrete class),有多少个子类就有多少张表。 
第一种方式属于单表策略,其优点在于查询子类对象的时候无需表连接,查询速度快,适合多态查询;缺点是可能导致表很大。后两种方式属于多表策略,其优点在于数据存储紧凑,其缺点是需要进行连接查询,不适合多态查询。

 

14、简述Hibernate常见优化策略。

 

答:这个问题应当挑自己使用过的优化策略回答,常用的有: 
① 制定合理的缓存策略(二级缓存、查询缓存)。 
② 采用合理的Session管理机制。 
③ 尽量使用延迟加载特性。 
④ 设定合理的批处理参数。 
⑤ 如果可以,选用UUID作为主键生成器。 
⑥ 如果可以,选用基于版本号的乐观锁替代悲观锁。 
⑦ 在开发过程中, 开启hibernate.show_sql选项查看生成的SQL,从而了解底层的状况;开发完成后关闭此选项。
⑧ 考虑数据库本身的优化,合理的索引、恰当的数据分区策略等都会对持久层的性能带来可观的提升,但这些需要专业的DBA(数据库管理员)提供支持。

 

15、谈一谈Hibernate的一级缓存、二级缓存和查询缓存。

答:HibernateSession提供了一级缓存的功能,默认总是有效的,当应用程序保存持久化实体、修改持久化实体时,Session并不会立即把这种改变提交到数据库,而是缓存在当前的Session中,除非显示调用了Sessionflush()方法或通过close()方法关闭Session。通过一级缓存,可以减少程序与数据库的交互,从而提高数据库访问性能。 SessionFactory级别的二级缓存是全局性的,所有的Session可以共享这个二级缓存。不过二级缓存默认是关闭的,需要显示开启并指定需要使用哪种二级缓存实现类(可以使用第三方提供的实现)。一旦开启了二级缓存并设置了需要使用二级缓存的实体类,SessionFactory就会缓存访问过的该实体类的每个对象,除非缓存的数据超出了指定的缓存空间。 
一级缓存和二级缓存都是对整个实体进行缓存,不会缓存普通属性,如果希望对普通属性进行缓存,可以使用查询缓存。查询缓存是将HQLSQL语句以及它们的查询结果作为键值对进行缓存,对于同样的查询可以直接从缓存中获取数据。查询缓存默认也是关闭的,需要显示开启。

 

16HibernateDetachedCriteria类是做什么的?

答:DetachedCriteriaCriteria的用法基本上是一致的,但Criteria是由SessioncreateCriteria()方法创建的,也就意味着离开创建它的SessionCriteria就无法使用了。DetachedCriteria不需要Session就可以创建(使用DetachedCriteria.forClass()方法创建),所以通常也称其为离线的Criteria,在需要进行查询操作的时候再和Session绑定(调用其getExecutableCriteria(Session)方法),这也就意味着一个DetachedCriteria可以在需要的时候和不同的Session进行绑定。

 

17@OneToMany注解的mappedBy属性有什么作用?

答:@OneToMany用来配置一对多关联映射,但通常情况下,一对多关联映射都由多的一方来维护关联关系,例如学生和班级,应该在学生类中添加班级属性来维持学生和班级的关联关系(在数据库中是由学生表中的外键班级编号来维护学生表和班级表的多对一关系),如果要使用双向关联,在班级类中添加一个容器属性来存放学生,并使用@OneToMany注解进行映射,此时mappedBy属性就非常重要。如果使用XML进行配置,可以用<set>标签的inverse="true"设置来达到同样的效果。

 

 

18MyBatis中使用#$书写占位符有什么区别? 

答:#将传入的数据都当成一个字符串,会对传入的数据自动加上引号;$将传入的数据直接显示生成在SQL中。注意:使用$占位符可能会导致SQL注入攻击,能用#的地方就不要使用$,写order by子句的时候应该用$而不是#

 

19、解释一下MyBatis中命名空间(namespace)的作用。 
答:在大型项目中,可能存在大量的SQL语句,这时候为每个SQL语句起一个唯一的标识(ID)就变得并不容易了。为了解决这个问题,在MyBatis中,可以为每个映射文件起一个唯一的命名空间,这样定义在这个映射文件中的每个SQL语句就成了定义在这个命名空间中的一个ID。只要我们能够保证每个命名空间中这个ID是唯一的,即使在不同映射文件中的语句ID相同,也不会再产生冲突了。

 

20MyBatis中的动态SQL是什么意思? 

答:对于一些复杂的查询,我们可能会指定多个查询条件,但是这些条件可能存在也可能不存在,例如在58同城上面找房子,我们可能会指定面积、楼层和所在位置来查找房源,也可能会指定面积、价格、户型和所在位置来查找房源,此时就需要根据用户指定的条件动态生成SQL语句。如果不使用持久层框架我们可能需要自己拼装SQL语句,还好MyBatis提供了动态SQL的功能来解决这个问题。

 

MyBatis中用于实现动态SQL的元素主要有: - if - choose / when / otherwise - trim - where - set - foreach

下面是映射文件的片段。

    <select id="foo" parameterType="Blog" resultType="Blog">

        select * from t_blog where 1 = 1

        <if test="title != null">

            and title = #{title}

        </if>

        <if test="content != null">

            and content = #{content}

        </if>

        <if test="owner != null">

            and owner = #{owner}

        </if>

   </select>

当然也可以像下面这些书写。

    <select id="foo" parameterType="Blog" resultType="Blog">

        select * from t_blog where 1 = 1

        <choose>

            <when test="title != null">

                and title = #{title}

            </when>

            <when test="content != null">

                and content = #{content}

            </when>

            <otherwise>

                and owner = "owner1"

            </otherwise>

        </choose>

    </select>

再看看下面这个例子。

    <select id="bar" resultType="Blog">

        select * from t_blog where id in

        <foreach collection="array" index="index"

            item="item" open="(" separator="," close=")">

            #{item}

        </foreach>

    </select>

 

 

21、什么是IoCDIDI是如何实现的? 

答:

IoC叫控制反转,DI叫依赖注入;

IoC就是把对象调用交由容器,

IoC由容器来创建对象并管理对象之间的依赖关系

 

DI是对IoC更准确的描述,即组件之间的依赖关系由容器在运行期决定。

 

依赖注入可以通过setter方法注入(设值注入)、构造器注入和接口注入三种方式来实现,

 

22SpringBean的作用域有哪些?

答:在Spring的早期版本中,仅有两个作用域:singletonprototype,前者表示Bean以单例的方式存在;后者表示每次从容器中调用Bean时,都会返回一个新的实例,prototype通常翻译为原型。

23、解释一下什么叫AOP(面向切面编程)? 
答:AOPAspect-Oriented Programming)指一种程序设计范型,该范型以一种称为切面(aspect)的语言构造为基础,切面是一种新的模块化机制,用来描述分散在对象、类或方法中的横切关注点(crosscutting concern)。

 

24、你是如何理解"横切关注"这个概念的? 
答:"横切关注"是会影响到整个应用程序的关注功能,它跟正常的业务逻辑是正交的,没有必然的联系,但是几乎所有的业务逻辑都会涉及到这些关注功能。通常,事务、日志、安全性等关注就是应用中的横切关注功能。

25、你如何理解AOP中的连接点(Joinpoint)、切点(Pointcut)、增强(Advice)、引介(Introduction)、织入(Weaving)、切面(Aspect)这些概念? (上课的图)
答: a. 连接点(Joinpoint):程序执行的某个特定位置(如:某个方法调用前、调用后,方法抛出异常后)。一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就是连接点。Spring仅支持方法的连接点。 b. 切点(Pointcut):如果连接点相当于数据中的记录,那么切点相当于查询条件,一个切点可以匹配多个连接点。Spring AOP的规则解析引擎负责解析切点所设定的查询条件,找到对应的连接点。 c. 增强(Advice):增强是织入到目标类连接点上的一段程序代码。Spring提供的增强接口都是带方位名的,如:BeforeAdviceAfterReturningAdviceThrowsAdvice等。很多资料上将增强译为“通知”,这明显是个词不达意的翻译,让很多程序员困惑了许久。

说明: Advice在国内的很多书面资料中都被翻译成"通知",但是很显然这个翻译无法表达其本质,有少量的读物上将这个词翻译为"增强",这个翻译是对Advice较为准确的诠释,我们通过AOP将横切关注功能加到原有的业务逻辑上,这就是对原有业务逻辑的一种增强,这种增强可以是前置增强、后置增强、返回后增强、抛异常时增强和包围型增强。

d. 引介(Introduction):引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的未该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。 e. 织入(Weaving):织入是将增强添加到目标类具体连接点上的过程,AOP有三种织入方式:①编译期织入:需要特殊的Java编译期(例如AspectJajc);②装载期织入:要求使用特殊的类加载器,在装载类的时候对类进行增强;③运行时织入:在运行时为目标类生成代理实现增强。Spring采用了动态代理的方式实现了运行时织入,而AspectJ采用了编译期织入和装载期织入的方式。 f. 切面(Aspect):切面是由切点和增强(引介)组成的,它包括了对横切关注功能的定义,也包括了对连接点的定义。

补充:代理模式是GoF提出的23种设计模式中最为经典的模式之一,代理模式是对象的结构模式,它给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。简单的说,代理对象可以完成比原对象更多的职责,当需要为原对象添加横切关注功能时,就可以使用原对象的代理对象。我们在打开Office系列的Word文档时,如果文档中有插图,当文档刚加载时,文档中的插图都只是一个虚框占位符,等用户真正翻到某页要查看该图片时,才会真正加载这张图,这其实就是对代理模式的使用,代替真正图片的虚框就是一个虚拟代理;Hibernateload方法也是返回一个虚拟代理对象,等用户真正需要访问对象的属性时,才向数据库发出SQL语句获得真实对象。

 

26Spring中自动装配的方式有哪些? 
答: - no:不进行自动装配,手动设置Bean的依赖关系。 - byName:根据Bean的名字进行自动装配。 - byType:根据Bean的类型进行自动装配。 - constructor:类似于byType,不过是应用于构造器的参数,如果正好有一个Bean与构造器的参数类型相同则可以自动装配,否则会导致错误。 - autodetect:如果有默认的构造器,则通过constructor的方式进行自动装配,否则使用byType的方式进行自动装配。

说明:自动装配没有自定义装配方式那么精确,而且不能自动装配简单属性(基本类型、字符串等),在使用时应注意。

 

27Spring中如何使用注解来配置Bean?有哪些相关的注解? 
答:首先需要在Spring配置文件中增加如下配置:

<context:component-scan base-package="org.example"/>

然后可以用@Component@Controller@Service@Repository注解来标注需要由Spring IoC容器进行对象托管的类。这几个注解没有本质区别,只不过@Controller通常用于控制器,@Service通常用于业务逻辑类,@Repository通常用于仓储类(例如我们的DAO实现类),普通的类用@Component来标注。

 

28Spring支持的事务管理类型有哪些?你在项目中使用哪种方式? 
答:Spring支持编程式事务管理和声明式事务管理。许多Spring框架的用户选择声明式事务管理,因为这种方式和应用程序的关联较少,因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理,尽管在灵活性方面它弱于编程式事务管理,因为编程式事务允许你通过代码控制业务。

事务分为全局事务和局部事务。全局事务由应用服务器管理,需要底层服务器JTA支持(如WebLogicWildFly等)。局部事务和底层采用的持久化方案有关,例如使用JDBC进行持久化时,需要使用Connetion对象来操作事务;而采用Hibernate进行持久化时,需要使用Session对象来操作事务。

Spring提供了如下所示的事务管理器。

事务管理器实现类

目标对象

DataSourceTransactionManager

注入DataSource

HibernateTransactionManager

注入SessionFactory

JdoTransactionManager

管理JDO事务

JtaTransactionManager

使用JTA管理事务

PersistenceBrokerTransactionManager

管理ApacheOJB事务

 

 

29、如何在Web项目中配置SpringIoC容器? 
答:如果需要在Web项目中使用SpringIoC容器,可以在Web项目配置文件web.xml中做出如下配置:

<context-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>classpath:applicationContext.xml</param-value>

</context-param>

 

<listener>

    <listener-class>

        org.springframework.web.context.ContextLoaderListener

    </listener-class>

</listener>

 

30、如何在Web项目中配置Spring MVC 
答:要使用Spring MVC需要在Web项目配置文件中配置其前端控制器DispatcherServlet,如下所示:

<web-app>

    <servlet>

        <servlet-name>example</servlet-name>

        <servlet-class>

            org.springframework.web.servlet.DispatcherServlet

        </servlet-class>

        <load-on-startup>1</load-on-startup>

    </servlet>

 

    <servlet-mapping>

        <servlet-name>example</servlet-name>

        <url-pattern>*.html</url-pattern>

    </servlet-mapping>

</web-app>

 

说明:上面的配置中使用了*.html的后缀映射,这样做一方面不能够通过URL推断采用了何种服务器端的技术,另一方面可以欺骗搜索引擎,因为搜索引擎不会搜索动态页面,这种做法称为伪静态化。

 

31Spring MVC的工作原理是怎样的? 
答:Spring MVC的工作原理如下图所示:  
① 客户端的所有请求都交给前端控制器DispatcherServlet来处理,它会负责调用系统的其他模块来真正处理用户的请求。 
② DispatcherServlet收到请求后,将根据请求的信息(包括URLHTTP协议方法、请求头、请求参数、Cookie等)以及HandlerMapping的配置找到处理该请求的Handler(任何一个对象都可以作为请求的Handler)。 
③在这个地方Spring会通过HandlerAdapter对该处理器进行封装。 
④ HandlerAdapter是一个适配器,它用统一的接口对各种Handler中的方法进行调用。 
⑤ Handler完成对用户请求的处理后,会返回一个ModelAndView对象给DispatcherServletModelAndView顾名思义,包含了数据模型以及相应的视图的信息。 
⑥ ModelAndView的视图是逻辑视图,DispatcherServlet还要借助ViewResolver完成从逻辑视图到真实视图对象的解析工作。 
⑦ 当得到真正的视图对象后,DispatcherServlet会利用视图对象对模型数据进行渲染。 
⑧ 客户端得到响应,可能是一个普通的HTML页面,也可以是XMLJSON字符串,还可以是一张图片或者一个PDF文件。

 

 

32、如何在Spring IoC容器中配置数据源? 
答: DBCP配置:

<bean id="dataSource"

        class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

    <property name="driverClassName" value="${jdbc.driverClassName}"/>

    <property name="url" value="${jdbc.url}"/>

    <property name="username" value="${jdbc.username}"/>

    <property name="password" value="${jdbc.password}"/>

</bean>

 

<context:property-placeholder location="jdbc.properties"/>

C3P0配置:

<bean id="dataSource"

        class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">

    <property name="driverClass" value="${jdbc.driverClassName}"/>

    <property name="jdbcUrl" value="${jdbc.url}"/>

    <property name="user" value="${jdbc.username}"/>

    <property name="password" value="${jdbc.password}"/>

</bean>

 

<context:property-placeholder location="jdbc.properties"/>

提示: DBCP的详细配置在第153题中已经完整的展示过了。

 

 

33、如何配置配置事务增强? 
答:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

     xmlns:aop="http://www.springframework.org/schema/aop"

     xmlns:tx="http://www.springframework.org/schema/tx"

     xsi:schemaLocation="

     http://www.springframework.org/schema/beans

     http://www.springframework.org/schema/beans/spring-beans.xsd

     http://www.springframework.org/schema/tx

     http://www.springframework.org/schema/tx/spring-tx.xsd

     http://www.springframework.org/schema/aop

     http://www.springframework.org/schema/aop/spring-aop.xsd">

 

  <!-- this is the service object that we want to make transactional -->

  <bean id="fooService" class="x.y.service.DefaultFooService"/>

 

  <!-- the transactional advice -->

  <tx:advice id="txAdvice" transaction-manager="txManager">

  <!-- the transactional semantics... -->

  <tx:attributes>

    <!-- all methods starting with 'get' are read-only -->

    <tx:method name="get*" read-only="true"/>

    <!-- other methods use the default transaction settings (see below) -->

    <tx:method name="*"/>

  </tx:attributes>

  </tx:advice>

 

  <!-- ensure that the above transactional advice runs for any execution

    of an operation defined by the FooService interface -->

  <aop:config>

  <aop:pointcut id="fooServiceOperation"

    expression="execution(* x.y.service.FooService.*(..))"/>

  <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>

  </aop:config>

 

  <!-- don't forget the DataSource -->

  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"

    destroy-method="close">

  <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>

  <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>

  <property name="username" value="scott"/>

  <property name="password" value="tiger"/>

  </bean>

 

  <!-- similarly, don't forget the PlatformTransactionManager -->

  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

  <property name="dataSource" ref="dataSource"/>

  </bean>

 

  <!-- other <bean/> definitions here -->

 

</beans>

 

 

34、选择使用Spring框架的原因(Spring框架为企业级开发带来的好处有哪些)? 
答:可以从以下几个方面作答: - 非侵入式:支持基于POJO的编程模式,不强制性的要求实现Spring框架中的接口或继承Spring框架中的类。 - IoC容器:IoC容器帮助应用程序管理对象以及对象之间的依赖关系,对象之间的依赖关系如果发生了改变只需要修改配置文件而不是修改代码,因为代码的修改可能意味着项目的重新构建和完整的回归 HYPERLINK "http://lib.csdn.net/base/softwaretest" \t "_blank" \o "软件测试知识库" 测试。有了IoC容器,程序员再也不需要自己编写工厂、单例,这一点特别符合Spring的精神"不要重复的发明轮子" - AOP(面向切面编程):将所有的横切关注功能封装到切面(aspect)中,通过配置的方式将横切关注功能动态添加到目标代码上,进一步实现了业务逻辑和系统服务之间的分离。另一方面,有了AOP程序员可以省去很多自己写代理类的工作。 - MVCSpringMVC框架是非常优秀的,从各个方面都可以甩Struts 2几条街,为Web表示层提供了更好的解决方案。 - 事务管理:Spring以宽广的胸怀接纳多种持久层技术,并且为其提供了声明式的事务管理,在不需要任何一行代码的情况下就能够完成事务管理。 - 其他:选择Spring框架的原因还远不止于此,SpringJava企业级开发提供了一站式选择,你可以在需要的时候使用它的部分和全部,更重要的是,你甚至可以在感觉不到Spring存在的情况下,在你的项目中使用Spring提供的各种优秀的功能。

 

35Spring IoC容器配置Bean的方式? 
答: - 基于XML文件进行配置。 - 基于注解进行配置。 - 基于Java程序进行配置(Spring 3+

 

 

36、阐述Spring框架中Bean的生命周期? 
答: 
① Spring IoC容器找到关于Bean的定义并实例化该Bean 
② Spring IoC容器对Bean进行依赖注入。 
③ 如果Bean实现了BeanNameAware接口,则将该Beanid传给setBeanName方法。 
④ 如果Bean实现了BeanFactoryAware接口,则将BeanFactory对象传给setBeanFactory方法。 
⑤ 如果Bean实现了BeanPostProcessor接口,则调用其postProcessBeforeInitialization方法。 
⑥ 如果Bean实现了InitializingBean接口,则调用其afterPropertySet方法。 
⑦ 如果有和Bean关联的BeanPostProcessors对象,则这些对象的postProcessAfterInitialization方法被调用。 
⑧ 当销毁Bean实例时,如果Bean实现了DisposableBean接口,则调用其destroy方法。

 

 

37、依赖注入时如何注入集合属性? 
答:可以在定义Bean属性时,通过<list> / <set> / <map> / <props>分别为其注入列表、集合、映射和键值都是字符串的映射属性。

 

38Spring中的自动装配有哪些限制? 
答: - 如果使用了构造器注入或者setter注入,那么将覆盖自动装配的依赖关系。 - 基本数据类型的值、字符串字面量、类字面量无法使用自动装配来注入。 - 优先考虑使用显式的装配来进行更精确的依赖注入而不是使用自动装配。

 

39、在Web项目中如何获得SpringIoC容器? 
答:

WebApplicationContext ctx =

WebApplicationContextUtils.getWebApplicationContext(servletContext);

 

 40SSHSSM的组成及其区别

SSH指的是:spring+Struts+hibernate;而SSM指的是:spring +SpringMVC + MyBatis

SSH 通常指的是 Struts2 做前端控制器,spring 管理各层的组件,hibernate 负责持久化层。

SSM 则指的是 SpringMVC 做前端控制器,spring 管理各层的组件,MyBatis 负责持久化层。

 

共同之处是都使用了Spring的依赖注入DI来管理各层的组件,使用了面向切面编程AOP来实现日志管理,权限认证,事务等通用功能的切入。

不同之处是 Struts2 SpringMVC 做前端控制器的区别,hibernate MyBatis 做持久化时的区别。

Struts2 也可以和 MyBatis 搭配使用,SpringMVC 也可以和 Hibernate 搭配使用。

 

41SpringMVCStruts : 

1)两者有个共同之处,那就是两者都数据javaweb层的开发框架,都是mvc模式的的经典产品,都实现了页面分离控制的功能,但是两者之间是有区别的。 2)在开发中,人们更愿意使用SpringMVC而不是Struts。因为SpringMVC分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。在扩展和灵活性上更胜一筹。

3Struts的优势在于静态注入,插件机制和拦截器链,但是struts存在漏洞,经常会被作为攻击点进行冲击。相比更加安全简单的SpringMVC,开发者渐渐开发放弃了它。 

 

42Hibernate MyBatis: 1HibernateMybatis都是流行的持久层开发框架,一句话概括:MyBatis 简单易上手; 2hibernate成熟,市场推广率高。 3MyBatis可以进行更为细致的SQL优化,可以减少查询字段。 4MyBatis容易掌握,而Hibernate门槛较高。 5)更重要的是,mybatis提供了对应各种用途、功能的插件,而hibernate在这一方面是远远比不上mybatis的。 6HibernateDAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。 7Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。 8Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL 9Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。 10)但是hibernat缺点很明确,如果涉及到多张关联表的调用时:   1. 多表关联等比较复杂,使用的成本并不低;   2. 效率比较低,在大型项目中很少会使用到它,因为sql都是自动生成的,不太好进行人工的优化。 

 

43Struts 2中,Action通过什么方式获得用户从页面输入的数据,又是通过什么方式把其自身的数据传给视图的?

答:Action从页面获取数据有三种方式:

①通过Action属性接受参数

②通过域模型获取参数

③通过模型驱动获取参数 (ModelDriven<T>

Action将数据存入值栈(Value Stack)中,视图可以通过表达式语言(EL)从值栈中获取数据。

 

44、简述Struts 2是如何实现MVC

答:MVC架构模式要求应用程序的输入、处理和输出三者分离,将系统分成模型(Model)、视图(View)、控制器(Controller)三个部分,通过控制器实现模型和视图的解耦合,使得应用程序的开发和维护变得容易,如下图所示。其中,模型代表了应用程序的数据和处理这些数据的规则,同时还可以为视图提供的查询保存相关的状态,通常由JavaBean来实现,模型的代码写一次就可以被多个视图重用;视图用来组织模型的内容,它从模型中获得数据,并将数据展现给用户,在Struts 2中通常由JSPFreemarker模板等来实现;控制器负责从客户端接受请求并将其转换为某种行为,行为完成后再选择一个视图来呈现给用户,控制器本身不需要输出任何内容,它只是接收请求并决定调用哪个模型组件去处理请求,StrutsPrepareAndExecuteFilter过滤器是Struts 2中的核心,它和一系列的Action构成了Struts 2中的控制器。

45、阐述Struts 2如何实现用户输入验证。在你做过的项目中使用的是那种验证方式,为什么选择这种方式?

答:Struts 2可以使用手动验证和自动验证框架实现用户输入验证。自动验证框架是将对输入的验证规则放在XML文件中,这种方式比较灵活,可以在不修改代码的情况下修改验证的规则。

 

46、阐述Struts 2中的Action如何编写?Action是否采用了单例?

答:Struts2Action有三种写法:

POJO

②实现Action接口重写execute()方法

③继承ActionSupport

Action没有像Servlet一样使用单实例多线程的工作方式,很明显,每个Action要接收不同用户的请求参数,这就意味着Action是有状态的,因此在设计上使用了每个请求对应一个Action的处理方式。

47Struts 2中的Action并没有直接收到用户的请求,那它为什么可以处理用户的请求,又凭什么知道一个请求到底交给哪个Action来处理?

答:Struts2的核心过滤器接收到用户请求后,会对用户的请求进行简单的预处理(例如解析、封装参数),然后通过反射来创建Action实例,并调用Action中指定的方法来处理用户请求。

要决定请求交给哪一个Action来处理有两种方式:1利用配置文件:可以在配置文件中通过<action>标签配置和请求对应的Action类以及要调用的方法;2利用约定:Struts2中可以使用约定(convention)插件,例如约定xxx总是对应XxxAction,这是对约定优于配置理念的践行。

 

48、你经常用到的Struts 2常量配置有哪些?

答:

struts.i18n.encoding– 指定默认编码

struts.objectFactory/ struts.objectFactory.spring.autoWire – 对象工厂 / Spring的自动装配方式(名字、类型)

struts.devMode– 是否使用开发模式

struts.locale– 指定默认区域,默认值是en_US

struts.i18n.resources– 国际化使用的资源文件

struts.enable.DynamicMethodInvocation– 是否允许动态方法调用

 

49、简述Struts2的异常处理机制。

答:Struts 2提供了声明式的异常处理机制,可以在配置文件中加入如下代码:

<global-exception-mappings>

<exception-mapping exception=”…” result=”…”/>

</global-exception-mappings>

 

50、说一下你对约定优于配置(CoC)的理解。

答:约定优于配置(convention over configuration),也称作按约定编程,是一种软件设计范式,旨在减少软件开发人员需做决定的数量,获得简单的好处而又不失灵活性。CoC本质是说,开发人员仅需规定应用中不符约定的部分。例如,如果模型中有个名为Sale的类,那么数据库中对应的表就会默认命名为sales。只有在偏离这一约定时,例如将该表命名为products_sold,才需写有关这个名字的配置。如果您所用工具的约定与你的期待相符,便可省去配置;反之,你可以配置来达到你所期待的方式。遵循约定虽然损失了一定的灵活性,不能随意安排目录结构,不能随意进行函数命名,但是却能减少配置。更重要的是,遵循约定可以帮助开发人员遵守构建标准,包括各种命名的规范,这对团队开发是非常有利的。

 

51Struts2中如何实现I18N

答:首先,为不同语言地区编写不同的资源文件;然后在Struts 2配置文件中配置struts.i18n.custom.resources常量;在Action中可以通过调用getText()方法读取资源文件获取国际化资源。

52、简述拦截器的工作原理以及你在项目中使用过哪些自定义拦截器。

答:Struts 2中定义了拦截器的接口以及默认实现,实现了Interceptor接口或继承了AbstractInterceptor的类可以作为拦截器。接口中的init()方法在拦截器被创建后立即被调用,它在拦截器的生命周期内只被调用一次,可以在该方法中对相关资源进行必要的初始化。每拦截一个请求,intercept()方法就会被调用一次。destory()方法将在拦截器被销毁之前被调用它在拦截器的生命周期内也只被调用一次。

项目中使用过的有权限拦截器、执行时间拦截器、令牌拦截器等。

 

 

53、如何在Struts2中使用Ajax功能?

答:以下是Struts 2中实现Ajax的可选方式:

JSON plugin+  HYPERLINK "http://lib.csdn.net/base/jquery" \t "_blank" \o "jQuery知识库" jQuery

DOJO plugin

DWR (DirectWeb Remoting)

 

54、谈一下拦截器和过滤器的区别。

答:拦截器和过滤器都可以用来实现横切关注功能,其区别主要在于:

①拦截器是基于Java反射机制的,而过滤器是基于接口回调的。

②过滤器依赖于Servlet容器,而拦截器不依赖于Servlet容器。

③拦截器只能对Action请求起作用,而过滤器可以对所有请求起作用。

④拦截器可以访问Action上下文、值栈里的对象,而过滤器不能。

55、谈一下Struts 1Struts 2的区别。

 

 

56Struts 2中如何访问HttpServletRequestHttpSessionServletContext三个域对象

答:有两种方式:

①通过ServletActionContext的方法获得;

②通过ServletRequestAwareSessionAwareServletContextAware接口注入。

 

57Struts 2中的默认包struts-default有什么作用?

答:它定义了Struts 2内部的众多拦截器和Result类型,而Struts 2很多核心的功能都是通过这些内置的拦截器实现,如:从请求中把请求参数封装到action、文件上传和数据验证等等都是通过拦截器实现的。在Struts 2的配置文件中,自定义的包继承了struts-default包就可以使用Struts 2为我们提供的这些功能。

 

58、简述值栈(Value-Stack)的原理和生命周期

答:Value-Stack贯穿整个 Action 的生命周期,保存在request作用域中,所以它和request的生命周期一样。当Struts 2接受一个请求时,会创建ActionContextValue-StackAction对象,然后把Action存放进Value-Stack,所以Action的实例变量可以通过OGNL访问。由于Action是多实例的,和使用单例的Servlet不同,每个Action都有一个对应的Value-StackValue-Stack存放的数据类型是该Action的实例,以及该Action中的实例变量,Action对象默认保存在栈顶。

 

59J2EE是什么?

:Je22Sun公司提出的多层(multi-diered),分布式(distributed),基于组件(component-base)的企业级应用模型(enterpriese application model).在这样的一个应用系统中,可按照功能划分为不同的组件,这些组件又可在不同计算机上,并且处于相应的层次(tier)中。所属层次包括客户层(clietn tier)组件,web层和组件,Business层和组件,企业信息系统(EIS)层。

 

一个另类的回答:j2ee就是增删改查。

 

60J2EE是技术还是平台还是框架? 什么是J2EE

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

   J2EE也是一个框架,包括JDBCJNDIRMIJMSEJBJTA等技术。

 

 

61、开发中都用到了那些设计模式?用在什么场合?

每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心。通过这种方式,你可以无数次地使用那些已有的解决方案,无需在重复相同的工作。主要用到了MVC的设计模式。用来开发JSP/Servlet或者J2EE的相关应用。简单工厂模式等

 

 

62SQL Server Oracle 以及 MySQL 有哪些区别?

 

1.数据库对比。
----1.Oracle:最贵,功能最多,安装最不方便,Oracle环境里的其他相关组件最多,支持平台数量一般,使用中等方便,开发中等方便,运维中等方便,不开源,速度最慢,最安全。
----2.Microsoft SQL Server 2014:中等贵,功能最少,安装中等方便,Microsoft SQL Server 2014环境里的其他相关组件最少,支持平台最少,使用最方便,开发最方便,运维最方便,不开源,速度中等,一般安全。
----3.Mysql:免费,功能中等,安装最方便,Mysql环境里的其他相关组件数量中等,支持平台最多,使用最不方便,开发最不方便,运维最不方便,有开源版本,速度最快,最不安全。

2.从不同职业的角度来看。
----1.对于初学数据库的孩子来说,比如学生,建议学习Microsoft SQL Server 2014。原因主要是方便。微软平台,从Windows操作系统、VS开发工具、C#语言等等,无论安装、使用、学习都很方便,并且书籍也很多。使用这个平台,能让你更集中注意力在学习上,避免很多无关因素的打扰。比如,安装Oracle的话,需要了解很多非数据库知识,学生时期,本来时间就少,因此不推荐在此时期学习Oracle。

----2.对于在国企、事业单位里的人来说,建议精通Windows\Office\C#\Microsoft SQL Server 2014,因为这类工作岗位上会经常做一些小软件的快速开发,以及数据的快速处理。

----3.对于在百度、阿里巴巴这类互联网企业的人来说,建议精通Mysql。因为这类企业不愿意花钱购买正版软件,同时又需要对源代码进行定制,因此Mysql最适合这类企业。

----4.对于专门从事大型软件项目开发,以及电信、电商、金融等,这类企业有钱,并且对数据安全最重视,因此,这类企业适合使用Oracle

 

 

63

项目开发流程

可行性分析 >>> 可行性分析报告 / 项目开发计划书

需求分析 >>> 需求规格说明书 

OOAD(用例图、时序图、活动图)

界面原型:帮助理解需求、业务层设计时推导事务脚本

设计 >>> 概要设计说明书/详细设计说明书 

抽取业务实体(领域对象):类图、E-R图(概念设计阶段)

分层架构:确定各层的技术实现方案(具体到使用的框架、数据库服务器、应用服务器等)。业务层设计:事务脚本模式(事务:用户发送一次请求就是一个事务;脚本:一个方法或一个函数;事务脚本:把一次请求封装为一个方法或一个函数;事务脚本模式:一个事务开始于脚本的打开,终止于脚本的关闭)。业务层涉及的对象有三种类型:事务脚本类(封装了业务的流程)、数据访问对象(DAO,封装了持久化操作)、数据传输对象(DTO,封装了失血/贫血领域对象),三者之间的关系是事务脚本类组合(聚合)数据访问对象,这二者都依赖了数据传输对象

正向工程(UML类图生成Java代码)和逆向工程(Java代码生成UML类图)

数据库物理设计(ER图转换成表间关系图、建库和建表、使用工具插入测试数据)

编码

测试 >>> 测试报告 / 缺陷报告 

单元测试:对软件中的最小可测试单元进行检查和验证,在Java中是对类中的方法进行测试,可以使用JUnit工具来实施。

集成测试:集成测试也叫组装测试或联合测试。在单元测试的基础上,将所有模块按照设计要求组装成为子系统进行测试。

系统测试:将已经确认的软件、硬件、外设、网络等元素结合在一起,进行信息系统的各种组装测试和确认测试,系统测试是针对整个产品系统进行的测试,目的是验证系统是否满足了需求规格的定义,找出与需求规格不符或与之矛盾的地方,从而提出更加完善的方案。

验收测试:在软件产品完成了单元测试、集成测试和系统测试之后,产品发布之前所进行的软件测试活动。它是技术测试的最后一个阶段,也称为交付测试。验收测试的目的是确保软件准备就绪,并且可以让最终用户将其用于执行软件的既定功能和任务。

交付和维护 >>> 用户手册 / 操作手册

项目管理

版本控制:CVS/SVN/Git

自动构建:Ant/Maven/Ivy/Gradle

持续集成:Hudson/Jenkins

系统架构

负载均衡服务器:F5A10

应用服务器: 

HTTP服务器:ApacheNginXHTTP、反向代理、邮件代理服务器)

Servlet容器:TomcatResin

EJB容器:WildFlyJBoss Application Server)、GlassFishWeblogicWebsphere

数据库服务器:MySQLOracle

第三方工具(插件)应用

图表工具:基于jQuery的图表插件(如jQchartFlotCharted等)、Chart.jsHighcharts等。

报表工具:Pentaho ReportingiReportDynamicReports等。

文档处理:POIiText等。

工作流引擎:jBPMOpenWFESnakerSWAMP等。

作业调度:QuartzJobServerOddjob等。

缓存服务:EhCachememcachedSwarmCache等。

消息队列:Open-MQZeroMQ等。

安全框架:ShiroPicketBox等。

搜索引擎:IndexTankLuceneElasticSearch等。

Ajax框架:jQueryExtJSDWR等。

UI插件:EasyUIMiniUI等。

富文本框:UEditorCKEditor等。

 

64

Activiti工作流面试相关知识

1:什么是工作流,工作流的核心对象是什么,activiti共操作数据库多少张表
  * 工作流就是多个参与者,按照某种预定义的规则,传递业务信息,进行审核的功能一个框架(Activiti)
  * processEngine,调用Service,从而操作数据库的表
  * 23表

2:工作流中RepositoryServiceRuntimeServiceTaskServiceHistoryService分别表示什么操作
RepositoryService:流程定义和部署对象
RuntimeService:执行管理,包括流程实例和执行对象(正在执行)
TaskService:执行任务相关的(正在执行)
HistoryService:历史管理
IdentityServiceActiviti表的用户角色组


3:流程实例和执行对象的区别
 * 流程从开始到结束的最大分支,一个流程中,流程实例只有1个
 * 执行对象,就是按照流程定义的规则执行一次的操作,一个流程中,执行对象可以有多个


4:流程变量在项目中的作用
 * 1:用来传递业务参数,目的就是审核人可以通过流程变量查看申请人的一些审核信息
   2:在连线的condition中设置流程变量,用来指定应该执行的连线${message=='重要'}

   3:使用流程变量指定个人任务和组任务的办理人#{userID}

5activiti工作流中,如果一个任务完成后,存在多条连线,应该如何处理?
  * 使用流程变量
  * 当一个任务完成之后,根据这几条连线的条件和设置流程变量,例如${流程变量的名称=='流程变量的值'}{}符号是boolean类型,判断走哪条连线
6activiti工作流中,排他网关和并行网关都能执行什么功能
  排他网关:分支,通过连线的流程变量,判断执行哪条连线,如果条件不符合,会执行默认的连线离开,注意:只能执行其中的一个流程。
  并行网关:可以同时执行多个流程,直到总流程的结束。可以对流程进行分支和聚合,注意:流程实例和执行对象是不一样的


7:分配个人任务的三种方式
*直接给值,在Xxxx.bpmn文件中指定
*流程变量${流程变量的名称}或者#{}*使用类 监听这个类(实现一个接口),指定任务的办理人(setAssgnee())


8:个人任务和组任务的查询一样吗?
  * 不一样
  * 都是用TaskService完成(TaskService.createTasQuery)
  * 个人任务(taskAssgnee),组任务(taskCandidateUser)
  * 数据库存放,个人任务(类型:参与),组任务(类型,参与,候选)

一、 什么是工作流

以请假为例,现在大多数公司的请假流程是这样的

员工打电话(或网聊)向上级提出请假申请——上级口头同意——上级将请假记录下来——月底将请假记录上交公司——公司将请假录入电脑

采用工作流技术的公司的请假流程是这样的

员工使用账户登录系统——点击请假——上级登录系统点击允许

就这样,一个请假流程就结束了

有人会问,那上级不用向公司提交请假记录?公司不用将记录录入电脑?答案是,用的。但是这一切的工作都会在上级点击允许后自动运行!

这就是工作流技术。

 

Georgakopoulos给出的工作流定义是:工作流是将一组任务组织起来以完成某个经营过程:定义了任务的触发顺序和触发条件,每个任务可以由一个或多个软件系统完成,也可以由一个或一组人完成,还可以由一个或多个人与软件系统协作完

 

 

二、 工作流技术的优点

从上面的例子,很容易看出

工作流系统,实现了工作流程的自动化,提高了企业运营效率、改善企业资源利用、提高企业运作的灵活性和适应性、提高量化考核业务处理的效率、减少浪费(时间就是金钱)。

而手工处理工作流程,一方面无法对整个流程状况进行有效跟踪、了解,另一方面难免会出现人为的失误和时间上的延时导致效率低下,特别是无法进行量化统计,不利于查询、报表及绩效评估。

 

三、 Java开发者会为什么要学Activity工作流

Java领域,JBPMActivity是两个主流的工作流系统,而Activity的出现无疑将会取代JBPMActivity的开发者就是从Jbpm开发者出来的)。

 

四、 Activity工作流学习要点

 

1. 1个插件

Eclipse中安装Activity插件,让你可以在Eclipse中绘制Activity工作流图

 

2. 1个引擎

ProcessEngine对象,Activity工作流引擎。这是Activiti工作的核心。负责生成流程运行时的各种实例及数据、监控和管理流程的运行。

所有的操作都是从获取引擎开始的,所以一般会把引擎作为全局变量

ProcessEngine processEngine =ProcessEngines.getDefaultProcessEngine();

 

3. 1个配置文件

activiti.cfg.xmlActiviti核心配置文件,配置流程引擎创建工具的基本参数和数据库连接池参数

 

4. 5种数据库表

Activiti的后台是有数据库的支持,所有的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。用途也和服务的API对应。

ACT_RE_*: 'RE'表示repository。 这个前缀的表包含了流程定义和流程静态资源(图片,规则,等等)。

ACT_RU_*: 'RU'表示runtime。 这些运行时的表,包含流程实例,任务,变量,异