[笔面] Java开发常见面试题目

常见的Java开发面试题目

1.CGLIB 和 JDK生成动态代理类的区别。
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法

2.HashMap、HashTable和concurrentHashMap的区别,HashMap的底层实现。
1.HashTable的方法是同步的,HashMap未经同步,所以在多线程场合要手动同步HashMap这个区别就像Vector和ArrayList一样。
2.HashTable不允许null值(key和value都不可以),HashMap允许null值(key和value都可以)。
3.HashTable有一个contains(Object value),功能和containsValue(Object value)功能一样。

因为多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap,如以下代码

final HashMap<String, String> map = new HashMap<String, String>(2);

Thread t = new Thread(new Runnable() {

@Override

public void run() {

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

new Thread(new Runnable() {

@Override

public void run() {

map.put(UUID.randomUUID().toString(), "");

}

}, "ftf" + i).start();

}

}

}, "ftf");

t.start();

t.join();

效率低下的HashTable容器
HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下HashTable的效率非常低下。因为当一个线程访问HashTable的同步方法时,其他线程访问HashTable的同步方法时,可能会进入阻塞或轮询状态。如线程1使用put进行添加元素,线程2不但不能使用put方法添加元素,并且也不能使用get方法来获取元素,所以竞争越激烈效率越低。

锁分段技术
HashTable容器在竞争激烈的并发环境下表现出效率低下的原因是所有访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。
ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap类似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素, 每个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。


3.Spring的事务管理机制。
Spring事务机制主要包括声明式事务和编程式事务,此处侧重讲解声明式事务,编程式事务在实际开发中得不到广泛使用,仅供学习参考。

Spring声明式事务让我们从复杂的事务处理中得到解脱。使得我们再也无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作。再也无需要我们在与事务相关的方法中处理大量的try…catch…finally代码。我们在使用Spring声明式事务时,有一个非常重要的概念就是事务属性。事务属性通常由事务的传播行为,事务的隔离级别,事务的超时值和事务只读标志组成。我们在进行事务划分时,需要进行事务定义,也就是配置事务的属性。

下面分别详细讲解,事务的四种属性,仅供诸位学习参考:

Spring在TransactionDefinition接口中定义这些属性,以供PlatfromTransactionManager使用, PlatfromTransactionManager是spring事务管理的核心接口。

public interface TransactionDefinition {
int getPropagationBehavior();//返回事务的传播行为。
int getIsolationLevel();//返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据。
int getTimeout();//返回事务必须在多少秒内完成。
boolean isReadOnly();//事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的。
}

1. TransactionDefinition接口中定义五个隔离级别:

ISOLATION_DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应;



ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。



ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。



ISOLATION_REPEATABLE_READ 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。



ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。

  

1: Dirty reads(脏读)。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。
2: non-repeatable reads(数据不可重复读)。比如事务A中两处读取数据-total-的值。在第一读的时候,total是100,然后事务B就把total的数据改成200,事务A再读一次,结果就发现,total竟然就变成200了,造成事务A数据混乱。
3: phantom reads(幻象读数据),这个和non-repeatable reads相似,也是同一个事务中多次读不一致的问题。但是non-repeatable reads的不一致是因为他所要取的数据集被改变了(比如total的数据),但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变,而是他的条件数据集改变。比如Select account.id where account.name="ppgogo*",第一次读去了6个符合条件的id,第二次读取的时候,由于事务b把一个帐号的名字由"dd"改成"ppgogo1",结果取出来了7个数据。

2. 在TransactionDefinition接口中定义了七个事务传播行为:

(1)PROPAGATION_REQUIRED 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。

Java代码:

//事务属性 PROPAGATION_REQUIRED 

methodA{ 

…… 

methodB(); 

…… 

}



//事务属性 PROPAGATION_REQUIRED 

methodB{ 

…… 

}

  

使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务。

 

单独调用methodB方法:

Java代码

main{

metodB();

}
相当于

Java代码

Main{



Connection con=null;



try{



con = getConnection();



con.setAutoCommit(false);



//方法调用



methodB();



//提交事务



con.commit();



}



Catch(RuntimeException ex){



//回滚事务



con.rollback();



}



finally{



//释放资源



closeCon();



}



}

  


Spring保证在methodB方法中所有的调用都获得到一个相同的连接。在调用methodB时,没有一个存在的事务,所以获得一个新的连接,开启了一个新的事务。

单独调用MethodA时,在MethodA内又会调用MethodB.

执行效果相当于:

Java代码

main{



Connection con = null;



try{



con = getConnection();



methodA();



con.commit();



}



catch(RuntimeException ex){



con.rollback();



}



finally{



closeCon();



}



}

  

调用MethodA时,环境中没有事务,所以开启一个新的事务.当在MethodA中调用MethodB时,环境中已经有了一个事务,所以methodB就加入当前事务。

(2)PROPAGATION_SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。

Java代码:

//事务属性 PROPAGATION_REQUIRED 

methodA(){ 

methodB(); 

}



//事务属性 PROPAGATION_SUPPORTS 

methodB(){ 

…… 

}

  

单纯的调用methodB时,methodB方法是非事务的执行的。当调用methdA时,methodB则加入了methodA的事务中,事务地执行。

(3)PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。

Java代码:

//事务属性 PROPAGATION_REQUIRED 

methodA(){ 

methodB(); 

}



//事务属性 PROPAGATION_MANDATORY 

methodB(){ 

…… 

}

  

当单独调用methodB时,因为当前没有一个活动的事务,则会抛出异常throw new IllegalTransactionStateException("Transaction propagation 'mandatory' but no existing transaction found");当调用methodA时,methodB则加入到methodA的事务中,事务地执行。


(4)PROPAGATION_REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。

Java代码:

//事务属性 PROPAGATION_REQUIRED 

methodA(){ 

doSomeThingA(); 

methodB(); 

doSomeThingB(); 

}



//事务属性 PROPAGATION_REQUIRES_NEW 

methodB(){ 

…… 

}



Java代码:



main(){ 

methodA(); 

}

  

相当于

Java代码:

main(){ 

TransactionManager tm = null; 

try{ 

//获得一个JTA事务管理器 

tm = getTransactionManager(); 

tm.begin();//开启一个新的事务 

Transaction ts1 = tm.getTransaction(); 

doSomeThing(); 

tm.suspend();//挂起当前事务 

try{ 

tm.begin();//重新开启第二个事务 

Transaction ts2 = tm.getTransaction(); 

methodB(); 

ts2.commit();//提交第二个事务 

} 

Catch(RunTimeException ex){ 

ts2.rollback();//回滚第二个事务 

} 

finally{ 

//释放资源 

} 

//methodB执行完后,复恢第一个事务 

tm.resume(ts1); 

doSomeThingB(); 

ts1.commit();//提交第一个事务 

} 

catch(RunTimeException ex){ 

ts1.rollback();//回滚第一个事务 

} 

finally{ 

//释放资源 

} 

}

  

在这里,我把ts1称为外层事务,ts2称为内层事务。从上面的代码可以看出,ts2与ts1是两个独立的事务,互不相干。Ts2是否成功并不依赖于ts1。如果methodA方法在调用methodB方法后的doSomeThingB方法失败了,而methodB方法所做的结果依然被提交。而除了methodB之外的其它代码导致的结果却被回滚了。使用PROPAGATION_REQUIRES_NEW,需要使用JtaTransactionManager作为事务管理器。
(5)PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作为事务管理器。(代码示例同上,可同理推出)

(6)PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常;

(7)PROPAGATION_NESTED如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。这是一个嵌套事务,使用JDBC 3.0驱动时,仅仅支持DataSourceTransactionManager作为事务管理器。需要JDBC 驱动的java.sql.Savepoint类。有一些JTA的事务管理器实现可能也提供了同样的功能。使用PROPAGATION_NESTED,还需要把PlatformTransactionManager的nestedTransactionAllowed属性设为true;而nestedTransactionAllowed属性值默认为false;

Java代码:

//事务属性 PROPAGATION_REQUIRED 

methodA(){ 

doSomeThingA(); 

methodB(); 

doSomeThingB(); 

}



//事务属性 PROPAGATION_NESTED 

methodB(){ 

…… 

}



如果

  

单独调用methodB方法,则按REQUIRED属性执行。如果调用methodA方法,相当于下面的效果:

Java代码:

main(){ 

Connection con = null; 

Savepoint savepoint = null; 

try{ 

con = getConnection(); 

con.setAutoCommit(false); 

doSomeThingA(); 

savepoint = con2.setSavepoint(); 

try{ 

methodB(); 

}catch(RuntimeException ex){ 

con.rollback(savepoint); 

} 

finally{ 

//释放资源 

}



doSomeThingB(); 

con.commit(); 

} 

catch(RuntimeException ex){ 

con.rollback(); 

} 

finally{ 

//释放资源 

} 

}

  

当methodB方法调用之前,调用setSavepoint方法,保存当前的状态到savepoint。如果methodB方法调用失败,则恢复到之前保存的状态。但是需要注意的是,这时的事务并没有进行提交,如果后续的代码(doSomeThingB()方法)调用失败,则回滚包括methodB方法的所有操作。


嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。


PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW的区别:它们非常类似,都像一个嵌套事务,如果不存在一个活动的事务,都会开启一个新的事务。使用PROPAGATION_REQUIRES_NEW时,内层事务与外层事务就像两个独立的事务一样,一旦内层事务进行了提交后,外层事务不能对其进行回滚。两个事务互不影响。两个事务不是一个真正的嵌套事务。同时它需要JTA事务管理器的支持。


使用PROPAGATION_NESTED时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚,它是一个真正的嵌套事务。DataSourceTransactionManager使用savepoint支持PROPAGATION_NESTED时,需要JDBC 3.0以上驱动及1.4以上的JDK版本支持。其它的JTA TrasactionManager实现可能有不同的支持方式。


PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行。


另一方面, PROPAGATION_NESTED 开始一个 "嵌套的" 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。


由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于 roll back.
PROPAGATION_REQUIRED应该是我们首先的事务传播行为。它能够满足我们大多数的事务需求。

4.Hibernate的工作原理,以及对象管理机制。

1.通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件
2.由hibernate.cfg.xml中的<mapping resource="com/xx/User.hbm.xml"/>读取并解析映射信息
3.通过config.buildSessionFactory();//创建SessionFactory
4.sessionFactory.openSession();//打开Sesssion
5.session.beginTransaction();//创建事务Transation
6.persistent operate持久化操作
7.session.getTransaction().commit();//提交事务
8.关闭Session
9.关闭SesstionFactory

在hibernate中对象有三种状态:瞬时态或自由态(transient)、持久化态(persistent)、托管态或游离态(detached)
(1).三态简介:
◆transient:瞬态或者自由态 (例如new Person("张三")
1.该po通过new等方式创建
2.该po的实例和session没有关联,不在session中缓存
3.该po在数据库中没有对应的记录

◆persistent:持久化状态 例如通过get和load等得到的对象
1.该po通过get、load等方法从数据库中取出并转化成对象
2.该po与session中的实例关联,在session中缓存
3.该po在数据库中有对应的记录

◆detached:脱管状态或者游离态
1.该po通过session的close、clear或者evict(obj)方法从持久态变化得到
2.该po的实例和session没有关联,不在session中缓存
3.该po在数据库中有对应的记录(前提是没有其他session删除此记录)
4.通过delete(obj)但不能执行事务(在一个事务中),也可以得到游离态的po,因delete而变成游离态可以通过save或saveOrUpdate()变成持久态。

(2)hibernate常用方法简介
◆update方法
1.操作的对象:自由态或脱管状态(因session的关闭而处于脱管状态)的对象
2.作用:将对象变为持久态(更新到数据库中)
3.触发方式:手动调用

◆flush方法
1.操作的对象:持久态对象(po)
2.作用:将对象更新到数据库中
3.触发方式:
a.手动调用
b.session的关闭、SessionFactory关闭,自动调用
c.get()一个对象,把对象的属性进行改变,把资源关闭,自动调用
d.transaction commit的时候,自动调用
e.transaction commit的时候,自动调用

◆lock方法
1.操作的对象:没有更改过的 脱管状态的对象(针对的是因Session的关闭而处于脱管状态的po对象,不能针对因delete而处于脱管状态的po对象)
2.作用:将对象变为持久化状态,等待flush方法将其更新到数据库
3.触发方式:手动调用

◆clear方法
1.操作的对象:session缓存
2.作用:完整的清除session缓存
3.触发方式:手动调用

◆evcit(obj)方法
1.操作的对象:某个持久化对象
2.作用:把某个持久化对象从session的缓存中清空
3.触发方式:手动调用


注意:在实际业务中经常需要从数据库取到一个对象,并将其进行处理,编码或解码某些属性进行其他操作,这时如果对象处于持久态,会在session关闭时同步到数据库中,而我们不想更改数据库中数据的状态,这时有两个方法解决:
1.new一个自由态的对象,拷贝原对象的属性(主键id)除外,使用new处理的新对象进行操作。
2.将对象从session中清空(evict(obj)方法),使其变为detached托管态,再进行操作。

5.String,StringBuffer和StringBuilder的区别。

6.流量控制需要用到什么算法。
流量控制就是让发送方的发送速率不要太快,让接收方来得及接受。利用滑动窗口机制可以很方便的在TCP连接上实现对发送方的流量控制。TCP的窗口单位是字节,不是报文段,发送方的发送窗口不能超过接收方给出的接收窗口的数值。
具体的算法有交互式数据流Nagle算法和慢启动与拥塞避免算法等,了解即可。

7.mysql如何实现分库分表,分哪几个步骤?
一般情况下,都可以对主键ID取模,做Hash,散列到多个表中。
比如我要对User表做分表操作,分散到一百个表中:
<?php
for($i=0;$i< 100; $i++ ){
//echo "CREATE TABLE db2.members{$i} LIKE db1.members<br>";
echo "INSERT INTO members{$i} SELECT * FROM members WHERE mid%100={$i}<br>";
}
?>

8.写一个死锁例子。

9.如何实现范式和反范式?
范式是关系数据库理论的基础,也是我们在设计数据库结构过程中所要遵循的规则和指导方法。
目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,还又称完美范式)。
各种范式呈递次规范,越高的范式数据库冗余越小。
不满足范式的模型,就是反范式模型。

反范式跟范式所要求的正好相反,在反范式的设计模式,我们可以允许适当的数据的冗余,用这个冗余去取操作数据时间的缩短。本质上就是用空间来换取时间,把数据冗余在多个表中,当查询时可以减少或者是避免表之间的关联;
RDBMS模型设计过程中,常常使用范式约束我们的模型,但在NOSQL模型中则大量采用反范式。

10.举一个反范式设计的例子?

数据库设计要严格遵守范式,这样设计出来的数据库,虽然思路很清晰,结构也很合理,但是,有的时候,却要在一定程度上打破范式设计。

这里其实并不矛盾,因为范式越高,设计出来的表可能越多,关系可能越复杂,但是性能却不一定会很好,因为表一多,就增加了关联性。特别是在高可用的OLTP数据库中,这一点表现得很明显。

最明显的打破范式的设计方法就是冗余法,以空间换取时间的做法,把数据冗余在多个表中,当查询时可以减少或者是避免表之间的关联。

还是用上面的例子,学生表与课程表,假定课程表要经常被查询,而且在查询中要显示学生的姓名,查询语句则为:

SQL>select code,name,subject from course c,
student s where s.id=c.code where code=?

这个语句如果被大范围、高频率执行,可能会因为表关联造成一定程度的影响,现在,假定评估到学生改名的需求是非常少的,那么,就可以把学生姓名冗余到课程表中,又变回了如表1-7所示:

表1-7

ID(PK)

编号

姓名

选修科目

1

001

张三

语文

2

001

张三

数学

3

001

张三

英语

4

002

李四

物理

5

002

李四

化学

6

003

王五

历史

7

003

王五

地理

8

003

王五

生物

注意:我这里并没有省略学生表,不过是把学生姓名冗余在了课程表中,如果万一有很少的改名需求,只要保证在课程表中改名正确即可。

那么,修改以后的语句可以简化为:

SQL>select code,name,subject from course c where code=?

 

 

11.linux常用的调优工具有哪些?
Perf 是用来进行软件性能分析的工具。
通过它,应用程序可以利用 PMU,tracepoint 和内核中的特殊计数器来进行性能统计。它不但可以分析指定应用程序的性能问题 (per thread),也可以用来分析内核的性能问题,当然也可以同时分析应用代码和内核,从而全面理解应用程序中的性能瓶颈。
最初的时候,它叫做 Performance counter,在 2.6.31 中第一次亮相。此后他成为内核开发最为活跃的一个领域。在 2.6.32 中它正式改名为 Performance Event,因为 perf 已不再仅仅作为 PMU 的抽象,而是能够处理所有的性能相关的事件。
使用 perf,您可以分析程序运行期间发生的硬件事件,比如 instructions retired ,processor clock cycles 等;您也可以分析软件事件,比如 Page Fault 和进程切换。
这使得 Perf 拥有了众多的性能分析能力,举例来说,使用 Perf 可以计算每个时钟周期内的指令数,称为 IPC,IPC 偏低表明代码没有很好地利用 CPU。Perf 还可以对程序进行函数级别的采样,从而了解程序的性能瓶颈究竟在哪里等等。Perf 还可以替代 strace,可以添加动态内核 probe 点,还可以做 benchmark 衡量调度器的好坏。

12.jvm的工作原理。


13.jvm的垃圾回收机制。

public void work()throws LeaveEarlyException { 

try{ 

便利店开门; 

营业时间; //可能会抛出Exception异常 

}catch(Exception e){ //店员突发离店

throw new LeaveEarlyException(); 

}finally{ 

关门; 

} 

} 

14.finally在任何情况下都会运行吗?如果不是在什么情况下不运行?
在程序中,应该确保占用的资源被释放,比如及时关闭数据库连接,关闭输入流,或者关闭输出流。finally代码块能保证特定的操作总是会被执行。

当你在捕获到异常的处理代码里加上:
System.exit();
这样的话finally的代码块是不会执行的。

17.Java为什么要使用内部类?
Java中的内部类和接口加在一起,可以的解决常被C++程序员抱怨Java中存在的一个问题——没有多继承。实际上,C++的多继承设计起来很复杂,而Java通过内部类加上接口,可以很好的实现多继承的效果。
每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。

18.平时关注比较多的是什么技术论坛?
图灵社区,InfoQ,开源中国,
CSDN,36氪,
另外也会关注一些技术团队的博客,
比如阿里中间件团队博客,http://jm.taobao.org/
阿里核心系统团队博客 http://csrd.aliapp.com/
QQ客户端团队博客 http://impd.tencent.com/
美团技术团队 http://tech.meituan.com/
自己也经常在博客园写博客。

20.MySQL存储过程常用的方法有哪些?
创建 MySQL 存储过程的简单语法为:

create procedure 存储过程名字() 

( 

[in|out|inout] 参数 datatype 

) 

begin 

MySQL 语句; 

end; 

可以使用call来调用存储过程。

Java中,类CallableStatement为Java程序提供了一种调用存储过程的方法。CallableStatement对象可以带有用于输入数据 (IN模式参数),输出结果(OUT模式参数) 或者用于上面这两种功能的参数(IN OUT模式参数)。

下面是在JDBC中调用存储过程的语法。需要注意的是语法中的方括号只是用于表示可选参数的,它不是命令语法的一部分。

{call procedure_name([?, ?, ...])}

下面是调用可以返回结果参数值的存储过程的语法:

{? = call procedure_name([?, ?, ...])}

  

21.jvm各个存储区分别默认为多少?
JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指 定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。

22.系统多久进行一次垃圾回收?

23.nio direct memory默认是多少?
在传统的文件IO操作中,我们都是调用操作系统提供的底层标准IO系统调用函数&nbsp; read()、write()
,此时调用此函数的进程(在JAVA中即java进程)由当前的用户态切换到内核态,然后OS的内核代码负责将相应的文件数据读取到内核的IO缓冲区,然
后再把数据从内核IO缓冲区拷贝到进程的私有地址空间中去,这样便完成了一次IO操作。至于为什么要多此一举搞一个内核IO缓冲区把原本只需一次拷贝数据
的事情搞成需要2次数据拷贝呢?
我想学过操作系统或者计算机系统结构的人都知道,这么做是为了减少磁盘的IO操作,为了提高性能而考虑的,因为我们的程序访问一般都带有局部性,也就是所
谓的局部性原理,在这里主要是指的空间局部性,即我们访问了文件的某一段数据,那么接下去很可能还会访问接下去的一段数据,由于磁盘IO操作的速度比直接
访问内存慢了好几个数量级,所以OS根据局部性原理会在一次
read()系统调用过程中预读更多的文件数据缓存在内核IO缓冲区中,当继续访问的文件数据在缓冲区中时便直接拷贝数据到进程私有空间,避免了再次的低
效率磁盘IO操作。

24.如何理解NIO?
NIO 可以让 java 程序员在和传统的 native 编码方式不同的方式下 , 实现高性能的输入 / 输出效果 ,NIO 把大多数消耗时间的 I/O 操作( namely,filling,draining buffer )的行为交给操作系统 , 所以性能上相比有了很大提升。

25.Java正则表达式如何表达前两位为13的11为手机号码?

26.覆盖了hashcode()方法,还要再覆盖那个方法?

27.for(; ;)会如何运行?
死循环,for(;;) = while(true),
除非循环体中终止。

28.jdbc如何访问数据库,快速写出访问代码。

29.jvm加载class文件的原理及访问顺序?

30.无状态会话Bean和有状态会话bean有什么区别?

31.链表有什么特点?

32.链式栈和顺序栈有什么区别?

33.软件生成周期模型有哪些种类?分别用在什么情况下?

34.共享锁和排他锁的区别?

35.mysql如何实现分页查询?

36.String类底层是如何实现的,List,Map底层是如何实现的?

37.建数据库需要遵循哪些原则?应该注意哪些方面?

38.spring的ioc和aop是如何实现?

39.jdk的反射有哪些api接口?是如何实现的?

41.MySQL数据库有哪些类型的索引?
MySQL主要提供2种方式的索引:B-Tree索引,Hash索引。
B树索引具有范围查找和前缀查找的能力,对于有N节点的B树,检索一条记录的复杂度为O(LogN)。相当于二分查找。
哈希索引只能做等于查找,但是无论多大的Hash表,查找复杂度都是O(1)。
显然,如果值的差异性大,并且以等值查找(=、 <、>、in)为主,Hash索引是更高效的选择,它有O(1)的查找复杂度。
如果值的差异性相对较差,并且以范围查找为主,B树是更好的选择,它支持范围查找。

42.如何创建索引,什么时候该创建、什么时候不应该创建?

创建索引的标准语法: 

CREATE INDEX 索引名 ON 表名 (列名) 

TABLESPACE 表空间名;



创建唯一索引: 

CREATE unique INDEX 索引名 ON 表名 (列名) 

TABLESPACE 表空间名;



创建组合索引: 

CREATE INDEX 索引名 ON 表名 (列名1,列名2) 

TABLESPACE 表空间名;



创建反向键索引: 

CREATE INDEX 索引名 ON 表名 (列名) reverse 

TABLESPACE 表空间名;

什么情况下应不建或少建索引
表记录太少
如果一个表只有5条记录,采用索引去访问记录的话,那首先需访问索引表,再通过索引表访问数据表,一般索引表与数据表不在同一个数据块,这种情况下DB至少要往返读取数据块两次。而不用索引的情况下DB会将所有的数据一次读出,处理速度显然会比用索引快。
经常插入、删除、修改的表
对一些经常处理的业务表应在查询允许的情况下尽量减少索引。
数据重复且分布平均的表字段
假如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建索引一般不会提高数据库的查询速度。

42.分布式如何实现单点登入?
单点登录的实现有很多,下面是CAS的实现原理:
用户尝试使用应用程序的 URL 访问应用程序。用户被重定向到 CAS 登录 URL,采用的是 HTTPS 连接,他请求的服务的名称作为参数传递。这时向用户显示一个用户名/密码对话框。
用户输入 ID 和密码,CAS 对他进行身份验证。如果身份验证失败,目标应用程序根本不会知道这个用户曾经试图访问它 —— 用户在 CAS 服务器上就被拦住了。
如果身份验证成功,CAS 就将用户重定向回目标应用程序,并在 URL 中附加一个称为 ticket 的参数。然后,CAS 尝试创建一个称为 ticket-granting cookie 的内存 cookie。这是为了以后进行自动的重新验证;如果存在这个 cookie,就表示这个用户已经成功地登录了,用户就不需要再次输入他的用户名和密码。
然后,应用程序要检查这个 ticket 是否正确,以及是否代表一个有效用户;检查的方法是,打开一个 HTTPS 连接来调用 CAS serviceValidate URL,并作为参数传递 ticket 和服务名称。CAS 检查这个 ticket 是否有效,以及是否与请求的服务相关联。如果检查成功,CAS 就将用户名返回给应用程序。

43.Web开发中网站缓存有哪几种,有什么作用?
第一、DNS缓存。
  这个是域名的缓存,比如说,我们的域名对应的IP是1.1.1.1换成2.2.2.2的时候,你的浏览器和你的路由器里边会保存半个小时左右的缓存。这时候就会出现一种情况是,有一部分人代开的是A服务器上的网站,有一部分人打开的是B服务器的网站。这二种奇怪的现象就是因为DNS的原因。等DNS缓存过去了之后就会正常。同时我们要说明的是,DNS缓存有两个重要的节点,一个是分布在整个网络的路由器上,另一个是因为本地电脑的原因,比如说同一个办公室的,你的打开是A服务器,而别人打开是B服务器,这就跟本地的DNS缓存有很大关系了。
第二、网站程序缓存。
  这个一般我们可以在网站管理后台看到“更新缓存”的按钮,这就是网站程序的缓存。比如有的程序,特别是PHP的程序,他会将一些程序片段弄成缓存,比如将index.html经过处理放到一个地方变成index.php,方便随时调用。
第三、服务器缓存。
  这种缓存是在服务器上,因为IIS等服务器的缓存作用,你的访问会有一些缓存。有的人不能区别网站缓存和服务器缓存。可以这样理解:网站的缓存系统就比如是一个漏洞,把油倒进漏斗里边,然后再流进水桶里边。漏洞就是网站程序缓存,水桶就是服务器缓存,哪一个地方没有刷新干净,都还会有油的香味在里边。服务器的缓存相当于第二道关。
第四、CDN加速缓存。
  有的网站用到CDN加速,将你的网站分不到全国十几个服务器节点中。这就相当于把刚才我们讲到的油分发到很多油桶里边。这个时候如果不同地点的访问就会出现差异化。比如说360网站卫士,百度加速乐都有CDN加速功能。
第五、浏览器缓存。
  很多主流的浏览器都有缓存,而360浏览器高速模式,搜狗浏览器高速模式缓存时间最多。这就是你经常看到同办公室的人打开网站是一个样,你打开这个网站又是一个样,这是因为有人经常访问,所以浏览器会缓存一些东西。

 

你可能感兴趣的:(java开发)