これの話です。
Salesforce Developers
基本的な使い方はわかっていて、
ある変数に対するgetter/setter(アクセサメソッドと呼べばいいのかな)を定義すると
呼び出し側からは
// TestClassというクラスにmyPropertyというプロパティを定義した場合 TestClass test1 = new TestClass(); // getterが呼ばれる String str = test1.myProperty; // setterが呼ばれる test1.myProperty = 'Hi!';
というように(クラス名).(フィールド名)で簡単にアクセスできるようになる、という話。
今回よくわからなかったのが
そのgetter/setter内で同じプロパティ名を参照しているケースで、
public class TestClass { public String myProperty { get { // こんなん if (myProperty == null) { // (略) } } }
内部でどう動いているのか確認のために
次のようなコードを実行してみました。
(開発者コンソールにコピペすれば確認できます)
public class TestClass { public String myProperty { get { // ここのmyPropertyで何が参照されているのかよくわからなかった if (myProperty == null) { System.debug(LoggingLevel.INFO, 'myPropertyを生成します'); myProperty = 'Hello, World!'; } return myProperty; } set; } } // main TestClass testClass = new TestClass(); System.debug(LoggingLevel.INFO, '-----EXECUTE Getter-----'); System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, '-----EXECUTE Setter-----'); testClass.myProperty = 'こんにちは!'; System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, '-----EXECUTE Setter 2(set NULL)-----'); testClass.myProperty = null; System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, testClass.myProperty);
以下、実行結果(USER_DEBUGのみ)
13:04:08.053 (53542047)|USER_DEBUG|[21]|INFO|-----EXECUTE Getter----- 13:04:08.053 (53637540)|USER_DEBUG|[10]|INFO|myPropertyを生成します 13:04:08.053 (53701389)|USER_DEBUG|[22]|INFO|Hello, World! 13:04:08.053 (53740810)|USER_DEBUG|[23]|INFO|Hello, World! 13:04:08.053 (53757116)|USER_DEBUG|[25]|INFO|-----EXECUTE Setter----- 13:04:08.053 (53814142)|USER_DEBUG|[27]|INFO|こんにちは! 13:04:08.053 (53848413)|USER_DEBUG|[28]|INFO|こんにちは! 13:04:08.053 (53864121)|USER_DEBUG|[30]|INFO|-----EXECUTE Setter 2(set NULL)----- 13:04:08.053 (53917113)|USER_DEBUG|[10]|INFO|myPropertyを生成します 13:04:08.053 (53939613)|USER_DEBUG|[32]|INFO|Hello, World! 13:04:08.053 (53973310)|USER_DEBUG|[33]|INFO|Hello, World!
あーなるほど。
if文のmyPropertyは自分自身を指していて、
初回だけ値が定義されていない(null)からif文の中身が実行されますよ、ということなんですね。
ただし、この書き方だとmyPropertyにnullをセットすることができなくなりますよと。
(セットできるけど、getterが呼び出された時に初期化される)
(追記)
せっかくなのでもう少し試してみます。
検証1:getter内でmyPropertyに値をセットしなかった場合
public class TestClass { public String myProperty { get { String str; if (myProperty == null) { System.debug(LoggingLevel.INFO, 'myPropertyを生成します'); // ****変更点:別の変数に格納してみる**** str = 'Hello, World!'; } return str; } set; } } // main TestClass testClass = new TestClass(); System.debug(LoggingLevel.INFO, '-----EXECUTE Getter-----'); System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, '-----EXECUTE Setter-----'); testClass.myProperty = 'こんにちは!'; System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, '-----EXECUTE Setter 2(set NULL)-----'); testClass.myProperty = null; System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, testClass.myProperty);
結果1
14:23:10.076 (76091749)|USER_DEBUG|[23]|INFO|-----EXECUTE Getter----- 14:23:10.076 (76207524)|USER_DEBUG|[10]|INFO|myPropertyを生成します 14:23:10.076 (76235960)|USER_DEBUG|[24]|INFO|Hello, World! 14:23:10.076 (76273414)|USER_DEBUG|[10]|INFO|myPropertyを生成します 14:23:10.076 (76290322)|USER_DEBUG|[25]|INFO|Hello, World! 14:23:10.076 (76308709)|USER_DEBUG|[27]|INFO|-----EXECUTE Setter----- 14:23:10.076 (76392745)|USER_DEBUG|[29]|INFO|null 14:23:10.076 (76429525)|USER_DEBUG|[30]|INFO|null 14:23:10.076 (76446691)|USER_DEBUG|[32]|INFO|-----EXECUTE Setter 2(set NULL)----- 14:23:10.076 (76501997)|USER_DEBUG|[10]|INFO|myPropertyを生成します 14:23:10.076 (76517669)|USER_DEBUG|[34]|INFO|Hello, World! 14:23:10.076 (76552548)|USER_DEBUG|[10]|INFO|myPropertyを生成します 14:23:10.076 (76569634)|USER_DEBUG|[35]|INFO|Hello, World!
myPropertyは毎回nullとして扱われていますね。
検証2:setterがなかったら?
public class TestClass { public String myProperty { get { String str; if (myProperty == null) { System.debug(LoggingLevel.INFO, 'myPropertyを生成します'); myProperty = 'Hello, World!'; } return str; } // set; } } // main TestClass testClass = new TestClass(); System.debug(LoggingLevel.INFO, '-----EXECUTE Getter-----'); System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, '-----EXECUTE Setter-----'); testClass.myProperty = 'こんにちは!'; System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, '-----EXECUTE Setter 2(set NULL)-----'); testClass.myProperty = null; System.debug(LoggingLevel.INFO, testClass.myProperty); System.debug(LoggingLevel.INFO, testClass.myProperty);
結果2
ERROR: member variable not visible for assignment
エラーになりました。
検証1、2についてはともに期待した通りでした。
getter内でmyProperty = してるところってsetter呼んでるんだな、という。