2

原則として、ブロック内で例外がスローされるかどうか、またはブロック自体で , または ステートメントが発生するかどうかにかかわらず、ブロックは常に実行finallyされます。trycontinuebreakreturntry

したがって、以下に示すコード スニペットのメソッドの戻り値を変更する必要がありますが、変更していません。

final class Product
{
    private String productName=null;

    public Product(String productName)
    {
        this.productName=productName;
    }

    public String getProductName()
    {
        try
        {
            return this.productName;
        }
        finally
        {
            this.productName="The product name has been modified in the finally block.";
            System.out.println("Product name in the finally block : "+this.productName);
        }
    }
}

public final class Test
{
    public static void main(String...args)
    {
        System.out.println(new Product("Intel core i3").getProductName());
    }
}

このメソッドは、このメソッドが呼び出される前にgetProductName()、コンストラクターによってフィールドに割り当てられた製品名を返すだけです。productName

このメソッドが戻る前に、 の値がブロックproductNameで変更されfinallyます。したがって、メソッドはこの新しい変更された値を返す必要がありproductNameますが、このクラスのインスタンスが構築されたときに割り当てられた初期値を返します。


次の出力が生成されます。

finally ブロック内の製品名 : finally ブロック内の製品名が変更されました。
インテル コア i3

このメソッドが、ブロック内のproductNameフィールドに割り当てられた新しい値を返さないのはなぜですか? finally新しい値を返す必要があります。そうじゃない?

4

2 に答える 2

5

ここで重要なのは、メソッドからそれぞれのオブジェクトへの参照値を返すことです。呼び出し側では、メソッドの参照のコピーが得られます。Java ではすべてが値渡しであることを忘れないでください。参照も値渡しです。

ブロック内の参照を使用してオブジェクトをfinally変更すると、呼び出し側で変更が表示されます。ただし、それ自体の値を変更した場合、reference両方の参照が異なるため、変更はもちろん呼び出し側に反映されません。

このメソッドが戻る前に、productName の値が finally ブロックで変更されます。

ブロックで行ったことは、新しいオブジェクトを参照にfinally割り当てたことです。の基準値が変わります。したがって、上記の段落によると、変更は呼び出し側には反映されません。どちらも 2 つの異なる String オブジェクトを扱っています。StringproductNameproductName

したがって、メソッドはこの新しい変更された値を返す必要があります。

いいえ、そうすべきではありません。両方の String オブジェクトがまったく異なるためです。StringBuilderオブジェクトでこのコードを試してください:

public StringBuilder getProductName() {

    StringBuilder sb = new StringBuilder(productName);
    try {
        return sb;
    }
    finally {
        sb.append("Modified");
    }
}

これで、 への変更がStringBuilder戻り値に反映されます。では、ここで何が起こっているのでしょうか?

まず、次の return ステートメントを使用します。

return sb;

StringBuilder作成したオブジェクトへの参照を返しました。次に、finallyブロックで:

sb.append("Modified");

.. が指すオブジェクトを変更しましたsb。それ自体の参照値を変更していないsbため、オブジェクトへの変更は、そのオブジェクトを指しているすべての参照に対して表示され、したがって、呼び出し側の参照も表示されます。

finallyブロックを次のように変更します。

sb = new StringBuilder("Modified");

変更が反映されているかどうかを確認します。戻り値に変化はありません。それは、自分自身の基準値を変更したからsbです。

さらに、finallyブロックから変更された参照を返すと、元の戻り値が上書きされます。finallyブロックを次のように変更してみてください。

finally {

    this.productName="The product name has been modified in the finally block.";
    System.out.println("Product name in the finally block : "+this.productName);

    return this.productName;  // Note: This is bad idea
}

これで、新しい値が表示されます。


以下も参照してください。

于 2013-10-14T12:54:24.857 に答える
1

finally ブロックは . を実行していないためreturn this.productNameです。

this.productNametry ブロックの returnは、オブジェクトのアドレスを返します。finally ブロックでの代入により、新しいオブジェクトが作成され、戻り値は変更されません。

于 2013-10-14T12:55:24.893 に答える