Java:Effective java学习笔记之 通过私有构造器强化不可实例化的能力

Java 通过私有构造器强化不可实例化的能力

通过私有构造器强化不可实例化的能力

并非所有的类都是需要实例化的。有时候,我们可能需要编写至包含静态方法和静态域的类。这些类的名声很不好,因为有些人在面向对象的语言中滥用这样的类来编写过程化的程序。

尽管如此,它们也确实有它们特有的好处:

  • 1.利用这种类,以java.lang.Math或者java.util.Arrays的方式,把基本类型的值或者数组类型上的相关方法组织起来.
  • 2.我们也可以通过java.util.Collections的方式,把实现特定接口的对象上的静态方法包括工厂方法组织起来。
  • 3.利用这种类可以把final类上的方法组织起来,以取代扩展该类的做法。

以上是我们常用的一些工具类,一般是不希望被实例化的,因为实例化对它没有任何意义。

一、那么,我们可不可以将不可实例化的类定义为抽象类 ,因为我们知道抽象类是无法实例化的。但这样仍然不能保证,因为其子类依然可以被实例化。

抽象类

public abstract class DemoAbstract {
    
    
    public void test(){
    
    
        System.out.println(111111);
    }
}

子类

public class DemoAbstractSon extends DemoAbstract {
    
    
    @Override
    public void test() {
    
    
        super.test();
        System.out.println(222222);
    }
}

实验

public class Demo2 {
    
    
    public static void main(String[] args) {
    
    
        //抽象类不可以实例化
//        DemoAbstract demoAbstract = new DemoAbstract();
        //可以通过创建子类来获得父类对象,调用父类的方法
        DemoAbstract abstractSon = new DemoAbstractSon();
        abstractSon.test();
    }
}

二、有一些简单的习惯用法可以确保类不可被实例化。由于只有当类不包含显示的构造器时,编译器才会生成缺省的构造器,因此我们只要让这个类 包含私有构造器 ,他就不能被实例化了:

//Noninstantiable utility class
public class JDBCUtil {
    
    
    //Suppress default constructor for noninstantiability
    private JDBCUtil() {
    
    
        throw new AssertionError();
    }

    /**获取连接*/
    public static Connection getConnection() {
    
    
        Connection conn = null;
        try {
    
    
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/flowersale";
            String username = "root";
            String password = "root";
            conn = DriverManager.getConnection(url, username, password);
        } catch (ClassNotFoundException e) {
    
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
    
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return conn;
    }
    /**
     * 释放资源
     * @param rs
     * @param stmt
     * @param conn
     */
    public static void release(ResultSet rs,Statement stmt,Connection conn) {
    
    
        if(rs!=null) {
    
    
            try {
    
    
                rs.close();
            } catch (SQLException e) {
    
    
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        if(stmt!=null) {
    
    
            try {
    
    
                stmt.close();
            } catch (SQLException e) {
    
    
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        if(conn!=null) {
    
    
            try {
    
    
                conn.close();
            } catch (SQLException e) {
    
    
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    /**
     * 增删改代码整合
     */
    public static int execute(String sql,Object... args) {
    
    
        int result = -1;
        Connection conn = null;
        PreparedStatement ps = null;
        try {
    
    
            conn = JDBCUtil.getConnection();
            ps = conn.prepareStatement(sql);
            for(int i=0;i<args.length;i++) {
    
    
                ps.setObject(i+1, args[i]);
            }
            result = ps.executeUpdate();
        } catch (SQLException e) {
    
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
    
    
            JDBCUtil.release(null, ps, conn);
        }
        return result;
    }
}

上述代码是一个简单的JDBC连接数据库的工具类,在调用的过程中完全没必要将其实例化,故把该类的构造方法设为私有的,避免被实例化。

实验

public class DemoPrivate {
    
    
    //私有构造器,不可以被实例化和被继承
    private DemoPrivate(){
    
    
        //避免在类的内部调用构造器
        throw new AssertionError();
    }
    public void test(){
    
    
        System.out.println(111111);
    }

    public static void main(String[] args) {
    
    
        //会爆AssertionError错误
        DemoPrivate demoPrivate = new DemoPrivate();
        System.out.println(demoPrivate);
    }
}

三.优点

因为显示构造函数是私有的,所以它在类外是不可访问的,AssertionError不是必需的,但是它可以避免不小心在类的内部调用构造器。它保证该类在任何情况下都不会实例化。这种习惯用法有点违背直觉,好像构造器就是专门设计成不能被调用一样。因此明智的做法就是在代码中增加一条注释,如上所示。

四.缺点

这种习惯用法也有副作用,它使得一个类不能拥有子类。因为子类的所有构造函数都必须显示或者隐式地调用父类的构造函数,在这种情形下,子类就没有可访问的父类构造器可用了。

参考

《Effective Java》阅读笔记4 通过私有构造器强化不可实例化的能力

猜你喜欢

转载自blog.csdn.net/JMW1407/article/details/121440598