本文参考《编写高质量代码:改善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