Jon*_*eet 350
是的,构造函数可以抛出异常.通常这意味着新对象立即有资格进行垃圾收集(当然,它可能在一段时间内不会被收集).如果它在构造函数中早先可见(例如,通过指定静态字段或将其自身添加到集合中),那么"半构造"对象可能会留下来.
关于在构造函数中抛出异常要注意的一件事:因为调用者(通常)无法使用新对象,构造函数应该小心避免获取非托管资源(文件句柄等)然后抛出异常没有释放它们.例如,如果构造函数尝试打开a FileInputStream和a FileOutputStream,并且第一个成功但第二个失败,则应尝试关闭第一个流.如果它是抛出异常的子类构造函数,这会变得更难,当然......这一切都变得有点棘手.这不是经常出现的问题,但值得考虑.
Bil*_*ain 78
是的,他们可以抛出异常.如果是这样,它们将仅部分初始化,如果不是最终的,则受到攻击.
以下内容来自安全编码指南2.0.
可以通过终结器攻击来访问非最终类的部分初始化实例.攻击者覆盖子类中受保护的finalize方法,并尝试创建该子类的新实例.此尝试失败(在上面的示例中,SecurityManager检查ClassLoader的构造函数会引发安全性异常),但攻击者只是忽略任何异常并等待虚拟机对部分初始化的对象执行最终化.当发生这种情况时,将调用恶意终结方法实现,使攻击者能够访问此对象,即对正在最终确定的对象的引用.尽管该对象仅部分初始化,但攻击者仍然可以在其上调用方法(从而绕过SecurityManager检查).
V_S*_*ngh 14
是的,它可以抛出异常,您也可以在构造函数的签名中声明它,如下例所示:
public class ConstructorTest
{
public ConstructorTest() throws InterruptedException
{
System.out.println("Preparing object....");
Thread.sleep(1000);
System.out.println("Object ready");
}
public static void main(String ... args)
{
try
{
ConstructorTest test = new ConstructorTest();
}
catch (InterruptedException e)
{
System.out.println("Got interrupted...");
}
}
}
Run Code Online (Sandbox Code Playgroud)
Vin*_*lds 11
是的,允许构造函数抛出异常.
但是,选择它们应该是什么例外非常明智 - 检查异常或未选中.未经检查的异常基本上是RuntimeException的子类.
在几乎所有情况下(我都不能对这种情况提出异常),你需要抛出一个检查过的异常.原因是未经检查的异常(如NullPointerException)通常是由于编程错误(如未充分验证输入).
检查异常提供的优点是程序员被迫在其实例化代码中捕获异常,从而意识到可能无法创建对象实例.当然,只有代码审查才会捕获吞噬异常的糟糕编程习惯.