2

假设我有以下代码:

public class Conf{    
  public Conf(String szPath) throws IOException, ConfErrorException{
      ...
  }
  public void someMethod(){
    ...
  }
}

然后我想以这种方式实例化对象:

Conf configuration = new Conf("/etc/myapp/myconf.conf");

如果由于某种原因,构造函数抛出任何定义的异常,会创建对象吗?
我的意思是,我是否仍然能够访问其中的方法,例如,如下面的代码?

Conf configuration;
try{
   configuration = new Conf("/etc/myapp/myconf.conf");
}catch(IOException|ConfErrorException e){
   //Suppose we entered here
   configuration.someMethod();
}
4

8 回答 8

6

让我从一个对象构造失败的场景开始,它可以举例说明如果你可以使用这样的失败对象可能会出现什么问题:

让我们定义一个类 A,这样:

class A {
   private String a = "A";

   public A() throws Exception {
        throw new Exception();
   }
}

现在,假设我们想在一个try...catch块中创建一个 A 类型的对象。

A a = null;
try{
  a = new A();
}catch(Exception e) {
  //...
}
System.out.println(a);

显然,此代码的输出将是:null.

为什么 Java 不返回 A 的部分构造版本?毕竟,当构造函数失败时,它的name字段成员已经被初始化了,对吧?

Java 没有这样做,因为该对象没有成功构建。该对象处于不一致状态,因此被 Java 丢弃。您的变量 A 甚至没有初始化,它保持为空。

现在,如您所知,要完全构建一个新对象,必须首先初始化它的所有超类。如果其中一个超类未能构建,那么该对象的最终状态是什么?这是不可能确定的。

看看这个更详细的例子

class A {
   private final int a;
   public A() throws Exception { 
      a = 10;
   }
}

class B extends A {
   private final int b;
   public B() throws Exception {
       methodThatThrowsException(); 
       b = 20;
   }
}

class C extends B {
   public C() throws Exception { super(); }
}

C调用 的构造函数时,如果初始化时发生异常B,最终变量的值是int b多少?

因此,无法创建对象 C,它是伪造的,是垃圾,它没有完全初始化。

于 2013-01-10T11:31:20.727 回答
5

构造函数抛出任何定义的异常,会创建对象吗?

对象总是在构造函数被调用之前创建。否则构造函数中将没有this要初始化的对象。

如果你抛出一个异常,你将失去对该对象的引用,除非你做了一些可疑的事情,比如在抛出异常之前将对象存储在构造函数中。

public class Main {
    static class ThrowsException {
        static final List<ThrowsException> BAD_LIST = new ArrayList<>();

        ThrowsException() {
            System.out.println("this = " + this);
            BAD_LIST.add(this);
            throw new RuntimeException();
        }
    }

    public static void main(String... args) {
        for (int i = 0; i < 3; i++) {
            ThrowsException te = null;
            try {
                te = new ThrowsException();
            } catch (Exception ignored) {
            }
            System.out.println("te = " + te);
        }
        System.out.println(ThrowsException.BAD_LIST);
    }

印刷

this = Main$ThrowsException@22911fb5
te = null
this = Main$ThrowsException@65b8b5cd
te = null
this = Main$ThrowsException@41a7d9e7
te = null
[Main$ThrowsException@22911fb5, Main$ThrowsException@65b8b5cd, Main$ThrowsException@41a7d9e7]
于 2013-01-10T11:26:17.817 回答
2

Conf configuration = new Conf("/etc/myapp/myconf.conf");

此代码分 3 步完成:

  1. 创建所有基础对象。
  2. 创建对象 Conf
  3. 分配参考configuration

由于您没有完成第二步,因此第二步也不会完成,这意味着configuration不会初始化。这意味着它configuration 不是空的,它甚至没有被初始化。您的代码将无法编译。

然而,由于第一步完成,会有一堆丢失的对象(符合 GC 条件)。

于 2013-01-10T11:19:51.197 回答
2

不,构造函数抛出异常会突然完成 try 块。构造函数没有返回任何内容。块中没有更多内容。这意味着,在您的代码中,配置不变。

于 2013-01-10T11:20:28.003 回答
1

将创建一个对象,但您永远不会收到对它的引用。就目前而言,您的代码永远不会编译:

Conf configuration;
try{
    configuration = new Conf("/etc/myapp/myconf.conf");
}catch(IOException|ConfErrorException e){
    //Suppose we entered here
   configuration.someMethod();
}

编译器认识到configuration当它到达 catch 块时可能没有初始化。

于 2013-01-10T11:33:38.193 回答
0

如果由于某种原因,构造函数抛出任何定义的异常,会创建对象吗?

不,如果构造函数抛出异常,引用configuration将不会被赋值。

请参考:什么条件导致对象实例化返回 null?

于 2013-01-10T11:19:15.970 回答
0

不,如果对象的构造函数抛出异常,您将无法获取该对象的实例。

它是不应由构造函数创建的单例对象的“最佳”方法之一。

于 2013-01-10T11:21:14.043 回答
-1

不,如果初始化对象时抛出异常,则不会创建对象。

于 2013-01-10T11:25:45.340 回答