第4条:通过私有构造器强化不可实例化的能力
问题思考:有时候,你可能需要编写只包含静态方法和静态域的类作为工具类(utility class),这样的工具类不希望被实例化,实例化对它没有任何意义。然而,在缺少显示构造器的情况下,编译器会提供一个公有的、无参的缺省构造器(default constructor),这个构造器与其它构造器没有任何区别。在已发行的API中常常可以看到一些被无意识地实例化的类。
错误做法:将这种类做成抽象类来强制该类不可被实例化。这是行不通的,该类可以被子类化,并且该子类也可以被实例化。这样做甚至会误导用户,以为这种类是专门为了被继承而设计的。
解决办法:让这个类包含私有构造器:
1 //Noninstantiable utility class 2 public class JDBCUtil { 3 //Suppress default constructor for noninstantiability 4 private JDBCUtil() { 5 throw new AssertionError(); 6 } 7 8 /**获取连接*/ 9 public static Connection getConnection() { 10 Connection conn = null; 11 try { 12 Class.forName("com.mysql.jdbc.Driver"); 13 String url = "jdbc:mysql://localhost:3306/flowersale"; 14 String username = "root"; 15 String password = "root"; 16 conn = DriverManager.getConnection(url, username, password); 17 } catch (ClassNotFoundException e) { 18 // TODO Auto-generated catch block 19 e.printStackTrace(); 20 } catch (SQLException e) { 21 // TODO Auto-generated catch block 22 e.printStackTrace(); 23 } 24 return conn; 25 } 26 /** 27 * 释放资源 28 * @param rs 29 * @param stmt 30 * @param conn 31 */ 32 public static void release(ResultSet rs,Statement stmt,Connection conn) { 33 if(rs!=null) { 34 try { 35 rs.close(); 36 } catch (SQLException e) { 37 // TODO Auto-generated catch block 38 e.printStackTrace(); 39 } 40 } 41 if(stmt!=null) { 42 try { 43 stmt.close(); 44 } catch (SQLException e) { 45 // TODO Auto-generated catch block 46 e.printStackTrace(); 47 } 48 } 49 if(conn!=null) { 50 try { 51 conn.close(); 52 } catch (SQLException e) { 53 // TODO Auto-generated catch block 54 e.printStackTrace(); 55 } 56 } 57 } 58 59 /** 60 * 增删改代码整合 61 */ 62 public static int execute(String sql,Object... args) { 63 int result = -1; 64 Connection conn = null; 65 PreparedStatement ps = null; 66 try { 67 conn = JDBCUtil.getConnection(); 68 ps = conn.prepareStatement(sql); 69 for(int i=0;i<args.length;i++) { 70 ps.setObject(i+1, args[i]); 71 } 72 result = ps.executeUpdate(); 73 } catch (SQLException e) { 74 // TODO Auto-generated catch block 75 e.printStackTrace(); 76 }finally { 77 JDBCUtil.release(null, ps, conn); 78 } 79 return result; 80 } 81 }
上述代码是一个简单的JDBC连接数据库的工具类,在调用的过程中完全没必要将其实例化,故把该类的构造方法设为私有的,避免被实例化。
缺点:它使得一个类不能被子类化。因为所有的构造器都必须是显示或隐式地调用超类(superclass)的构造器,在这种情况下,子类就没有可以访问的超类构造器可以调用了。