9. Struts和struts2.0有什么区别,使用时需要注意什么?
/*Action类
Struts1要求Action类继承一个抽象类,Struts1使用抽象类编程而不是接口
Struts2可以实现Action接口也可以不实现,Struts2提供一个ActionSuport基类去实现常用接口。Action接口不是必须的,任何有execute的标识的POJO都有可能成为struts2的Action的对象
/*线程模式
Struts1的Action是单例模式并且是线程安全的,仅有Action一个实例来处理所有请求。单策略模式限制了Struts1 Action能做的事。比且在开发时要注意Action资源必须是线程
安全比且是同步的。
Struts2的Action对象为每个请求产生一个实例,因此没有线程安全问题。
/*Servlet依赖
Struts1 Action依赖与Servlet API,因为当一个Action被调用时HttpServletRequest和HttpServletResponse被传递给execute方法。
Struts2 Action不依赖与容器,允许Action脱离容器被单独测试。如果需要,struts2依然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServletRequest和HttpServletResponse的必要性。
/*可测性:
测试Struts1 Action的一个主要问题是execute方法暴漏了Servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)
struts2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。
/*捕获输入:
struts1使用ActionForm对象捕获输入。所有ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的基类不或输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有沉余的JavaBean)。
Struts2直接使用Acrtion属性作为输入属性,消除了对第二个输入对象的请求。输入属性可能是有自己(子)属性的Rich对象类型。Action属性能过通过web页面上的Taglibs访问。struts2也支持ActionForm模式。Richard对象类型,包括业务对象,能够用作输入/输出对象。这种ModelDriven特性简化了Taglib对POJO输入对象的引用。
/*表达式语言
Struts1整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很脆弱。
Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--“object graph Notation Language”(OGNL)
/*绑定值到页面(view)
Struts1使用标准JSP机制吧对象绑定到页面中来访问。
struts2使用ValueStack技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重同页面(view)
/*类型转换
Struts1 ActionForm属性通常都是String类型。struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的
struts2 使用OGNL进行类型转换,提供基本和常用对象的转换器。
/*效验
Struts1支持在ActionForm的validate方法中手动效验,或者通过Commons Validator的扩展来效验。同一个类可以有不同的效验内容,但不能效验子对象。
Struts2支持通过validate方法和XWork效验框架进行效验。XWork效验框架使用为属性类类型定义的效验和内容效验,来支持Chain效验子属性。
/*Action执行的控制
Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。
struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不能的生命周期。堆栈能够根据需要和不同的Action一起使用。
10. 使用Java定义一个单链表结构,编程实现对定义的单链表结构的反转。
/*
* @author luochengcheng
* 定义一个单链表
*/
class Node {
//变量
privatEint record;
//指向下一个对象
private Node nextNode;
public Node(int record) {
super();
this.record = record;
}
publicintgetRecord() {
return record;
}
public void setRecord(int record) {
this.record = record;
}
public Node getNextNode() {
returnnextNode;
}
public void setNextNode(Node nextNode) {
this.nextNode = nextNode;
}
}
/*
* @author luochengcheng
* 两种方式实现单链表的反转(递归、普通)
* 新手强烈建议旁边拿着纸和笔跟着代码画图(便于理解)
*/
public class ReverseSingleList {
/*
* 递归,在反转当前节点之前先反转后续节点
*/
public static Node reverse(Node head) {
if (null == head || null == head.getNextNode()) {
return head;
}
Node reversedHead = reverse(head.getNextNode());
head.getNextNode().setNextNode(head);
head.setNextNode(null);
returnreversedHead;
}
/*
* 遍历,将当前节点的下一个节点缓存后更改当前节点指针
*
*/
public static Node reverse2(Node head) {
if (null == head) {
return head;
}
Node P = head;
Node cur = head.getNextNode();
Node next;
while (null != cur) {
next = cur.getNextNode();
cur.setNextNode(P);
P = cur;
cur = next;
}
//将原链表的头节点的下一个节点置为null,再将反转后的头节点赋给head
head.setNextNode(null);
head = P;
return head;
}
public static void main(String[] args) {
Node head = new Node(0);
Node tmp = null;
Node cur = null;
// 构造一个长度为10的链表,保存头节点对象head
for (int i = 1; i < 10; i++) {
tmp = new Node(i);
if (1 == i) {
head.setNextNode(tmp);
} else {
cur.setNextNode(tmp);
}
cur = tmp;
}
//打印反转前的链表
Node h = head;
while (null != h) {
System.out.print(h.getRecord() + " ");
h = h.getNextNode();
}
//调用反转方法
head = reverse2(head);
System.out.println("\n*");
//打印反转后的结果
while (null != head) {
System.out.print(head.getRecord() + " ");
head = head.getNextNode();
}
}
}
运行:
C:\ex>java ReverseSingleList
0 1 2 3 4 5 6 7 8 9
*
9 8 7 6 5 4 3 2 1 0
11. 如何比较2个超大数组是否相等,要求时间复杂度O(n)(写出思路)
12. 现有8个硬币和一个天平,其中有一个硬币比其他的轻,最少需要几次能找到该硬币,如何实现,写出思路。