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 は初期化されておらず、null のままです。

ご存知のように、新しいオブジェクトを完全に構築するには、そのすべてのスーパー クラスを最初に初期化する必要があります。スーパー クラスの 1 つが構築に失敗した場合、オブジェクトの最終的な状態はどうなるでしょうか? それを決定することは不可能です。

このより精巧な例を見てください

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

いいえ、コンストラクターから例外がスローされると、try ブロックが突然完了します。コンストラクターからは何も返されません。ブロックランにはこれ以上何もありません。つまり、コードでは、構成は変更されていません。

于 2013-01-10T11:20:28.003 に答える
2

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

このコードは 3 つのステップで完了します。

  1. すべての基本オブジェクトを作成します。
  2. オブジェクト構成の作成
  3. への参照を割り当てるconfiguration

2 番目のステップが完了していないため、2 番目のステップも完了しません。つまり、configuration初期化されません。つまり、それconfiguration null ではなく、初期化されていません。コードはコンパイルされません。

ただし、最初のステップが完了すると、失われたオブジェクトが大量に発生します (GC の対象となります)。

于 2013-01-10T11:19:51.197 に答える
1

オブジェクトは作成されますが、それへの参照を受け取ることはありません。現状では、あなたのコードは決してコンパイルされません:

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

コンパイラはconfiguration、キャッチ ブロックに到達したときに が初期化されていない可能性があることを認識します。

于 2013-01-10T11:33:38.193 に答える
0

いいえ、オブジェクトのコンストラクターが例外をスローした場合、オブジェクトのインスタンスを取得できません。

これは、コンストラクターによって作成されるべきではないシングルトン オブジェクトの「最良の」方法の 1 つです。

于 2013-01-10T11:21:14.043 に答える
0

何らかの理由で、コンストラクターが定義された例外のいずれかをスローした場合、オブジェクトは作成されますか?

いいえ。コンストラクターが例外をスローした場合、参照configurationには値が割り当てられません。

これを参照してください:オブジェクトのインスタンス化が null を返す条件は何ですか?

于 2013-01-10T11:19:15.970 に答える
-1

いいえ、オブジェクトの初期化時に例外がスローされた場合、オブジェクトは作成されません。

于 2013-01-10T11:25:45.340 に答える