[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[jfriends] Re: [jfriends] 返値を毎回newして返すか、使 いまわすか




高橋(徹)です。

>返値に使うインスタンスを使いまわすと、そのインスタンスの内容を
>(受け取った側、保持している側で)変更して良いかどうかが、
>問題となります。
>AWTが返すDimensionの扱いで悩んだのはその判断でした。
>
>java.lang.Stringのように、インスタンスが変更不可能なものは
>使いまわしても全く問題無いのですが。

Java Report誌1999.4に、"Immutables"という記事があります。
内容は、イミュータブルなオブジェクトの設計についてです。
文字どおり、いったん生成された後は変更不可能なオブジェクトの
ことです。イミュータブルなオブジェクトの例にjava.lang.String
があります。戻り値に使って、あちこちで使いまわす場合は、
イミュータブルとして設計するとよいでしょう。イミュータブルな
オブジェクトはこのほか、スレッドセーフでもあります。
ただし、値を変更するには、その都度オブジェクトを生成すること
になり、パフォーマンスが悪くなります。

オブジェクトをイミュータブルにするには、フィールドに値を設定
するメソッド(setter)を持たないこと、全てのフィールドを
private宣言すること、です。ただし、フィールドがイミュータブル
でないオブジェクトだと、getterで取得した後に変更されてしまい
ます。そのときは、getterでフィールドを渡すときにclone()した
オブジェクトを渡すことで回避できるかもしれません。

また、パフォーマンスを重要視するときに、オブジェクト生成を
避けるイディオム"Pass-in, Pass-out"という話しも同記事に載って
います。メソッドを呼ぶ側がオブジェクトを保持し、メソッドの
引き数として渡し、メソッド内でそのオブジェクトに値を設定し
戻り値として返します。
例として紹介されていたコードは、Dimensionオブジェクトを返す
getSize()メソッドで、
(1)イディオムを使わない場合、
public Dimension getSize() {
  return new Dimension(width, height);
}

(2)Pass-inの場合
public void getSize(Dimension output) {
  output.width = width;
  output.height = height;
}

(3)Pass-in, Pass-out 
public Dimension getSize(Dimension output) {
  output.width = width;
  output.height = height;
  return output;
}

(1)の場合、getSizeするたびにオブジェクトの生成が発生します。
(2)の場合、オブジェクト生成はありませんが、button.getSize().width 
といった使いまわしができるようにするには(3)のように設計します。
(3)のイディオムを使った場合に、次のメソッドも用意しておくと便利です。
public final Dimension getSize() {
  return getSize( new Dimension() );
}
呼び手が最初にDimensionオブジェクトを必要とするときにこのメソッドを
使い、以降は(3)のメソッドを利用します。記事によれば、finalをつける
ことでコンパイラがインライン展開してくれることが期待できるとあります
が、そこまで必要かは?です。



------
Toru Takahashi
torutk@xxxxxxxxxx
NIFTY: GHE00470
http://www.alles.or.jp/~torutk/