最新上海---面试过程中遇到的问题--连载

JAVASE知识:


面向对象有封装,继承,多态,说说你对多态的理解?


封装:

封装的概念好比一辆汽车,你学开车的时候只需学会诸如踩油门、刹车,转方向盘即可,无需去了解它的发动机是如何发动。

继承:
继承,先说说我对类的理解,类起到的作用有:
分类(你所用某个类创建的对象实际上该类的个案)和模板的作用,那么继承则起到了对类再次分类的作用,
比如,有个类“动物”,“哺乳动物”继承“动物”,再往下“马”又继承了“哺乳动物”这个类。
在这里,我们从下往上讲,首先,我们把某种东西划分出来,叫做“马”(当然还有“牛”,“鱼”等等),接着,
我们发现,“马”,“羊”等还有很多共同的特点,于是,我们再次划分出了“哺乳动物”这个类,再次分类,
我们则有了“动物”。但在实际开发中,我们一般是从上往下定义的,即先有了“动物”,再有“哺乳动物”,最后有“马”。

多态:
多态,一重写,二重载。用汉字来打个比方,比如“开”这个字,在不同的时候各有的意思,比如“开门”,“开窗”,甚至有“开车”,“开饭”等,具有相同名称但操作不同。

简单来说就是: 一个接口,多种实现”,就是同一种事物表现出的多种形态。


接口:
接口,在JAVA不支持多继承的,实际上接口起到了类似多继承的作用,一个类只能继承另一个类(或抽象类)但可以实现多个接口。

打个比方,“张三”,他是一个“人”,因此他继承了“人”;与此同时,他是一个“司机”,他的平时行为还有“开车”,很显然,这并不能从“人”这个类里继承下来。怎么办?JAVA里只支持单继承,这个时候,接口就起到了作用,它定义了“司机”这个接口,“张三”实现了它,因此,他会开车了。


请你讲一下java中重载与重写的区别?


重写(override):重写是子类的方法覆盖父类的方法,要求方法名和参数都相同 。
 
重载(overload):重载是在同一个类中的两个或两个以上的方法,拥有相同的方法名,但是参数却不相同,方法体也不相同,最常见的重载的例子就是类的构造函数,可以参考API帮助文档看看类的构造方法。


请你讲一下Java中的继承与组合


继承和组合的概念

  在新类里简单地创建原有类的对象。我们把这种方法叫作“组合”,因为新类由现有类的对象合并而成。我们只是简单地重复利用代码的功能,而不是采用它的形式。

  第二种方法是创建一个新类,将其作为现有类的一个“类型”。我们可以原样采取现有类的形式,并在其中加入新代码,同时不会对现有的类产生影响。这种魔术般的行为叫作“继承”(Inheritance),涉及的大多数工作都是由编译器完成的。对于面向对象的程序设计,“继承”是最重要的基础概念之一。对于组合和继承这两种方法,大多数语法和行为都是类似的(因为它们都要根据现有的类型生成新类型)。


什么时候该用继承,什么时候该用组合?


以下两条原则说明了应该如何选择继承与组合:

如果存在一种IS-A的关系(比如Bee“是一个”Insect(昆虫)),并且一个类需要向另一个类暴露所有的方法接口,那么更应该用继承的机制。


如果存在一种HAS-A的关系(比如Bee“有一个”attack(攻击)功能),那么更应该运用组合。
总结来说,继承和组合都有他们的用处。只有充分理解各对象和功能之间的关系,才能充分发挥这两种机制各自的优点。



java中一般用什么数据类型来表示价格?

BigDecimal类型


为什么推荐使用接口而不是直接使用具体类?


面向对象是解决软件需求的变化而产生的,他的目的就是让需求变化时软件的改动达到最小化。如果只是一个IA接口,一个AClass类,IA接口就是多余的,你直接用实现类就可以了。

如果又来了一个BClass,也需要toString()方法。
用实现类可能忘了在BClass中定义toString()方法,但让BClass实现IA接口,就必须在BClass中实现toString()方法,不然编译不通过,这是接口的第一个好处:强制实现

如果要把IA ia = new AClass();换成new BClass();
用实现类需要修改两行,AClass a = new AClass();换成BClass b = new BClass();,a.toString(); 换成b.toString();
用接口只需要修改一行,IA ia = new AClass();换成IA ia = new BClass();
而IA.toString();是不需要修改的,这是接口的第二个好处:抽象行为


总结:

接口的第一个好处:强制实现

接口的第二个好处:抽象行为


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


如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。


java中String、StringBuffer、StringBuilder的区别?


1.三者在执行速度方面的比较:StringBuilder >  StringBuffer  >  String


2.String <(StringBuffer,StringBuilder)的原因
             String:字符串常量
    StringBuffer:字符串变量(线程安全)
    StringBuilder:字符串变量(非线程安全)

String:

String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。

StringBuffer:

如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:
 String S1 = “This is only a” + “ simple” + “ test”;
 StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
 你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个
 String S1 = “This is only a” + “ simple” + “test”; 其实就是:


 String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
这时候 JVM 会规规矩矩的按照原来的方式去做

StringBuilder:

StringBuilder被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。


3.对于三者使用的总结: 


      1.如果要操作少量的数据用 = String

      2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder

      3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer


输入一个字符串类型,如果有数字,就把它截出来,怎么处理?


  1. public static void main(String[] args) {  
  2.      String str = “love23next234csdn3423javaeye”;  
  3.      str=str.trim();  
  4.      String str2=“”;  
  5.      if(str != null && !”“.equals(str)){  
  6.      for(int i=0;i<str.length();i++){  
  7.      if(str.charAt(i)>=48 && str.charAt(i)<=57){  
  8.      str2+=str.charAt(i);  
  9.     }  
  10.    }  
  11.   
  12.   }  
  13.    System.out.println(str2);  
  14. }  
public static void main(String[] args) {
     String str = "love23next234csdn3423javaeye";
     str=str.trim();
     String str2="";
     if(str != null && !"".equals(str)){
     for(int i=0;i<str.length();i++){
     if(str.charAt(i)>=48 && str.charAt(i)<=57){
     str2+=str.charAt(i);
    }
   }

  }
   System.out.println(str2);
}


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

不是


java中基本类型有哪些?


数据类型可以分为两大类:
  1)基本类型;
  2)引用类型;


基本类型:可以分为三类,字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double。


引用数据类型:类、接口类型、数组类型、枚举类型、注解类型;



解析内存中的栈(stack)、堆(heap)、和静态区(static area)的用法。


通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用内存中的栈空间;

而通过new关键字和构造器创建的对象放在堆空间;

程序中的字面量(literal)如直接书写的100、”hello”和常量都是放在静态区中。


栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,理论上整个内存没有被其他进程使用的空间甚至硬盘上的虚拟内存都可以被当成堆空间来使用。

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


补充:较新版本的Java(从Java 6的某个更新开始)中使用了一项叫”逃逸分析”的技术,可以将一些局部对象放在栈上以提升对象的操作性能。



内存溢出(OutofMemory)怎么解决?


内存溢出分为:

1.PermGen space(永久保存区域)OutOfMemoryError: PermGen space

程序中使用了大量的jar或class,使java虚拟机装载类的空间不够。

解决办法:
①增加java虚拟机中的XX:PermSize和XX:MaxPermSize参数的大小
②清理应用程序中web-inf/lib下的jar,如果tomcat部署了多个应用,很多应用都使用了相同的jar,可以将共同的jar移到tomcat共同的lib下,减少类的重复加载。

2.Heap space(堆区域)OutOfMemoryError:  Java heap space
    

java虚拟机创建的对象太多,在进行垃圾回收之间,虚拟机分配的到堆内存空间已经用满了。


解决办法:
①检查程序,看是否有死循环或不必要地重复创建大量对象
②增加Java虚拟机中Xms(初始堆大小)和Xmx(最大堆大小)参数的大小


3.Stacks(栈区域)OutOfMemoryError:unable to create new native thread

Java线程个数很多的情况下容易发生


正则:


写一个匹配手机号码的正则表达式


  1. public class Tel {  
  2. public static void main(String[] args) {  
  3.   String regex = “1[358]\\d{9}”;  
  4.   String Tel = “15719371601”;  
  5.   if (Tel.matches(regex)) {  
  6.     System.out.println(Tel + ”是合法的手机号”);  
  7.   }  
  8.  }  
  9. }   
public class Tel {
public static void main(String[] args) {
  String regex = "1[358]\\d{9}";
  String Tel = "15719371601";
  if (Tel.matches(regex)) {
    System.out.println(Tel + "是合法的手机号");
  }
 }
} 



集合:


HashMap和HashTable的区别?


1) HashTable 与HashMap实现的是不同的接口、HashTable 是Dictionary的子类、HashMap 是Map接口的子类

2) HashTable的键值都不允许为空,HashMap的键值只允许其中一个为空。

3) HashTable 是多线程安全的、HashMap 是非线程安全的


或者就HashMap与HashTable主要从三方面来说。

 

一、历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现 


二、同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的 


三、值:只有HashMap可以让你将空值作为一个表的条目的key或value 


用HashMap怎么迭代数据?


【遍历方法一】


for(Map.Entry<key_type , value_type> entry : hashmap.entrySet()){  
   System.out.println(“Key=”+entry.getKey()+”—->value=”+entry.getValue().toString())  
}


【遍历方法二:用keySet遍历】

Iterator it=hashmap.keySet().iterator();//这是取得键对象   
while(it.hasNext())   
{   
   System.out.println( “it.Next数据的值是: “+get(it.next()));   //获得键所对应的值。   
}  


【遍历方法三:用entrySet遍历】

Iterator i = hasmap.entrySet().iterator();  
while(i.hasNext()){  
    Entry  entry=(Entry)it.next();  
    Object key=entry.getKey();  
    Object value=entry.getValue();  



java中LinkList和ArrayList的区别?


ArrayList随机访问速度快
LinkList频繁插取速度快

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。

 
2.对于随机访问get和set,ArrayList优于LinkedList,因为ArrayList可以随机定位,而LinkedList要移动指针一步一步的移动到节点处。(参考数组与链表来思考)


3.对于新增和删除操作add和remove,LinedList比较占优势,只需要对指针进行修改即可,而ArrayList要移动数据来填补被删除的对象的空间。


总结:

1. ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 
2. 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。 
3. 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据 。


switch是否能作用在byte上、是否能作用在long上、是否能作用在Stirng上?


byte,short,char 都可以隐含转换为int,所以,这些类型以及这些类型的包装类型也是可以的。

long 和String 类型都不符合sitch 的语法规定,并且不能被隐式转换成int类型,所以,它们不能作用于swtich 语句中。


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

答:不对,有相同的 hash code

这是java语言的定义:


1) 对象相等则hashCode一定相等;
2) hashCode相等对象未必相等


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

JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。


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

GC是垃圾收集器。Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:     
  
  System.gc()     
  Runtime.getRuntime().gc() 


JAVA中的final关键字有哪些用法?


一是其定义处,也就是说在final变量定义时直接给其赋值,

二是在构造函数中。而且在Java1.1以前,只能是在定义时给值。

三是在初如化代码块中{} 或者 static{}





多线程:


请你讲一下线程的生命周期


线程是一个动态执行的过程,它也有一个从产生到死亡的过程。


(1)生命周期的五种状态


1、新建(new Thread)
当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。
例如:Thread  t1=new Thread();


2、就绪(runnable)
线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。例如:t1.start();


3、运行(running)
线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。


4、死亡(dead)
当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。


自然终止:正常运行run()方法后终止


异常终止:调用stop()方法让一个线程终止运行


5.堵塞(blocked)
由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。


正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。


正在等待:调用wait()方法。(调用motify()方法回到就绪状态)


被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)
 


Thread.sleep()方法释放锁吗?


sleep()方法并不会释放锁。wait会释放。




算法:


写代码实现二叉树及其遍历方法


  1. package tree;    
  2.     
  3. import java.util.LinkedList;    
  4. import java.util.List;    
  5.     
  6. /**   
  7.  * 功能:把一个数组的值存入二叉树中,然后进行3种方式的遍历   
  8.  *    
  9.  * 参考资料0:数据结构(C语言版)严蔚敏   
  10.  *    
  11.  * 参考资料1:http://zhidao.baidu.com/question/81938912.html   
  12.  *    
  13.  * 参考资料2:http://cslibrary.stanford.edu/110/BinaryTrees.html#java   
  14.  *    
  15.  * @author ocaicai@yeah.net @date: 2011-5-17   
  16.  *    
  17.  */    
  18. public class BinTreeTraverse2 {    
  19.     
  20.     private int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };    
  21.     private static List<Node> nodeList = null;    
  22.     
  23.     /**   
  24.      * 内部类:节点   
  25.      *    
  26.      * @author ocaicai@yeah.net @date: 2011-5-17   
  27.      *    
  28.      */    
  29.     private static class Node {    
  30.         Node leftChild;    
  31.         Node rightChild;    
  32.         int data;    
  33.     
  34.         Node(int newData) {    
  35.             leftChild = null;    
  36.             rightChild = null;    
  37.             data = newData;    
  38.         }    
  39.     }    
  40.     
  41.     public void createBinTree() {    
  42.         nodeList = new LinkedList<Node>();    
  43.         // 将一个数组的值依次转换为Node节点    
  44.         for (int nodeIndex = 0; nodeIndex < array.length; nodeIndex++) {    
  45.             nodeList.add(new Node(array[nodeIndex]));    
  46.         }    
  47.         // 对前lastParentIndex-1个父节点按照父节点与孩子节点的数字关系建立二叉树    
  48.         for (int parentIndex = 0; parentIndex < array.length / 2 - 1; parentIndex++) {    
  49.             // 左孩子    
  50.             nodeList.get(parentIndex).leftChild = nodeList    
  51.                     .get(parentIndex * 2 + 1);    
  52.             // 右孩子    
  53.             nodeList.get(parentIndex).rightChild = nodeList    
  54.                     .get(parentIndex * 2 + 2);    
  55.         }    
  56.         // 最后一个父节点:因为最后一个父节点可能没有右孩子,所以单独拿出来处理    
  57.         int lastParentIndex = array.length / 2 - 1;    
  58.         // 左孩子    
  59.         nodeList.get(lastParentIndex).leftChild = nodeList    
  60.                 .get(lastParentIndex * 2 + 1);    
  61.         // 右孩子,如果数组的长度为奇数才建立右孩子    
  62.         if (array.length % 2 == 1) {    
  63.             nodeList.get(lastParentIndex).rightChild = nodeList    
  64.                     .get(lastParentIndex * 2 + 2);    
  65.         }    
  66.     }    
  67.     
  68.     /**   
  69.      * 先序遍历   
  70.      *    
  71.      * 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已   
  72.      *    
  73.      * @param node   
  74.      *            遍历的节点   
  75.      */    
  76.     public static void preOrderTraverse(Node node) {    
  77.         if (node == null)    
  78.             return;    
  79.         System.out.print(node.data + ” ”);    
  80.         preOrderTraverse(node.leftChild);    
  81.         preOrderTraverse(node.rightChild);    
  82.     }    
  83.     
  84.     /**   
  85.      * 中序遍历   
  86.      *    
  87.      * 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已   
  88.      *    
  89.      * @param node   
  90.      *            遍历的节点   
  91.      */    
  92.     public static void inOrderTraverse(Node node) {    
  93.         if (node == null)    
  94.             return;    
  95.         inOrderTraverse(node.leftChild);    
  96.         System.out.print(node.data + ” ”);    
  97.         inOrderTraverse(node.rightChild);    
  98.     }    
  99.     
  100.     /**   
  101.      * 后序遍历   
  102.      *    
  103.      * 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已   
  104.      *    
  105.      * @param node   
  106.      *            遍历的节点   
  107.      */    
  108.     public static void postOrderTraverse(Node node) {    
  109.         if (node == null)    
  110.             return;    
  111.         postOrderTraverse(node.leftChild);    
  112.         postOrderTraverse(node.rightChild);    
  113.         System.out.print(node.data + ” ”);    
  114.     }    
  115.     
  116.     public static void main(String[] args) {    
  117.         BinTreeTraverse2 binTree = new BinTreeTraverse2();    
  118.         binTree.createBinTree();    
  119.         // nodeList中第0个索引处的值即为根节点    
  120.         Node root = nodeList.get(0);    
  121.     
  122.         System.out.println(“先序遍历:”);    
  123.         preOrderTraverse(root);    
  124.         System.out.println();    
  125.     
  126.         System.out.println(“中序遍历:”);    
  127.         inOrderTraverse(root);    
  128.         System.out.println();    
  129.     
  130.         System.out.println(“后序遍历:”);    
  131.         postOrderTraverse(root);    
  132.     }    
  133.     
  134. }    
package tree;  

import java.util.LinkedList;  
import java.util.List;  

/** 
 * 功能:把一个数组的值存入二叉树中,然后进行3种方式的遍历 
 *  
 * 参考资料0:数据结构(C语言版)严蔚敏 
 *  
 * 参考资料1:http://zhidao.baidu.com/question/81938912.html 
 *  
 * 参考资料2:http://cslibrary.stanford.edu/110/BinaryTrees.html#java 
 *  
 * @author ocaicai@yeah.net @date: 2011-5-17 
 *  
 */  
public class BinTreeTraverse2 {  

    private int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };  
    private static List<Node> nodeList = null;  

    /** 
     * 内部类:节点 
     *  
     * @author ocaicai@yeah.net @date: 2011-5-17 
     *  
     */  
    private static class Node {  
        Node leftChild;  
        Node rightChild;  
        int data;  

        Node(int newData) {  
            leftChild = null;  
            rightChild = null;  
            data = newData;  
        }  
    }  

    public void createBinTree() {  
        nodeList = new LinkedList<Node>();  
        // 将一个数组的值依次转换为Node节点  
        for (int nodeIndex = 0; nodeIndex < array.length; nodeIndex++) {  
            nodeList.add(new Node(array[nodeIndex]));  
        }  
        // 对前lastParentIndex-1个父节点按照父节点与孩子节点的数字关系建立二叉树  
        for (int parentIndex = 0; parentIndex < array.length / 2 - 1; parentIndex++) {  
            // 左孩子  
            nodeList.get(parentIndex).leftChild = nodeList  
                    .get(parentIndex * 2 + 1);  
            // 右孩子  
            nodeList.get(parentIndex).rightChild = nodeList  
                    .get(parentIndex * 2 + 2);  
        }  
        // 最后一个父节点:因为最后一个父节点可能没有右孩子,所以单独拿出来处理  
        int lastParentIndex = array.length / 2 - 1;  
        // 左孩子  
        nodeList.get(lastParentIndex).leftChild = nodeList  
                .get(lastParentIndex * 2 + 1);  
        // 右孩子,如果数组的长度为奇数才建立右孩子  
        if (array.length % 2 == 1) {  
            nodeList.get(lastParentIndex).rightChild = nodeList  
                    .get(lastParentIndex * 2 + 2);  
        }  
    }  

    /** 
     * 先序遍历 
     *  
     * 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已 
     *  
     * @param node 
     *            遍历的节点 
     */  
    public static void preOrderTraverse(Node node) {  
        if (node == null)  
            return;  
        System.out.print(node.data + " ");  
        preOrderTraverse(node.leftChild);  
        preOrderTraverse(node.rightChild);  
    }  

    /** 
     * 中序遍历 
     *  
     * 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已 
     *  
     * @param node 
     *            遍历的节点 
     */  
    public static void inOrderTraverse(Node node) {  
        if (node == null)  
            return;  
        inOrderTraverse(node.leftChild);  
        System.out.print(node.data + " ");  
        inOrderTraverse(node.rightChild);  
    }  

    /** 
     * 后序遍历 
     *  
     * 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已 
     *  
     * @param node 
     *            遍历的节点 
     */  
    public static void postOrderTraverse(Node node) {  
        if (node == null)  
            return;  
        postOrderTraverse(node.leftChild);  
        postOrderTraverse(node.rightChild);  
        System.out.print(node.data + " ");  
    }  

    public static void main(String[] args) {  
        BinTreeTraverse2 binTree = new BinTreeTraverse2();  
        binTree.createBinTree();  
        // nodeList中第0个索引处的值即为根节点  
        Node root = nodeList.get(0);  

        System.out.println("先序遍历:");  
        preOrderTraverse(root);  
        System.out.println();  

        System.out.println("中序遍历:");  
        inOrderTraverse(root);  
        System.out.println();  

        System.out.println("后序遍历:");  
        postOrderTraverse(root);  
    }  

}  




JAVAEE知识:


web应用中class的加载顺序是什么?


Classpath–>WEB-INF/classes/WEB-INF/lib



请你讲一下JSP与servlet的区别?


1.jsp经编译后就变成了Servlet.(JSP的本质就是Servlet,JVM只能识别java的类,不能识别JSP的代码,Web容器将JSP的代码编译成JVM能够识别的java类)。

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

3.Servlet中没有内置对象,Jsp中的内置对象都是必须通过HttpServletRequest对象,HttpServletResponse对象以及HttpServlet对象得到,JSP是Servlet的一种简化,使用Jsp只需要完成程序员需要输出到客户端的内容,Jsp中的Java脚本如何镶嵌到一个类中,由Jsp容器完成,而Servlet则是个完整的Java类,这个类的Service方法用于生成对客户端的响应。 


简述Servlet中请求的转发与重定向的区别?


forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。    

redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来说浏览器会用刚才请求的所有参数重新请求,所以session, request参数都可以获取。



请你讲一下filter和servlet的区别?


1. Filter
Servlet中的过滤器Filter是实现了javax.servlet.Filter接口,在web.xml中配置与标签指定使用哪个Filter实现类过滤哪些URL链接。只在web启动时进行初始化操作,filter 流程是线性的, url传来之后,检查之后,可保持原来的流程继续向下执行,被下一个filter, servlet接收等,而servlet 处理之后,不会继续向下传递。filter功能可用来保持流程继续按照原来的方式进行下去,或者主导流程,而servlet的功能主要用来主导流程。
特点:可以在响应之前修改Request和Response的头部,只能转发请求,不能直接发出响应。filter可用来进行字符编码的过滤,检测用户是否登陆的过滤,禁止页面缓存等

2. Servlet
servlet 流程是短的,url传来之后,就对其进行处理,之后返回或转向到某一自己指定的页面。它主要用来在业务处理之前进行控制。



过滤器、监听器、拦截器的区别?


1.过滤器

Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是过滤字符编码、做一些业务逻辑判断等。其工作原理是,只要你在web.xml文件配置好要拦截的客户端请求,它都会帮你拦截到请求,此时你就可以对请求或响应(Request、Response)统一设置编码,简化操作;同时还可进行逻辑判断,如用户是否已经登陆、有没有权限访问该页面等等工作。


2.监听器

Servlet的监听器Listener,它是实现了javax.servlet.ServletContextListener 接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。主要作用是: 做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者是一些固定的对象等等。


3.拦截器

拦截器是在面向切面编程中应用的,就是在你的service或者一个方法前调用一个方法,或者在方法后调用一个方法。是基于JAVA的反射机制。


总结:


1.过滤器:所谓过滤器顾名思义是用来过滤的,在Java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者struts的action前统一设置字符集,或者去除掉一些非法字符(聊天室经常用到的,一些骂人的话)。filter 流程是线性的, url传来之后,检查之后,可保持原来的流程继续向下执行,被下一个filter, servlet接收等.

2.监听器:这个东西在c/s模式里面经常用到,他会对特定的事件产生产生一个处理。监听在很多模式下用到。比如说观察者模式,就是一个监听来的。又比如struts可以用监听来启动。Servlet监听器用于监听一些重要事件的发生,监听器对象可以在事情发生前、发生后可以做一些必要的处理。

3.拦截器:java的拦截器主要是用在插件上,扩展件上比如 hibernate、spring、struts2等有点类似面向切片的技术,在用之前先要在配置文件即xml文件里声明一段的那个东西。


EL表达式怎么获取值?


EL获取Map:


{map[key1]} &nbsp; ---- 直接取map中key=key1 的value; &nbsp;例: &nbsp;map .put("a","b"), &nbsp; {map[key1]} &nbsp; ---- 直接取map中key=key1 的value; &nbsp;例: &nbsp;map .put("a","b"), &nbsp; {map[“a”]}  就可以
注意:如果key1 是数值,例如; 1

EL表达式取List的值:


<c:forEach var=”student” items=” students><tr><spanstyle=whitespace:pre></span><td><c:outvalue= s t u d e n t s ” >< t r >< s p a n s t y l e = ” w h i t e − s p a c e : p r e ” >< / s p a n >< t d >< c : o u t v a l u e = ” {student.name}” default=”wang”/> </td>   
         <span style=”white-space:pre”> </span><td> <c:out value=”$ {student.age}” default=”wang”/> </td>   
          </tr>   
 </c:forEach> 


JSP中提供了四种属性范围,四种属性范围分别指以下四种:


page域——当前页:一个属性只能在一个页面中取得,跳转到其他页面无法取得。
request域——一次服务器请求:一个页面中设置的属性,只要经过了服务器跳转,则跳转之后的页面可以继续取得。
session域——一次会话:一个用户设置的内容,只要是与此用户相关的页面都可以访问(一个会话表示一个人,这个人设置的东西只要这个人不走,就依然有效)。
application——上下文中:在整个服务器上设置的属性,所有人都可以访问。


JSTL 核心标签库标签共有13个,功能上分为4类:


1.表达式控制标签:out、set、remove、catch
2.流程控制标签:if、choose、when、otherwise
3.循环标签:forEach、forTokens
4.URL操作标签:import、url、redirect



数据库:


请说出四种NOSQL数据库?


CouchDB、Redis、MongoDB、Riak、Neo4j、HBase。


请你讲一下NoSQL的优点/缺点


优点:
- 高可扩展性
- 分布式计算
- 低成本
- 架构的灵活性,半结构化数据
- 没有复杂的关系


缺点:
- 没有标准化
- 有限的查询功能(到目前为止)
- 最终一致是不直观的程序


请你讲一下关系型与非关系型数据的区别?


优点:
1)成本:nosql数据库简单易部署,基本都是开源软件,不需要像使用oracle那样花费大量成本购买使用,相比关系型数据库价格便宜。
2)查询速度:nosql数据库将数据存储于缓存之中,关系型数据库将数据存储在硬盘中,自然查询速度远不及nosql数据库。
3)存储数据的格式:nosql的存储格式是key,value形式、文档形式、图片形式等等,所以可以存储基础类型以及对象或者是集合等各种格式,而数据库则只支持基础类型。
4)扩展性:关系型数据库有类似join这样的多表查询机制的限制导致扩展很艰难。

缺点:
1)维护的工具和资料有限,因为nosql是属于新的技术,不能和关系型数据库10几年的技术同日而语。
2)不提供对sql的支持,如果不支持sql这样的工业标准,将产生一定用户的学习和使用成本。
3)不提供关系型数据库对事物的处理。


MySQL数据库,你是怎么理解索引的?


索引就是书的目录,方便你查找东西的.但是如果你要在书中添加内容的话 那么就会很麻烦,因为还得在目录里添加新的东西检索的道理跟这是一样的,作用是方便查找数据.但是如果你要对数据进行修改的话 就会花费很多时间,这就是检索的弊端。

数据库内连接和外连接有什么区别?

1、内连接(自然连接): 只有两个表相匹配的行才能在结果集中出现(把两个表中数据对应的数据查出来 ) 

2、外连接: 以某个表为基础把对应数据查出来(全连接是以多个表为基础
(1)左外连接(左边的表不加限制) (left join):左边表数据行全部保留,右边表保留符合连接条件的行
(2)右外连接(右边的表不加限制)(right join ) :右边表数据行全部保留,左边表保留符合连接条件的行
(3)全外连接(左右两表都不加限制) (full join):左外连接 union 右外连接


请你讲一下数据库中union的作用


将两个或更多查询的结果组合为单个结果集,该结果集包含联合查询中的所有查询的全部行。这与使用联接组合两个表中的列不同。


使用 UNION 组合两个查询的结果集的两个基本规则是:

 
1.所有查询中的列数和列的顺序必须相同。
2.数据类型必须兼容假设有以下两个表(也可以是查询出来的结果集)表


请你说下数据库的优化?


创建索引
语句使用大写
减少表之间的关系


什么是事务控制?


事务控制就是将一系列操作当成一个不可拆分的逻辑单元,保证这些操作要么都成功,要么都失败。在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。事务是恢复和并发控制的基本单位。


事务应该具有4个属性:原子性、一致性、隔离性、持续性。


请简单的讲一下数据库设计的三大范式

第一范式(确保每列保持原子性)
第二范式(确保表中的每列都和主键相关)
第三范式(确保每列都和主键列直接相关,而不是间接相关)



框架:




spring:


请你说下依赖注入的优缺点?


IoC还有另外一个名字——“依赖注入(Dependency Injection)”。


依赖注入。依赖注入让bean与bean之间以配置文件组织在一起,而不是以硬编码的方式耦合在一起。


从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,形象地说,即由容器动态地将某种依赖关系注入到组件之中。 

依赖注入是指所依赖的对象不是由自己new出来的,而是用别的方式注入的,Spring的依赖注入是在BeanFactory创建bean的时候完成的.通常是在”bean”类中定义了”依赖”(成员变量,type为别的类,最好是interface或者abstract class),BeanFactory通过配置注入这些”依赖”(BeanFactory创建bean的时候赋值给这些成员变量).当这些”依赖”的实现发生变化的时候,不需要修改”bean”类,而只需要修改Spring的配置文件.或者通过配置新的”依赖”实现,实现新的业务而不用修改”bean”类。


Spring的三种依赖注入实现类型——接口注入(Interface Injection)、设值注入(Setter Injection)、构造子注入(Constructor Injection)。



接口注入: 

传统的创建接口对象的方法, 借助接口来将调用者与实现者分离。


设值注入(setter注入): 

在各种类型的依赖注入模式中,设值注入模式在实际开发中得到了最广泛的应用(其中很大一部分得力于Spring框架的影响)。使用IoC的Setter注射,一些外部元数据被用于解决依赖性问题。并且在Spring中,这种元数据采取了简单的XML配置文件的形式。


构造器注入:

即通过构造函数完成依赖关系的设定, 在构造器注入类型的依赖注入机制中,依赖关系是通过类构造函数建立,容器通过调用类的构造方法,将其所需的依赖关系
注入其中。


总结:


     接口注入在灵活性、易用性上不如其他两种注入模式, 设值注入和构造器注入型的依赖注入实现则是目前主流的IOC实现模式, 构造器注入和设值注入模式各有千秋,而Spring都对构造器注入和设值注入类型的依赖注入机制提供了良好支持。 以构造器注入类型为主,辅之以设值注入类型机制作为补充,可以达到最好的依赖注入效果,不过对于基于Spring Framework开发的应用而言,设值注入使用更加广泛。


构造器注入的优势:


1. “在构造期即创建一个完整、合法的对象”,对于这条Java设计原则,设值注入无疑是最好的响应者。

2. 避免了繁琐的setter方法的编写,所有依赖关系均在构造函数中设定,依赖关系集中呈现,更加易读。

3. 由于没有setter方法,依赖关系在构造时由容器一次性设定,因此组件在被创建之后即处于相对“不变”的稳定状态,无需担心上层代码在调用过程中执行setter方法对组件依赖关系产生破坏,特别是对于Singleton模式的组件而言,这可能对整个系统产生重大的影响。

4. 同样,由于关联关系仅在构造函数中表达,只有组件创建者需要关心组件内部的依赖关系。
对调用者而言,组件中的依赖关系处于黑盒之中。对上层屏蔽不必要的信息,也为系统的
层次清晰性提供了保证。


5. 通过构造子注入,意味着我们可以在构造函数中决定依赖关系的注入顺序,对于一个大量
依赖外部服务的组件而言,依赖关系的获得顺序可能非常重要,比如某个依赖关系注入的
先决条件是组件的DataSource及相关资源已经被设定。


设值注入(setter注入)的优势:


1. 对于习惯了传统JavaBean开发的程序员而言,通过setter方法设定依赖关系显得更加直
观,更加自然。


2. 如果依赖关系(或继承关系)较为复杂,那么设值注入模式的构造函数也会相当庞大(我们需要在构造函数中设定所有依赖关系),此时构造器注入模式往往更为简洁。


3. 对于某些第三方类库而言,可能要求我们的组件必须提供一个默认的构造函数(如Struts中的Action),此时构造器注入类型的依赖注入机制就体现出其局限性,难以完成我们期望的功
能。



请简述你对IOC的理解?


IOC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
简单的来说比如开车、平时都是我们自己开车、但是有这么一种技术、他能自己驾驶汽车、使人解放双手、所以车子的控制器从人手里转换到了机器人手里了。这就是控制反转,把控制器权转给别人来完成某个任务。


请简述你对AOP的理解?


面向切面编程,本质就是过滤器、面向切面编程的目标就是分离关注点。什么是关注点呢,就是你要做的事,就是关注点。假如你是个公子哥,没啥人生目标,天天就是衣来伸手,饭来张口,整天只知道玩一件事!那么,每天你一睁眼,就光想着吃完饭就去玩(你必须要做的事),但是在玩之前,你还需要穿衣服、穿鞋子、叠好被子、做饭等等等等事情,这些事情就是你的关注点,但是你只想吃饭然后玩,那么怎么办呢?这些事情通通交给别人去干。在你走到饭桌之前,有一个专门的仆人A帮你穿衣服,仆人B帮你穿鞋子,仆人C帮你叠好被子,仆人C帮你做饭,然后你就开始吃饭、去玩(这就是你一天的正事),你干完你的正事之后,回来,然后一系列仆人又开始帮你干这个干那个,然后一天就结束了!

AOP的好处就是你只需要干你的正事,其它事情别人帮你干。也许有一天,你想裸奔,不想穿衣服,那么你把仆人A解雇就是了!也许有一天,出门之前你还想带点钱,那么你再雇一个仆人D专门帮你干取钱的活!这就是AOP。每个人各司其职,灵活组合,达到一种可配置的、可插拔的程序结构。

从Spring的角度看,AOP最大的用途就在于提供了事务管理的能力。事务管理就是一个关注点,你的正事就是去访问数据库,而你不想管事务(太烦),所以,Spring在你访问数据库之前,自动帮你开启事务,当你访问数据库结束之后,自动帮你提交/回滚事务!


请你谈谈你对Spring中IOC和AOP的理解;


1.IOC控制反转:控制权由对象本身转向容器,由容器对bean对象进行控制。


2.AOP面向切面编程:把具体的类创建对应的代理类,通过代理类来对具体类进行操作(即在不修改源代码的情况下,对原有功能进行扩展,通过代理类来对具体类进行操作)。


spring是一个容器,通过spring这个容器来对对象进行管理,根据配置文件来实现spring对对象的管理。




spring原理(底层) 是什么实现的?


内部最核心的就是IOC和AOP:


内部最核心的就是IOC了,动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射,反射其实就是在运行时动态的去创建,调用对象Spring就是在运行时,跟xml  Spring的配置 文件来动态的创建对象,和调用对象里的方法的 。


Spring还有一个核心就是AOP这个就是面向切面编程,可以为某一类对象 进行监督和控制(也就是在调用这类对象的具体方法的前后去调用你指定的模块)从而达到对一个模块扩充的功能,这些都是通过配置类达到的。 


Spring目的:就是让对象与对象(模块与模块)之间的关系没有通过代码来关联,都是通过配置类说明 管理的(Spring根据这些配置 内部通过反射去动态的组装对象) 
   

要记住:Spring是一个容器,凡是在容器里的对象才会有Spring所提供的这些服务和功能,Spring里用的最经典的一个设计模式就是:模板方法模式。


spring AOP面向切面,切面指的是什么?


切面是对横切性关注点的抽象。


spring怎么实现事务管理?


spring的事务声明有两种方式: 编程式和声明式


spring主要是通过“声明式事务”的方式对事务进行管理,即在配置文件中进行声明,通过AOP将事务切面切入程序,最大的好处是大大减少了代码量


通过5个事务属性来控制事务

1.传播行为,主要控制事务的边界
2.隔离等级:主要是并发时对数据同步的影响
3.回滚规则:主要是对检查数据和运行时数据回滚
4.事务超时.超时会锁定数据表.需要事务回滚
5.只读:优化数据库


spring事物配置有几种方式?


Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。

DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。


具体如下图:




总结:

第一种方式:每个Bean都有一个代理
第二种方式:所有Bean共享一个代理基类
第三种方式:使用拦截器
第四种方式:使用tx标签配置的拦截器
第五种方式:全注解


具体代码可参考: http://www.blogjava.net/robbie/archive/2009/04/05/264003.html




Spring AOP的配置有几种方式?


在Spring中实现AOP根据版本不同,可以有大致四种配置方式


1. 基于xml配置文件的代理配置方式 
这种方式在2.0以后很少用了,原因是配置项过多,过于繁琐。但对于理解Spring AOP还是很有帮助的 


2.利用2.0以后使用aop标签


3 利用Annotation(注解)


4 在Spring中结合进AspectJ


详细可参考这里: http://realizeamg.iteye.com/blog/766041


spring中ApplicationContext通常的实现有哪几种以及具体适用情况是什么?

方法一:在初始化时保存ApplicationContext对象

代码:
ApplicationContext ac = new FileSystemXmlApplicationContext(“applicationContext.xml”);
ac.getBean(“beanId”);
说明:这种方式适用于采用Spring框架的独立应用程序,需要程序通过配置文件手工初始化Spring的情况。


方法二:通过Spring提供的工具类获取ApplicationContext对象

代码:
ApplicationContext ac1 = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext sc);
ApplicationContext ac2 = WebApplicationContextUtils.getWebApplicationContext(ServletContext sc);
ac1.getBean(“beanId”);
ac2.getBean(“beanId”);

说明:
这种方式适合于采用Spring框架的B/S系统,通过ServletContext对象获取ApplicationContext对象,然后在通过它获取需要的类实例。

上面两个工具方式的区别是,前者在获取失败时抛出异常,后者返回null。


方法三:继承自抽象类ApplicationObjectSupport

方法四:继承自抽象类WebApplicationObjectSupport

方法五:实现接口ApplicationContextAware


spring中怎样开启注解装配?


自动装配: 
@Autowired使用自动装配的方式。将bean容器里面的值自动注入到bean中。 


spring mvc:


请你讲一下spring mvc的原理


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


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


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


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


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


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


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


springmvc的运行机制?


A)  首先客户端发送一个http请求
 
B)  DispatcherServlet接收到这个请求后将请求的处理工作交给处理器HandlerMapping来处理。
 
C)  HandlerMapping会通过一定的查询机制,查找出处理当前请求的Handler
 
D)  当DispatcherServlet通过HandlerMapping得到当前请求的处理类后,就将该请求交给相应的处理类来处理。
 
E)  处理器处理完业务逻辑后返回ModelAndView对象给DispatcherServlet,ModelAndView中包含了视图逻辑名和数据对象
 
F)  返回的视图逻辑名会通过视图解析器解析成真正的视图名并交给DispatcherServlet处理
 
G) DispatcherServlet将请求分派给真正的视图对象,最终反映到客户端



Hibernate:


hibernate 查询出来的对象分为哪几种状态?


1)瞬时状态?
在数据库中没有与之匹配的数据、没有纳入session的管理,执行完直接销毁


2)持久状态
在数据库中有与之匹配的数据、纳入session的管理、在清理缓存的时候(脏数据检测)会时刻与数据库中、数据保存统一


3)托管状态
在数据库中有与之匹配的数据、没有纳入session的管理


总结: hibernate做save或update操作,一般都会根据对象状态来操作,企业开发中一般都是用saveOrUpdate来替代save或update方法



Hibernate的ID生成器有哪些?


1.Native
2.Sequence
3.Increment
4.Assigned
5.uuid


1.常用于sqlserver的标志列,如用作oracle则会自动调用“hibernate_sequence”序列(native)
2.oracle特有的,如没指定固定序列,则自动调用hibernate_sequence(sequence)
3.会自动调用表的最大值max(increment)
4.由程序员手动赋值(字符串)(assigned)
5.由框架自动生成的32位字符串(推荐使用)(uuid)


请你讲一下hibernate一级缓存和二级缓存的区别?


缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。


主要的不同是它们的作用范围不同。


一级缓存是session级别的、也就是只有在同一个session里缓存才起作用、当这个session关闭后这个缓存就不存在了。


二级缓存是sessionFactory级别的、其缓存对同一个sessionFactory生产出来的session都有效、二级缓存我们通常使用其他的一些开源组件,比如hibernate经常使用的就是Ehcache,这个缓存在整个应用服务器中都会有效的。


MyBatis:


mybatis中#与$符号的区别?


A)、#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by “111”, 如果传入的值是id,则解析成的sql为order by “id”。
 
B)、 sqlorderby 将 传 入 的 数 据 直 接 显 示 生 成 在 s q l 中 。 如 : o r d e r b y user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id,  如果传入的值是id,则解析成的sql为order by id。
 
C)、#方式能够很大程度防止sql注入。
 
D)、$方式无法防止Sql注入。
 
E)、$方式一般用于传入数据库对象,例如传入表名。
 
F)、一般能用#的就别用$。



请你讲一下Mybatis的一二级缓冲?


1. 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。 

2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。 

3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。



struts2:



请你讲下struts2的原理


核心:

Struts2的核心用一句话概括:将用户的请求与展示分开。


原理:


a.       用户发送http请求http://localhost:8080/struts2_demo/hello.action。

b.       该请求会被应用服务器(tomcat)接收到,应用服务器会去解析url地址,解析是哪个webapp发送过来的请求(本例中webapp的名称为struts2_demo)。

c.       该webapp会参照web.xml继续进行执行。

d.       于是发现web.xml文件中有一个名字叫做struts2的filter。

e.       于是执行该filter,该filter的执行会参照struts.xml。

f.        在struts.xml文件中找到对应的namespace,继续找到名字为hello的action,再找到result,返回给客户端。


Struts2是单列还是多列?


struts2的Action是多例的、也就是每次请求产生一个Action的对象。
如果是单例的话,若出现两个用户都修改一个对象的属性值,则会因为用户修改时间不同,两个用户访问得到的属性不一样,操作得出的结果不一样

举个例子:
有一块布长度300cm,能做一件上衣(用掉100cm)和一件裤子(用掉200cm);甲和乙同时访问得到的长度都是300cm,
甲想做上衣和裤子,他先截取100cm去做上衣,等上衣做完再去做裤子,而乙这时正好也拿100cm去做上衣,那好,等甲做完上衣再做裤子的时候发现剩下的布(100cm)已经不够做裤子了…..这就是影响系统的性能,解决的办法就是给甲和乙一人一块300cm的布,就不会出现布被别人偷用的事情,也是就单实例和多实例的区别。



区别:


struts2和spring mvc的区别?


我们用struts2时采用的传统的配置文件的方式,并没有使用传说中的0配置。spring mvc可以认为已经100%零配置了(除了配置spring mvc-servlet.xml外)。


1. 机制:

spring mvc的入口是servlet,而struts2是filter(这里要指出,filter和servlet是不同的。以前认为filter是servlet的一种特殊),这样就导致了二者的机制不同,这里就牵涉到servlet和filter的区别了。


2. 性能:

spring会稍微比struts快。spring mvc是基于方法的设计,而sturts是基于类,每次发一次请求都会实例一个action,每个action都会被注入属性,而spring基于方法,粒度更细,但要小心把握像在servlet控制数据一样。spring3 mvc是方法级别的拦截,拦截到方法后根据参数上的注解,把request数据注入进去,在spring3 mvc中,一个方法对应一个request上下文。而struts2框架是类级别的拦截,每次来了请求就创建一个Action,然后调用setter getter方法把request中的数据注入;struts2实际上是通过setter getter方法与request打交道的;struts2中,一个Action对象对应一个request上下文。


3. 参数传递:

struts是在接受参数的时候,可以用属性来接受参数,这就说明参数是让多个方法共享的。


4. 设计思想上:

struts更加符合oop的编程思想, spring就比较谨慎,在servlet上扩展。


5. intercepter的实现机制:

struts有以自己的interceptor机制,spring mvc用的是独立的AOP方式。这样导致struts的配置文件量还是比spring mvc大,虽然struts的配置能继承,所以我觉得论使用上来讲,spring mvc使用更加简洁,开发效率Spring MVC确实比struts2高。spring mvc是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上spring3 mvc就容易实现restful url。struts2是类级别的拦截,一个类对应一个request上下文;实现restful url要费劲,因为struts2 action的一个方法可以对应一个url;而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。spring3 mvc的方法之间基本上独立的,独享request response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架方法之间不共享变量,而struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码,读程序时带来麻烦。


Hibernate和MyBatis区别?


1.开发速度
1.hibernate的真正掌握要比mybatis困难,hibernate比mybatis更加重量级一些
2.mybatis需要我们手动编写SQL语句,回归最原始的方式,所以可以按需求指定查询的字段,提高程序的查询效率,hibernate也可以写自己的SQL语句,这样就                            破坏了hibernate的封装和简介性


2.数据库的移植性
1.mybatis由于所有的SQL语句都是依赖于数据还写的,所以扩展性,迁移性比较差
2.hibernate于=与数据库具体的都关联在xml中,所以HQL对具体什么数据库不是很关心


3.缓存机制对比

hibernate的缓存机制不mybatis好

总结:


相同点:

1.hibernate与mybatis都可以通过SessionFactoryBuilding由XML配置文件生成SessionFactory,然后由SesionFactory 生成Session,最后由Session来开启执行事务和SQL
2.hibernate和mybatis都支持JDBC和JTA事物处理


不同点:

hibernate的优势:
1.hibernate的dao层开发比mybatis简单,mybatis需要维护SQL和结果映射
2.hibernate对对象的维护和缓存要比mybatis好,对增删改差的对象的维护要方便
3.hibernate对数据库的移植性很好,mybatis不好,不同的数据库写不同的SQL语句
4.hibernate有更好的二级缓存机制,可以使用第三方缓存,mybatis自身提高的缓存机制不佳

mybatis的优势:
1.mybatis可以进行更为细致化的SQL优化,可以减少查询字段
2.mybatis容易掌握,而hibernate门槛较高



整合:


SSM的原理(怎么工作的)?


运行流程:

1.jsp(view)发送请求

2.通过核心控制器DispatcherServlet调用请求解析器:HandlendMapping对请求进行解析,通过映射关系匹配到Controller层。

3.在控制层调用业务逻辑层(service),数据持久层(DAO)返回控制层,请求完成获取一个结果,设置一个要跳转的视图,(ModelAndView装载并传输数据,设置视图)

4.核心控制器调用 视图解析器:ViewResolver解析视图,匹配相应的页面实现页面跳转



Maven:


请你讲一下Maven的生命周期


Maven有三套相互独立的生命周期,请注意这里说的是“三套”,而且“相互独立”,初学者容易将Maven的生命周期看成一个整体,其实不然。这三套生命周期分别是:


Clean Lifecycle    在进行真正的构建之前进行一些清理工作。
Default Lifecycle  构建的核心部分,编译,测试,打包,部署等等。
Site Lifecycle       生成项目报告,站点,发布站点。


Maven拥有三套独立的生命周期,Maven的命令也是基于这些生命周期来说的。


1.clean:清理先前构建的构件,又分为下面三个下阶段:


  a.pre-clean 执行一些清理前需要完成的工作。
  b.clean 清理上一次构建生成的文件
  c.post-clean 执行一些清理后需要完成的工作


2.default:定义了真正构建时所需要的所有步骤,它是这三个中最核心的部分,包含的阶段如下:


  a.validate 验证项目是正确的并且所有必需的信息都是可用的
  b.initialize 初始化构建状态
  c.generate-sources 产生所有的用来编译的源代码
  d.process-sources 处理源代码
  e.generate-resources 产生包含在package中的资源
  f.process-resources 复制和处理资源到目标目录,为打包做好准备
  g.compile 编译项目的主源代码
  h.process-classes 对编译器产生的文件进行后期处理
  i.generate-test-sources 产生所有用来编译的测试源代码
  j.process-test-sources 处理测试源代码
  k.generate-test-resources 创建测试所需要的资源
  l.process-test-resources 复制和处理资源到测试目标目录
  m.compile 编译测试源代码到目标目录
  n.process-test-classes 对编译测试源代码产生的文件进行后期处理
  o.test 使用适当的单元测试框架运行测试,这些测试代码不应该被打包或者部署
  p.prepare-package 执行所有需要执行的操作为打包做准备,这往往会产生一个还未打包的处理过的包版本
  q.package 使用设置的方式对编译过的文件进行打包
  r.pre-integration-test 执行一些集成测试执行前必须的操作
  s.integration-test 处理和部署包到集成测试环境中,进行测试
  t.post-integration-test 对集成测试进行后期处理
  u.verify 执行所有检查确保包是正确的和符合质量要求的
  v.install 安装包到本地仓库,为其他本地的项目提供依赖i
  w.deploy 发布包,拷贝最后的包到远程仓库中,为其他的开发任何项目提供使用


3.site:建立和发布项目站点


  a.pre-site 前期准备
  b.site 产生项目的站点文档
  c.post-site 后期处理
  d.site-deploy 部署站点到服务器



maven中的jar冲突你是怎么解决的?


解决方法:在pom配置文件中加入<dependency>标签(去除依赖中的jar)




前端:


Ajax是如何工作的?


Ajax 由 HTML、JavaScript技术、DHTML 和 DOM 组成,这一杰出的方法可以将笨拙的 Web 界面转化成交互性的 Ajax 应用程序。


AJAX最核心的一个对象是XMLHttpRequest,所有的Ajax操作都离不开对这个对象的操作


XMLHttpRequest对象相关方法:


打开请求
XMLHttpRequest.open(传递方式,地址,是否异步请求)


准备就绪执行
XMLHttpRequest.onreadystatechange


获取执行结果
XMLHttpRequest.responseText



在注册的时候判断用户名是否存在,怎么实现?


使用AJAX的异步处理把当前用户名传到后台去,与数据库中的用户表进行对比看是否存在。




Javascirpt:


请你讲一下JavaScript 中2个等号“”==“”与3个等号”===”的区别


==, 两边值类型不同的时候,要先进行类型转换,再比较。 
===,不做类型转换,类型不同的一定不等。


下面分别说明: 

先说 ===,这个比较简单。下面的规则用来判断两个值是否===相等: 

1、如果类型不同,就[不相等] 
2、如果两个都是数值,并且是同一个值,那么[相等];(!例外)的是,如果其中至少一个是NaN,那么[不相等]。(判断一个值是否是NaN,只能用isNaN()来判断) 
3、如果两个都是字符串,每个位置的字符都一样,那么[相等];否则[不相等]。 
4、如果两个值都是true,或者都是false,那么[相等]。 
5、如果两个值都引用同一个对象或函数,那么[相等];否则[不相等]。 
6、如果两个值都是null,或者都是undefined,那么[相等]。 

再说 ==,根据以下规则: 

1、如果两个值类型相同,进行 === 比较。 
2、如果两个值类型不同,他们可能相等。根据下面规则进行类型转换再比较: 
   a、如果一个是null、一个是undefined,那么[相等]。 
   b、如果一个是字符串,一个是数值,把字符串转换成数值再进行比较。 
   c、如果任一值是 true,把它转换成 1 再比较;如果任一值是 false,把它转换成 0 再比较。 
   d、如果一个是对象,另一个是数值或字符串,把对象转换成基础类型的值再比较。对象转换成基础类型,利用它的toString或者valueOf方法。js核心内置类,会尝试valueOf先于toString;例外的是Date,Date利用的是toString转换。非js核心的对象,令说(比较麻烦,我也不大懂) 
   e、任何其他组合,都[不相等]。



Jquery:


用JQuery在页面上怎么添加属性?


jQuery中用attr()方法来获取和设置元素属性


jQuery的委托事务?


什么是事件委托:

通俗的讲,事件就是onclick,onmouseover,onmouseout,等一些事件,委托呢,就是让别人来做,这个事件本来是加在某些元素上的,然而你却加到别人身上来做,完成这个事件。


举个列子:

有三个同事预计会在周一收到快递。为签收快递,有两种办法:

一是三个人在公司门口等快递;

二是委托给前台MM代为签收。

现实当中,我们大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递)。前台MM收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台MM也会在收到寄给新员工的快递后核实并代为签收。


原理:
  利用冒泡的原理,把事件加到父级上,触发执行效果。


Jquery代码:

  1. (function(){&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$('#ul1,#ul2').on('click','li',function(){&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!$(this).attr('s'))&nbsp;{&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(this).css('background','red');&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(this).attr('s',true);&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else&nbsp;{&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(this).css('background','#fff');&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(this).removeAttr('s');&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;})&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>});&nbsp;&nbsp;</span></li></ol></div><pre code_snippet_id="2028027" snippet_file_name="blog_20161204_2_5723832" name="code" class="html" style="display: none;"> (function(){&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$('#ul1,#ul2').on('click','li',function(){&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!$(this).attr('s'))&nbsp;{&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(this).css('background','red');&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(this).attr('s',true);&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else&nbsp;{&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(this).css('background','#fff');&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$(this).removeAttr('s');&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;})&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>});&nbsp;&nbsp;</span></li></ol></div><pre code_snippet_id="2028027" snippet_file_name="blog_20161204_2_5723832" name="code" class="html" style="display: none;"> (function(){ (‘#ul1,#ul2’).on(‘click’,’li’,function(){ 
                    if(!
    (‘#ul1,#ul2’).on(‘click’,’li’,function(){                 if(!
    (this).attr(’s’)) { (this).css(background,red); ( t h i s ) . c s s ( ‘ b a c k g r o u n d ′ , ′ r e d ′ ) ; (this).attr(’s’,true); }else { (this).css(‘background’,’#fff’); (this).css(‘background’,’#fff’); (this).removeAttr(’s’); } }) });


    Jquery的选择器有哪些?


    jQuery选择器共有四大类,分别为基本选择器,层次选择器,过滤选择器和表单选择器。


    一、基本选择器
    1. id选择器(指定id元素)
    2. class选择器(遍历css类元素)
    3. element选择器(遍历html元素)
    4. * 选择器(遍历所有元素)
    5. 并列选择器
    二、层次选择器
    三、过滤选择器
    四、表单选择器

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值