さて、私は優れたJodaTimeライブラリをいじり回して、一般的な小売/会計(4-5-4)カレンダーを実装しようと試みてきました。私はすでに私の会社の特定のケースを見つけましたが、一般的なケース(主に年の初めとうるう年の決定)はキラーです。たとえば、2会計年度(通常は364日)が1ISO年の間に開始される一連の日付があります。
年の始まりのルールを決定する過程で、私は、ISOの飛躍日のどちら側に該当するかに基づいて、年の始まりを決定するための抽象クラスといくつかの具体的なクラスに行き着きました。
(簡素化された)抽象クラス:
private static abstract class SimpleFiscalYearEndPattern implements FiscalYearEndPattern {
protected final int leapYearCountOffset;
protected final int doomsdayOffset;
private final int startingDayOfWeek;
private final int yearOffset;
private final long millisFromEpochToFiscalYearStart;
private final long millisElapsedToEpochDividedByTwo;
/**
* Restricted constructor
* @param fiscalYear
* @param startingOn
* @param inFirstWeek
*/
protected SimpleFiscalYearEndPattern(final int fiscalYear, final LocalDate startingOn, final MonthDay inFirstWeek) {
this.yearOffset = fiscalYear - startingOn.getYear();
this.doomsdayOffset = getDoomsdayOffset(inFirstWeek);
this.startingDayOfWeek = startingOn.getDayOfWeek();
final int startingDoomsday = getDoomsdayOffset(new MonthDay(startingOn, REFERENCE_CHRONOLOGY));
// If the starting doomsday is a later day-of-week, it needs to become negative.
this.leapYearCountOffset = calculateLeapYearCountOffset(startingDoomsday : doomsdayOffset, doomsdayOffset);
final int leapYearsBefore = getPreviousLeapYears(fiscalYearBeforeEpoch);
}
}
(簡素化された)具体的なクラス(1/7から2/28の範囲の日付の場合):
private static final class BeforeLeapYearEndPattern extends SimpleFiscalYearEndPattern {
private static final int FIRST_YEAR_LEAP_YEAR_OFFSET = -1;
private BeforeLeapYearEndPattern(final int fiscalYear, final LocalDate startingOn, final MonthDay onOrBefore) {
super(fiscalYear, startingOn, onOrBefore);
}
public static final BeforeLeapYearEndPattern create(final int fiscalYear, final LocalDate startingOn, final MonthDay onOrBefore) {
return new BeforeLeapYearEndPattern(fiscalYear, startingOn, onOrBefore);
}
/* (non-Javadoc)
* @see ext.site.time.chrono.FiscalYearEndPatternBuilder.SimpleFiscalYearEndPattern#getPreviousLeapYears(int)
*/
@Override
protected int getPreviousLeapYears(final int isoYear) {
// Formula gets count of leap years, including current, so subtract a year first.
final int previousYear = isoYear - 1;
// If the doomsday offset is -1, then the first year is a leap year.
return (previousYear + leapYearCountOffset + (previousYear / 4) - (previousYear / 100) + (previousYear / 400)) / 7 + (leapYearCountOffset == FIRST_YEAR_LEAP_YEAR_OFFSET ? 1 : 0);
}
お気づきの方もいらっしゃると思いますがleapYearCountOffset
、抽象スーパークラスで(最終変数として)定義されている、を使用します。これはgetPreviousLeapYears()
、スーパークラスコンストラクターから呼び出されます。スーパークラスコンストラクターで式を繰り返したくありません。3/1〜12/31の範囲の日付では異なります。また、インスタンス変数を具象サブクラスに配置したくありません。他の計算にはまだが必要leapYearCountOffset
です。
質問は次のとおりです。leapYearCountOffset
(サブクラス)メソッドがコンストラクターから呼び出されたときの状態はどうなっていますか?それは何らかの形で保証されていますか、それともコンパイラの気まぐれで変更される可能性があるものですか?そして、一体どうやってそれをテストして見つけることができますか?コンパイラーがいくつかのステートメントを自由に再配置できることはすでに知っていますが、それはここで起こりますか?