让工具类不能实例化

本文参考《编写高质量代码:改善Java程序的151个建议》
Java开发中,我们经常会使用工具类。例如JDK自带的Math类,工具类的方法和属性都是静态的,因此不需要实例即可访问。因为不需要实例化,因此JDK对工具类做了构造函数私有化的限制。让我们看看Math类的源码:

public final class Math {

    /**
     * Don't let anyone instantiate this class.
     */
    private Math() {}
}

使用private访问限制Math类除了本身之外都不能产生新的实例。注释也写得十分清楚:“不要让任何人实例化这个类。”但是Java中反射十分强大,可以修改构造函数访问权限,即使将构造函数私有化,也还是控制不住。还是有解决办法:

public final class Util {

    /**
     * Don't let anyone instantiate this class.
     */
    private Util() {
    	throw new Error("该类不能被实例化!");
    }
}

这样就可以保证你的工具类不可实例化。

下面参考一位博主的博文来详细说明怎么实例化private修饰构造方法的类:

Java反射在类中的应用:通过反射访问构造函数(方法): https://blog.csdn.net/jijiangpeng/article/details/95096903.

public class Book {

    String name; //图书名称
    int id, price; //图书编号和价格

    //空的构造方法
    private Book() {
    }

    //带两个参数的构造方法
    protected Book(String _name, int _id) {
        this.name = _name;
        this.id = _id;
    }

    //带可变参数的构造方法
    public Book(String... strings) throws NumberFormatException {
        if (0 < strings.length)
            id = Integer.valueOf(strings[0]);
        if (1 < strings.length)
            price = Integer.valueOf(strings[1]);
    }

    //输出图书信息
    public void print() {
        System.out.println("name=" + name);
        System.out.println("id=" + id);
        System.out.println("price=" + price);
    }
}

测试:

public class Test01 {

    public static void main(String[] args) {
        //获取动态类Book
        Class book = Book.class;
        //获取Book类的所有构造方法
        Constructor[] declaredContructors = book.getDeclaredConstructors();
        //遍历所有构造方法
        for (int i = 0; i < declaredContructors.length; i++) {
            Constructor con = declaredContructors[i];
            //判断构造方法的参数是否可变
            System.out.println("查看是否允许带可变数量的参数:" + con.isVarArgs());
            System.out.println("该构造方法的入口参数类型依次为:");
            //获取所有参数类型
            Class[] parameterTypes = con.getParameterTypes();
            for (int j = 0; j < parameterTypes.length; j++) {
                System.out.println(" " + parameterTypes[j]);
            }
            System.out.println("该构造方法可能拋出的异常类型为:");
            //获取所有可能拋出的异常类型
            Class[] exceptionTypes = con.getExceptionTypes();
            for (int j = 0; j < exceptionTypes.length; j++) {
                System.out.println(" " + parameterTypes[j]);
            }
            //创建一个未实例化的Book类实例
            Book book1 = null;
            while (book1 == null) {
                try { //如果该成员变量的访问权限为private,则拋出异常
                    if (i == 1) {
                        //通过执行带两个参数的构造方法实例化book1
                        book1 = (Book) con.newInstance("Java 教程", 10);
                    } else if (i == 2) {
                        //通过执行默认构造方法实例化book1
                        book1 = (Book) con.newInstance();
                    } else {
                        //通过执行可变数量参数的构造方法实例化book1
                        Object[] parameters = new Object[]{new String[]{"100", "200"}};
                        book1 = (Book) con.newInstance(parameters);
                    }
                } catch (Exception e) {
                    System.out.println("在创建对象时拋出异常,下面执行 setAccessible() 方法");
                    con.setAccessible(true); //设置允许访问 private 成员
                }
            }
            book1.print();
            System.out.println("=============================\n");
        }
    }
}

当通过反射访问默认构造方法 Book() 时,将看到如下所示的输出:(实例化成功)

查看是否允许带可变数量的参数:false
该构造方法的入口参数类型依次为:
该构造方法可能拋出的异常类型为:
在创建对象时拋出异常,下面执行 setAccessible() 方法
name=null
id=0
price=0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值