面试经常问一些模棱两可的问题,也就是一些在一些条件成立时,才能给出确定答案的问题。
比如问Java是否支持多继承。那么回答要缜密,接口支持,类不支持。
多继承导致网状继承结构。
F F
soft bed
softbed
F这层的成员变量会在softbed会出现两份。
所以在C++中采用虚继承来解决,达到了一种菱形结构。
F
soft bed
softbed
还有一点,就是F层的成员方法(不支持多态的方法),在soft和bed中都有。
Java所有方法都是virtual的
内存结构
---------------------------
Data [C++中是全局变量和static,Java中是static]
---------------------------
Code [代码区是共享的]
---------------------------
Heap
---------------------------
Stack
---------------------------
Java的接口,那都是指针表,只有在运行时,才能确定每个方法的具体指向。
所以在IDE中,在一定代码中,右键点击一个接口的引用,寻找definition的时候,只能定位到接口,不能定义到具体实现类,因为在IDE中能确定编译时的类型。
=================================================
Java修饰符号最后总结。
问class的修饰符有几种?
缜密回答,如果是顶级类,只有两种public 和 default。如果是内部类(成员内部类)就可以有四种。
new Outer().new Outer.Inner();
局部内部类是只能访问final的局部变量。
匿名内部类肯定是继承一个现有类型的类,或者实现一个现有接口。
静态内部类也是一个顶级类,不依赖于外部类的实例,只能访问外部类的静态成员变量,就好像静态方法。
C++中的嵌套类只相当于Java的静态内部类。
=========================
final和abstract是互斥的!绝对不能出现在一起。
final的变量可以在构造器中修改,因为Java没有想C++的初始化列表。
类型和名字在一起是核心原则,其他修饰符顺序可以随便变。
<modifiers><return-type><name>[argument_list][throws ...]
native与abstract也肯定互斥。
记住,书写习惯是很重要的。因为可以认为代码中“如果占居的位置一样,那么享受的权利就一样”
=========================
IdentityMap只用==排序。
List和Set的选择,在Hibernate和CMP中有用到,而且区别比较大。以后总结
=========================
线程相关函数,
sleep()可以出现在非Synchronized块中。而wait()肯定是Synchronized块中,因为此操作会释放锁。
都会跑出InterruppptedException。
----------------------------------------
线程加锁问题,困扰着软件开发人员。
T1 --------------------〉数据 <--------------------------T2
那么就在数据这边加锁呗。
在共享的对象类型中加减锁,在可读可写成员变量加减锁。
在访问static变量,加锁,访问相同外部资源加锁
在有读写两个方法,比如生产者,消费者问题,就要在加锁方法中添加wait和notify操作。
~~~~~~~~~~~~~~~~~~~~~~~~~~
实际上,在J2EE开发中,我们在做什么呢,实际上就是在编写数据那部分的代码。
Servlet,是什么,就是很多线程共享的一个数据对象,有相关的服务方法。
所以不建议在Servlet中写成员变量,因为有数据同步问题。
所以一般,都是在方法中定义局部变量,[在这说一句,为什么局部变量没有数据同步问题呢,那是因为对于每一个开启的Thread,都会从进程的栈区分化出一部分做本线程的独立栈区分配给局部变量]
SingleThreadModel已经被单独废除,因为此接口不能避免数据同步问题,因为即使一个Servlet类型可以创建多个实例,对于成员变量没有线程同步问题,但是如果在Servlet中操作共享对象,比如ServletContext,就完蛋了,或者是静态变量,和其他共享资源都要保护。
~~~~~~~~~~~~~~~~~~~~~~~~~~
IO 相关
byte[] InputStream OutStream
primitive DataInputStream DataOutputStream
String
字符 Reader Writer
InputStream和OutStream因为不能确定源和目的地,所以都是抽象的。
在字节流和字符流之间必须要有个桥转换,也就是Reader的构建需要一个InputStreamReader(InputStream,charset);
这里指的字符集是指JVM外部的编码方式。
外部编码方式---------------IN----------->JVM(UNICODE)-------------OUT------------->外部编码方式
--------------------------------------------
Exception RuntimeException
如果自定义异常是继承RuntimeException,就是表明如果在此处跑出这样的异常,其他地方是没有什么办法进行修复的,也就是调用方无办法。
而已检查异常则是,可以修复的异常。比如用户验证等,可以让用户在此输入用户名和密码。
最好也将运行时异常也声明在方法签名中。
============================
JDBC,驱动有四类,就是对已有ODBC的桥接,对Pro*C的本地C函数的调用,通过专有数据库协议,通过独立的协议,但需要在单独的一个Server进行转换。
分页显示的实现,可以从两个角度来做,一个SQL,一个是JDBC API,
import java.sql.*;
import java.io.*;
public class SeparatePage{
private String url;
private String username;
private String password;
private Connection conn(String url,String username,String password){
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con=DriverManager.getConnection(url,username,password);
return con;
}
catch(Exception conException){
conException.printStackTrace();
return null;
}
}
private PreparedStatement setScrollRs(Connection con,String sql){
try{
if(con==null)
return null;
PreparedStatement pst=con.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
return pst;
}
catch(Exception psException){
psException.printStackTrace();
return null;
}
}
private ResultSet execute(PreparedStatement pst){
try{
ResultSet rs=pst.executeQuery();
return rs;
}
catch(Exception ee){
System.out.println("query error:"+ee);
return null;
}
}
private int countPage(ResultSet rs,int pageSize){
try{
rs.last();
int rowCount = rs.getRow();
int pageCount = (rowCount+pageSize-1) / pageSize;
return pageCount;
}
catch(Exception e1){
System.out.println("countPage error:"+e1);
return 0;
}
}
private void beginPos(ResultSet rs,int pageNo,int pageSize){
try{
rs.absolute((pageNo-1) * pageSize + 1);
}
catch(Exception sql)
{
sql.printStackTrace();
}
}
private String getPrompt(String msg){
BufferedReader bis=new BufferedReader(new InputStreamReader(System.in));
try{
String s="";
System.out.println(msg);
if(s.length()<1) s = bis.readLine();
return s;
}catch(Exception ioException)
{
return null;
}
}
private void view(ResultSet rs,int pageSize){
try{
ResultSetMetaData rmeta = rs.getMetaData();
int numColumns = rmeta.getColumnCount();
int i = 0;
while(i<pageSize && !rs.isAfterLast())
{
for(int j = 0;j< numColumns;j++)
{
String sTemp = rs.getString(j+1);
System.out.print(sTemp+" ");
}
i++;
rs.next();
System.out.println();
}
}catch(Exception se){
se.printStackTrace();
}
}
void demo()
{
Connection con=null;
PreparedStatement pst=null;
ResultSet rs=null;
try{
boolean flag=true;
con=conn(url,username,password);
String sql = "select * from xj order by id";
pst=setScrollRs(con,sql);
rs=execute(pst);
while(flag){
int pageSize=Integer.parseInt(getPrompt("请输入页面长度"));
int pageCount=countPage(rs,pageSize);
if(getPrompt("是否退出(y/n)?").equals("y"))
{
flag = false;
break;
}
int pageNo=Integer.parseInt(getPrompt("请输入要查看第几页"));
beginPos(rs,pageNo,pageSize);
view(rs,pageSize);
if(getPrompt("是否返回(y/n)?").equals("y"))
continue;
}
}
catch(Exception e){
e.printStackTrace();
}
finally{
try{
if(con!=null) con.close();
if(pst!=null) pst.close();
if(rs!=null) rs.close();
}
catch (Exception ec){
ec.printStackTrace();
}
}
}
public static void main(String args[]){
if(args.length!=3){
System.out.println("use:java JDBCConn url username password");
return;
}
SeparatePage sp=new SeparatePage();
sp.url=args[0];
sp.username=args[1];
sp.password=args[2];
sp.demo();
}
}
============================
方框就是Attribute。
实际上还有Session的Map,有Session和一个ID,而这个ID被作为一个hook钩子放置于Cookie中,使得浏览器与Session对应上,屏蔽了Http无状态的弊端。
===========
监听器分为对于Session,Request,Application的生命周期的监听器和属性添加删除的监听器。
对于Session还有一个就是跟群集有关的,在FailOver的时候,要对Session 进行网络传输到备用设备上,那么属性和需要支持串行化,对于不能串行化的资源,比如数据库连接,需要有一个时机来断开和重新获得,那么就有HttpSessionActivationListener。
Struts和EJB,都是API依赖,都是基于继承多态的框架,移植性降低。
而Spring和Hibernate基于反射,弊端是依赖于配置,配置文件多,调试困难,因为都是要在运行时才能确定配置是否正确。
posted on 2006-04-22 12:34
北国狼人的BloG 阅读(531)
评论(2) 编辑 收藏 所属分类:
达内学习总结