Java面试总结
前段时间一直找工作,遇到面试了很多公司,遇到了一些问题,每次面试之后,回来都把面试总结一下,现将面试总结贡献,希望对找工作的朋友有点用
一、同步和互斥:
互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。
二、下面代码有何异常,为什么?
Thread t = new Thread();
t.start();
t.start();
该题目考的就是Java中的线程模型,Java中,每个线程有六个状态,在Thread类有个私有变量private int threadStatus = 0;用来标记线程的状态,Java中,线程的所有状态如下:
System.out.println(Thread.State.NEW.ordinal());
// output:0
System.out.println(Thread.State.RUNNABLE.ordinal());
// output:1
System.out.println(Thread.State.BLOCKED.ordinal());
// output:2
System.out.println(Thread.State.WAITING.ordinal());
// output:3
System.out.println(Thread.State.TIMED_WAITING.ordinal());
// output:4
System.out.println(Thread.State.TERMINATED.ordinal());
// output:5
因此,当我们new一个Thread类之后,该线程的状态threadStatus为0(默认值),表示该线程为新奇的一个线程,在调用了t.start()之后,该值变为非0(一般来说为1),而在Thread类的start方法中有如下逻辑
if (threadStatus != 0)
throw new IllegalThreadStateException();
即当第二次调用t.start()时,则会抛出IllegalThreadStateException异常
线程之间的装换关系图如下:
三、设计一个线程,当子线程执行结束之后,再执行主线程
package com.yf.interview;
public class ThreadTest2 {
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
System.out.println("The main thread is begin");
Thread t = new SubThread1(1);
t.start();
t.join();
System.out.println("The main thread is end");
}
}
class SubThread1 extends Thread {
private int i;
public SubThread1(int i) {
this.i = i;
}
public void run() {
System.out.println("the subThread is begin ");
try {
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("the subThread is end ");
}
}
四、Struts2的原理
答案:
1 客户端初始化一个指向Servlet容器(例如Tomcat)的请求
2 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin)
3 接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action
4 如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy
5 ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类
6 ActionProxy创建一个ActionInvocation的实例。
7 ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。
8 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可 能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper
五、Hibernate原理及为什么要用
答案:
原理:
1.读取并解析配置文件
2.读取并解析映射信息,通过SessionFactory创建Session
3.打开Sesssion
4.创建事务Transation
5.持久化操作
6.提交事务
7.关闭Session
为什么要用:
1. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
2. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作
3. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
4. hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。
六、Ajax原理
答案:
Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面
七、数据库事物以及事物级别
答案:
事物: 构成数据库处理逻辑单元的执行程序
事物特性(ACID):
?原子性: 要么全部执行要么全部不执行
?一致性: 一个事物的执行结果,数据库保持一致性
?隔离性: 一个事物执行时,与另个一个事物无关
?持久性: 对于已经提交的事物,数据库的改变时永久的
事物级别
1.读未提交(Read Uncommitted):这种隔离级别可以让当前事务读取到其它事物还没有提交的数据。这种读取应该是在回滚段中完成的。通过上面的分析,这种隔离级别是最低的,会导致引发脏读,不可重复读,和幻读。
2.读已提交(Read Committed):这种隔离级别可以让当前事务读取到其它事物已经提交的数据。通过上面的分析,这种隔离级别会导致引发不可重复读,和幻读。
3.可重复读取(Repeatable Read):这种隔离级别可以保证在一个事物中多次读取特定记录的时候都是一样的。通过上面的分析,这种隔离级别会导致引发幻读。
4.串行(Serializable):这种隔离级别将事物放在一个队列中,每个事物开始之后,别的事物被挂起。同一个时间点只能有一个事物能操作数据库对象。这种隔离级别对于数据的完整性是最高的,但是同时大大降低了系统的可并发性。
八、Spring对事物的支持
答案:Spring提供的事务管理可以分为两类:编程式的和声明式的。编程式的,比较灵活,但是代码量大,存在重复的代码比较多;声明式的比编程式的更灵活方便。
1、传统使用JDBC的事务管理
以往使用JDBC进行数据操作,使用DataSource,从数据源中得到Connection,我们知道数据源是线程安全的,而连接不是线程安全的,所以对每个请求都是从数据源中重新取出一个连接。一般的数据源由容器进行管理,包括连接池。例如TOMCAT,WEBSPHERE,WEBLOGIC等这些J2EE商业容器都提供了这个功能。
以往的我们使用JDBC在写代码时,事务管理可能会是这样:
Connection conn = null;
try{
conn = DBConnectionFactory.getConnection;
conn.setAutoCommit(false);
//do something
conn.commit(); //commit transcation
}catch(Exception e){
conn.rollback();
}
finally{
try{
conn.close();
} catch(SQLException se){ //do sth.}
//close ResultSet,PreparedStatement,Connection
//notice:Maybe ocurr Exception when u close rs,pstmt,conn
}
按照以往的思路来写代码,代码量比较长,而且容易疏忽,忘掉一些try/catch,引发一些异常无法catch,虽然有时候我们会写DBTool类,来关闭这些资源,并且保证在关闭这些资源时,不向外抛异常,但是这样做会导致额外的麻烦。
2、Spring提供的编程式的事务处理
Spring提供了几个关于事务处理的类:TransactionDefinition //事务属性定义
TranscationStatus //代表了当前的事务,可以提交,回滚。
PlatformTransactionManager这个是spring提供的用于管理事务的基础接口,其下有一个实现的抽象类AbstractPlatformTransactionManager,我们使用的事务管理类例如DataSourceTransactionManager等都是这个类的子类。
我们使用编程式的事务管理流程可能如下:
(1) 声明数据源。
(2) 声明一个事务管理类,例如:DataSourceTransactionManager,HibernateTransactionManger,JTATransactionManager等
(3) 在我们的代码中加入事务处理代码:
TransactionDefinition td = new TransactionDefinition();
TransactionStatus ts = transactionManager.getTransaction(td);
try{
//do sth
transactionManager.commit(ts);
}catch(Exception e){transactionManager.rollback(ts);}
使用Spring提供的事务模板TransactionTemplate:
void add()
{
transactionTemplate.execute( new TransactionCallback(){
pulic Object doInTransaction(TransactionStatus ts)
{ //do sth}
}
}
TransactionTemplate也是为我们省去了部分事务提交、回滚代码;定义事务模板时,需注入事务管理对象。
3、Spring声明式事务处理
Spring声明式事务处理也主要使用了IoC,AOP思想,提供了TransactionInterceptor拦截器和常用的代理类TransactionProxyFactoryBean,可以直接对组件进行事务代理。
使用TransactionInterceptor的步骤:
(1)定义数据源,事务管理类
(2)定义事务拦截器,例如:
<bean id = "transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="target"><ref local="userManagerTarget"/></property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
TransactionProxyFactoryBean只是为组件的事务代理,如果我们要给组件添加一些业务方面的验证等,可以使用TransactionTemplate加拦截器方式,为组件添加多个拦截器,spring AOP中提供了三类Advice,即前增强,后增强,抛出异常时的增强,可以灵活使用。
九、JavaScript创建对象的几种方式
1.利用json创建对象
var myObj = {
"id": 1, //属性名用引号括起来,属性间由逗号隔开
"name": "zhangsan",
"age":10,
"test":function(){
document.write("我叫"+this.name+"今年"+this.age+"岁");
}
};
myObj.test()
//结果
//我叫zhangsan今年10岁
2.用 function 关键字模拟 class
function myClass() {
this.id = 5;
this.name = 'myclass';
this.getName = function() {
return this.name;
}
}
var my = new myClass();
alert(my.id);
alert(my.getName());
3.使用JavaScript中的Object类型
var company= new Object();
company.name= "天堂";
company.address = "北京";
company.produce= function(message)
{
alert(message);
}
company.produce("天堂");