梦想空间's profile梦想空间PhotosBlogListsMore ![]() | Help |
|
|
July 10 java类加载的表现形式(收藏)使用者角度
java中的类是动态加载的,我们先看一下我们常用的类加载方式,先有一个感性的认识,才能进一步
深入讨论,类加载无非就是下面三种方式。 class A{} class B{} class C{} public class Loader{ public static void main(String[] args) throws Exception{ Class aa=A.class; Class bb=Class.forName("B"); Class cc=ClassLoader.getSystemClassLoader().loadClass("C"); } } 我们先看.class字面量方式,很多人可能不知道这种方式,因为这种用法不是一般java语法。 通过javap我们可以发现,这种方式的大致等价于定义了一个静态成员变量 static Class class$0;(后面的编号是增长的) 你可以试图再定义一个 static Class class$0,应该会收到一个编译错误(重复定义)。 Class aa=A.class;
就相当于 if(class$0==null){ try{ Class.forName("A"); } cacth(ClassNotFoundException e){ throw new NoClassDefFoundError(e); } } Class aa=class$0; 可以很清楚的看到,这种类的字面量定义其实不是加载类的方式,而是被编译器处理了,实质
上是使用了Class.forName方法,但是使用这种方式有一个很大的好处就是不用处理异常,因为 编译器处理的时候如果找不到类会抛出一个NoClassDefFoundError。也许你觉得需要处理 ClassNotFoundException这种异常,事实上99%的情况下我们可以把这种异常认为是一个错误。 所以大部分情况我们使用这种方式会更简洁。 最常用的方式就是Class.forName方式了,这也是一个通用的上层调用。这个方法有两个重载,
可能很多人都忽略了第二个方法。 public static Class forName(String name) throws ClassNotFoundException public static Class forName(String name, boolean initialize,ClassLoader loader) throws ClassNotFoundException 第二个方法后面多了两个参数,第二个参数表示是否初始化,第三个参数为指定的类加载器。
在上面的例子中: Class bb=Class.forName("B");等价于 Class bb=Class.forName("B",true,Loader.class.getClassLoader()); 这里要详细说一下这个类的初始化这个参数,如果这个参数为false的话, 类中的static成员不会被初始化,static语句块也不会被执行。 也就是类虽然被加载了,但是没有被初始化,不过在第一次使用时仍然会初始化。 所以我们有时候会看到Class.forName("XXX").newInstance()这样的语句,为什么这里要创建一个 不用的实例呢?不过是为了保证类被初始化(兼容以前的系统)。 其实第二个方法是比较难用的,需要指定类加载器,如果不指定而且又没有安装安全管理器的化, 是无法加载类的,只要看一下具体的实现就明白了。 最本质的方式当然是直接使用ClassLoader加载了,所有的类最终都是通过ClassLoader加载的,
Class cc=ClassLoader.getSystemClassLoader().loadClass("C"); 这里通过使用系统类加载器来加载某个类,很直接的方式,但是很遗憾的是通过这种方式加载类, 类是没有被初始化的(也就是初始化被延迟到真正使用的时候).不过我们也可以借鉴上面的经验,加载 后实例化一个对象Class cc=ClassLoader.getSystemClassLoader().loadClass("C").newInstance()。 这里使用了系统类加载器,也是最常用的类加载器,从classpath中寻找要加载的类。 java中默认有三种类加载器:引导类加载器,扩展类加载器,系统类加载器。 java中的类加载有着规范的层次结构,如果我们要了解类加载的过程,需要明确知道哪个类被谁 加载,某个类加载器加载了哪些类等等,就需要深入理解ClassLoader的本质。 以上只是类加载的表面的东西,我们还将讨论深层次的东西。 java中的时间操作(收藏)java中的时间操作不外乎这四种情况: 1、获取当前时间 2、获取某个时间的某种格式 3、设置时间 4、时间的运算 好,下面就针对这三种情况,一个一个搞定。
一、获取当前时间
有两种方式可以获得,第一种,使用Date类。 j2SE的包里有两个Date类,一个是java.sql.Date,一个是java.util.Date 这里,要使用java.util.Date。获取当前时间的代码如下 Date date = new Date(); date.getTime(); 还有一种方式,使用System.currentTimeMillis();
这两种方式获得的结果是一样的,都是得到一个当前的时间的long型的时间的毫秒值,这个值实际上是当前时间值与1970年一月一号零时零分零秒相差的毫秒数。 当前的时间得到了,但实际的应用中最后往往不是要用这个long型的东西,用户希望得到的往往是一个时间的字符串,比如“2006年6月18号”,或“2006-06-18”,老外可能希望得到的是“06-18-2006”,诸如此类等等。这就是下一个要解决的问题
二、获取某个时间的某种格式
获取时间的格式,需要用到一个专门用于时间格式的类java.text.SimpleDateFormat。 首先,定义一个SimpleDateFormat变量 SimpleDateFormat sdf = new SimpleDateFormat("",Locale.SIMPLIFIED_CHINESE); 这个构造函数的定义如下: SimpleDateFormat(String pattern, Locale locale) 第一个参数pattern,我们后面再解释,这里我们使用一个"",第二个参数,是用来设置时区的,这里用到了java.util.Locale这个类,这个类了面定义了很多静态变量,直接拿过来用就OK,我们把时区设置为Locale.SIMPLIFIED_CHINESE,只看名字,这个静态变量的意义已经很清楚了。
接下来我们使用这个SimpleDateFormat把当前时间格式化为一个如下格式的时间字符串“XXXX年XX月XX日_XX时XX分XX秒”,代码: sdf.applyPattern("yyyy年MM月dd日_HH时mm分ss秒"); String timeStr = sdf.format(new Date());
获取时间格式的函数是format,这个函数的参数是java.util.Date对象,这个没有什么花头。 要说明一下的是这个pattern,所谓的模式。这里,yyyy,MM,dd等,这就是模式。 我们可以在SimpleDateFormat的构造函数中指定模式,比如 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd",Locale.SIMPLIFIED_CHINESE); 也可以获取时间格式的时候使用applyPattern函数临时指定,上面的例子就是这样。 什么字符代表什么,这是j2se约定好的,设置模式的时候,我们可以使用约定好的字符加上任何我们想要的字符串。 j2se对字符所代表的模式的约定列表如下:
June 16 JAVA中数据库操作的各种方式与设计模式的应用 (收藏) 青山不改绿水长流-EKing 1. 在业务层使用JDBC直接操作数据库-最简单,最直接的操作紧耦合方式,黑暗中的痛苦 1)数据库url,username,password写死在代码中 Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); String url="jdbc:oracle:thin:@localhost:1521:orcl"; String user="scott"; String password="tiger"; Connection conn= DriverManager.getConnection(url,user,password); Statement stmt=conn.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); String sql="select * from test"; ResultSet rs=stmt.executeQuery(sql); 2)使用DBHelp类封装JDBC操作;数据库url,username,password可以放在配置文件中(如xml)。这种方法在小程序中应用较多。 2.DAO(Data Accessor Object)模式-松耦合的开始 DAO = data + accessor + domain object 例如User类-domain object (javabean) UserDAO类-accessor ,提供的方法getUser(int id),save(User user)内包含了JDBC操作在业务逻辑中使用这两个类来完成数据操作。 使用Factory模式可以方便不同数据库连接之间的移植。 3.数据库资源管理模式 3.1 数据库连接池技术资源重用,避免频繁创建,释放连接引起大大量性能开销;更快的系统响应速度; 通过实现JDBC的部分资源对象接口( Connection, Statement, ResultSet ),可以使用Decorator设计模式分别产生三种逻辑资源对象: PooledConnection, PooledStatement和 PooledResultSet。 一个最简单地数据库连接池实现: public class ConnectionPool { private static Vector pools; private final int POOL_MAXSIZE = 25; /** * 获取数据库连接 * 如果当前池中有可用连接,则将池中最后一个返回;若没有,则创建一个新的返回 */ public synchronized Connection getConnection() { Connection conn = null; if (pools == null) { pools = new Vector(); } if (pools.isEmpty()) { conn = createConnection(); } else { int last_idx = pools.size() - 1; conn = (Connection) pools.get(last_idx); pools.remove(last_idx); } return conn; } /** * 将使用完毕的数据库连接放回池中 * 若池中连接已经超过阈值,则关闭该连接;否则放回池中下次再使用 */ public synchronized void releaseConnection(Connection conn) { if (pools.size() >= POOL_MAXSIZE) try { conn.close(); } catch (SQLException e) { // TODO自动生成 catch 块 e.printStackTrace(); } else pools.add(conn); } public static Connection createConnection() { Connection conn = null; try { Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); String url = "jdbc:oracle:thin:@localhost:1521:orcl"; String user = "scott"; String password = "tiger"; conn = DriverManager.getConnection(url, user, password); } catch (InstantiationException e) { // TODO自动生成 catch 块 e.printStackTrace(); } catch (IllegalAccessException e) { // TODO自动生成 catch 块 e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO自动生成 catch 块 e.printStackTrace(); } catch (SQLException e) { // TODO自动生成 catch 块 e.printStackTrace(); } return conn; } } 注意:利用getConnection()方法得到的Connection,程序员很习惯地调用conn.close()方法关闭了数据库连接,那么上述的数据库连接机制便形同虚设。 在调用conn.close()方法方法时如何调用releaseConnection()方法?这是关键。这里,我们使用Proxy模式和java反射机制。 public synchronized Connection getConnection() { Connection conn = null; if (pools == null) { pools = new Vector(); } if (pools.isEmpty()) { conn = createConnection(); } else { int last_idx = pools.size() - 1; conn = (Connection) pools.get(last_idx); pools.remove(last_idx); } ConnectionHandler handler=new ConnectionHandler(this); return handler.bind(con); } public class ConnectionHandler implements InvocationHandler { private Connection conn; private ConnectionPool pool; public ConnectionHandler(ConnectionPool pool){ this.pool=pool; } /** * 将动态代理绑定到指定Connection * @param conn * @return */ public Connection bind(Connection conn){ this.conn=conn; Connection proxyConn=(Connection)Proxy.newProxyInstance( conn.getClass().getClassLoader(), conn.getClass().getInterfaces(),this); return proxyConn; } /* (非 Javadoc) * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO自动生成方法存根 Object obj=null; if("close".equals(method.getName())){ this.pool.releaseConnection(this.conn); } else{ obj=method.invoke(this.conn, args); } return obj; } } 在实际项目中,并不需要你来从头开始来设计数据库连接池机制,现在成熟的开源项目,如C3P0,dbcp,Proxool等提供了良好的实现。一般推荐使用Apache dbcp,基本使用实例: DataSource ds = null; try{ Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env"); ds = (DataSource)envCtx.lookup("jdbc/myoracle"); if(ds!=null){ out.println("Connection is OK!"); Connection cn=ds.getConnection(); if(cn!=null){ out.println("cn is Ok!"); Statement stmt = cn.createStatement(); ResultSet rst = stmt.executeQuery("select * from BOOK"); out.println("
rst is Ok!" + rst.next()); while(rst.next()){ out.println(" BOOK_CODE:" + rst.getString(1)); } cn.close(); }else{ out.println("rst Fail!"); } } else out.println("Fail!"); }catch(Exception ne){ out.println(ne); } 3.2 Statement Pool 普通预编译代码: String strSQL=”select name from items where id=?”; PreparedStatement ps=conn.prepareStatement(strSQL); ps.setString(1, “2”); ResultSet rs=ps.executeQuery(); 但是PreparedStatement 是与特定的Connection关联的,一旦Connection关闭,则相关的PreparedStatement 也会关闭。为了创建PreparedStatement 缓冲池,可以在invoke方法中通过sql语句判断池中还有没有可用实例。 4. 持久层设计 1) Hernate:适合对新产品的开发,进行封闭化的设计 Hibernate 2003年被Jboss接管,通过把java pojo对象映射到数据库的table中,采用了xml/javareflection技术等。3.0提供了对存储过程和手写sql的支持,本身提供了hql语言。开发所需要的文件: hibernate配置文件: hibernate.cfg.xml 或 hibernate.properties hibernate 映射文件: a.hbm.xml pojo类源文件: a.java 导出表与表之间的关系: a. 从java对象到hbm文件:xdoclet b. 从hbm文件到java对象:hibernate extension c. 从数据库到hbm文件:middlegen d. 从hbm文件到数据库:SchemaExport 2) Iatis :适合对遗留系统的改造和对既有数据库的复用,有很强的灵活性 3) Apache OJB:优势在于对标准的全面支持 4)EJB:适合集群服务器,其性能也不象某些人所诟病的那么差劲 5) JDO (java data object) 设置一个Properties对象,从而获取一个JDO的PersistenceManagerFactory(相当于JDBC连接池中的DataSource),进而获得一个PersistenceManager对象(相当于JDBC中的Connection对象),之后,你可以用这个PersistenceManager对象来增加、更新、删除、查询对象。 JDOQL是JDO的查询语言;它有点象SQL,但却是依照Java的语法的。 JDBC连接各种数据库方式列表 (收藏)下面罗列了各种数据库使用JDBC连接的方式,可以作为一个手册使用。 1、Oracle8/8i/9i数据库(thin模式) Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); String url="jdbc:oracle:thin:@localhost:1521:orcl"; //orcl为数据库的SID String user="test"; String password="test"; Connection conn= DriverManager.getConnection(url,user,password); 2、DB2数据库 Class.forName("com.ibm.db2.jdbc.app.DB2Driver ").newInstance(); String url="jdbc:db2://localhost:5000/sample"; //sample为你的数据库名 String user="admin"; String password=""; Connection conn= DriverManager.getConnection(url,user,password); 3、Sql Server7.0/2000数据库 Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance(); String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb"; //mydb为数据库 String user="sa"; String password=""; Connection conn= DriverManager.getConnection(url,user,password); 4、Sybase数据库 Class.forName("com.sybase.jdbc.SybDriver").newInstance(); String url =" jdbc:sybase:Tds:localhost:5007/myDB";//myDB为你的数据库名 Properties sysProps = System.getProperties(); SysProps.put("user","userid"); SysProps.put("password","user_password"); Connection conn= DriverManager.getConnection(url, SysProps); 5、Informix数据库 Class.forName("com.informix.jdbc.IfxDriver").newInstance(); String url = "jdbc:informix-sqli://123.45.67.89:1533/myDB:INFORMIXSERVER=myserver; user=testuser;password=testpassword"; //myDB为数据库名 Connection conn= DriverManager.getConnection(url); 6、MySQL数据库 Class.forName("org.gjt.mm.mysql.Driver").newInstance(); //或者Class.forName("com.mysql.jdbc.Driver"); String url ="jdbc:mysql://localhost/myDB?user=soft&password=soft1234&useUnicode=true&characterEncoding=8859_1" //myDB为数据库名 Connection conn= DriverManager.getConnection(url); 7、PostgreSQL数据库 Class.forName("org.postgresql.Driver").newInstance(); String url ="jdbc:postgresql://localhost/myDB" //myDB为数据库名 String user="myuser"; String password="mypassword"; Connection conn= DriverManager.getConnection(url,user,password); 8、access数据库直连用ODBC的 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver") ; String url="jdbc:odbc:Driver={MicroSoft Access Driver (*.mdb)};DBQ="+application.getRealPath("/Data/ReportDemo.mdb"); Connection conn = DriverManager.getConnection(url,"",""); Statement stmtNew=conn.createStatement() ; |
|
|