Java EE知识储备(一)
参考文献:《Java编程思想Thinking in Java第四版》 Bruce Eckel著 机械工业出版社目录:
1、ArrayList和Vector的区别,HashMap和HashTable的区别。
2、Struts中事件的请求如/xxxx.do?method=xx的形式能否修改?
3、事务及并发问题的处理上保证数据的一致性的机制。
4、分页方式来显示列表的数据的好处
5、编程:HTML展示表格
6、编程:HashMap遍历问题
7、求运行结果:异常处理问题
8、EL表达式问题
9、求运行结果:ArrayList
10、发现String性能不好,原因?
1、ArrayList和Vector的区别,HashMap和HashTable的区别。
答:Vector类、Hashtable类和Stack类都已经过时。
(1)ArrayList和Vector的区别:
Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好。
当Vector或ArrayList中的元素超过它的初始大小需要扩展时,Vector默认是增加为原来的一倍,而ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。
jdk1.8中ArrayList的源代码:
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
jdk1.8中Vector的源代码:
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
(2)Hashtable和HashMap的区别:
HashMap是Hashtable的轻量级实现。HashMap不是线程安全的,允许在一个集合有一个null键和在一个集合有多个null值;Hashtable是线程安全的,不允许任何内容为null值。在效率上,HashMap高于Hashtable。HashMap是Map接口的一个实例,Hashtable是继承于Dictionary类的。
Hashtable类的对象必须重写Object的hashCode和equals方法。
2、在Struts中,事件的请求一般采用如/xxxx.do?method=xx的形式,请问这里的do和method能否修改为别的字符,若不能请说明原因,若能请说明如何修改。
答:可以修改。do在web.xml里面配置,method在struts-config.xml配置。
比如在web.xml里面修改为*.action结尾:
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/application-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
3、在事务及并发问题的处理上,一般采用什么机制来保证数据的一致性,有几种不同的方式?各自优缺点?
答:在事务及并发问题的处理上一般采用锁机制来保证数据的一致性,锁机制常见有两种,悲观锁和乐观锁。
(1)悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。
(2)乐观锁:假定不会发生并发冲突,只是在提交时检查是否违反数据完整性。乐观锁不能解决脏读的问题。
悲观锁的实现,往往依靠数据库提供的锁机制;乐观锁,一般是基于数据版本记录机制来实现,就是在数据库表增加一个表示“版本”的字段,读取出数据时,将此版本号一同读出,更新数据时,对版本号做递增处理,此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
4、系统中一般都采用分页方式来显示列表的数据,这样做有什么好处?
答:从性能上可以减轻数据库查询的压力及应用服务器的压力,另外减少了在网络中的数据量传送,从而加快页面数据的显示。
5、请使用HTML标记语言补充完整,使其可以展示下图所示表格。
图5.1 题目要求
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8"/>
<title>第五题</title>
</head>
<body>
<table border="1px" width="40%">
<tr>
<td>1</td>
<td>2</td>
<td rowspan="2">3</td>
</tr>
<tr>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>6</td>
<td colspan="2">7</td>
</tr>
</table>
</body>
</html>
6、使代码遍历hm对象并将每个key及其对应的value用System.out.println输出。
HashMap<String,String> hm = new HashMap<String,String>();
hm.put(“1111”,”Remoa”);
hm.put(“1112”,”Deng”);
hm.put(“1113”,”Qinyi”);
答:代码示例如下:
package com.remoa.test;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class HashMapLearn {
public static void main(String[] args) {
HashMap<String,String> hm = new HashMap<String,String>();
hm.put("1111","Remoa");
hm.put("1112","Deng");
hm.put("1113","Qinyi");
//方式一
for(Iterator<Map.Entry<String, String>> iter = hm.entrySet().iterator(); iter.hasNext();){
Map.Entry<String, String> entry = iter.next();
System.out.println("key=" + entry.getKey() + ", value=" + entry.getValue());
}
//方式二
for(String key : hm.keySet()){
System.out.println("key=" + key + ", value=" + hm.get(key));
}
}
}
7、代码如下:
package com.remoa.test;
public class ExceptionTest {
public static void main(String[] args) {
float i = 0;
try {
for (i = 0; i < 10; i++) {
try {
System.out.println("10/" + i + "=" + 10 / i);
if (i == 2) {
throw new RuntimeException("i=" + i);
}
} catch (ArithmeticException e) {
System.out.println("异常一,i=" + i);
}
}
} catch (Exception e) {
System.out.println("异常二," + e.getMessage());
}
}
}
写出运行结果:
图7.1 运行结果
8、EL表达式${param.userName}与下列哪个语句等价?
①<%=StringUtils.trimToEmpty((String)request.getSession().getAttribute(“userName”))%>
②<%=StringUtils.trimToEmpty((String)request.getAttribute(“userName”))%>
③<%=StringUtils.trimToEmpty(request.getParameter(“userName”))%>
答:有${username}这样一个正则表达式,它回去依次调用pageContext.getAttribute("username")->request.getAttribute("username")->session.getAttribute("username") -> application.getAttribute("username"),只要找到某一个不为空的值就立刻返回。
param对应request.getParameter()
paramValues对应request.getParameterValues()
request.getParameter取得是通过容器的实现来取得通过类似post,get等方式传入的数据。request.getAttribute只是在web容器内部流转,仅仅是请求处理阶段。
${param.name} 等价于 request.getParamter("name"),这两种方法一般用于服务器从页面或者客户端获取的内容。
${requestScope.name} 等价于 request.getAttribute("name"),一般是从服务器传递结果到页面,在页面中取出服务器保存的值。
所以答案为③
9、代码如下,求运行结果:
package com.remoa.test;
import java.util.ArrayList;
import java.util.List;
class UserVO{
private String userId;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
@Override
public String toString() {
return "UserVO [userId=" + userId + "]";
}
}
public class ExceptionTest {
public static void main(String[] args) {
UserVO userVO = new UserVO();
List<UserVO> userVOs = new ArrayList<UserVO>();
for (int i = 0; i < 3; i++) {
userVO.setUserId("Remoa" + i);
userVOs.add(userVO);
}
System.out.println("userVOs.size()=" + userVOs.size());
for (UserVO _userVO : userVOs) {
System.out.println(_userVO.getUserId());
}
}
}
答:
图9.1 运行结果
说明:ArrayList.add()方法:将指定的元素添加到此列表的结尾。
答:因为String对象的不可变性,每一次读要创建一个新的String对象,改为StringBuffer可能会提高性能。