Calendar クラスは内部的に 2 つのデータ コンテナを持っているようです。
protected long time
protected int[] fields
したがって、 を呼び出すときは、クラスではなくのcal.set(Calendar.WEEK_OF_YEAR, 1)
値を変更します。fields
time
Java API で
保護された抽象ボイドcomputeFields()
現在のミリ秒の時間値 time を fields[] のカレンダー フィールド値に変換します。これにより、カレンダー フィールドの値を、カレンダーに設定された新しい時間と同期させることができます。時間は最初に再計算されません。時間を再計算してからフィールドを再計算するには、complete() メソッドを呼び出します。
computeFields()
Androidの最初のケースでは内部的に呼び出されていないと思います。
私の理論を確認するために、次のコードをテストしました。
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
Calendar cal = Calendar.getInstance();
System.out.println(cal);
System.out.println(sdf.format(cal.getTime()));
cal.set(Calendar.WEEK_OF_YEAR, 1);
System.out.println(cal);
System.out.println(sdf.format(cal.getTime()));
cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(cal);
System.out.println(sdf.format(cal.getTime()));
LogCat:
java.util.GregorianCalendar[ time=1348010308802,areFieldsSet=true ,lenient=true,zone=org.apache.harmony.luni.internal.util.ZoneInfo["null",mRawOffset=0,mUseDst=false],firstDayOfWeek=1 ,minimalDaysInFirstWeek=4,ERA==1,YEAR==2012,MONTH==8, WEEK_OF_YEAR==38 ,WEEK_OF_MONTH==4,DAY_OF_MONTH==18,DAY_OF_YEAR==262, DAY_OF_WEEK==3 ,DAY_OF_WEEK_IN_MONTH==3, AM_PM==1,HOUR==11,HOUR_OF_DAY=23,MINUTE==18,SECOND==28,MILLISECOND==802,ZONE_OFFSET==0,DST_OFFSET==0]
2012.09.18
java.util.GregorianCalendar[ time=?,areFieldsSet=false ,lenient=true,zone=org.apache.harmony.luni.internal.util.ZoneInfo["null",mRawOffset=0,mUseDst=false],firstDayOfWeek=1 ,minimalDaysInFirstWeek=4,ERA==1,YEAR==2012,MONTH==8, WEEK_OF_YEAR==1 ,WEEK_OF_MONTH==4,DAY_OF_MONTH==18,DAY_OF_YEAR==262, DAY_OF_WEEK==3 ,DAY_OF_WEEK_IN_MONTH==3, AM_PM==1,HOUR==11,HOUR_OF_DAY=23,MINUTE==18,SECOND==28,MILLISECOND==802,ZONE_OFFSET==0,DST_OFFSET==0]
2012.01.03
java.util.GregorianCalendar[ time=?,areFieldsSet=false ,lenient=true,zone=org.apache.harmony.luni.internal.util.ZoneInfo["null",mRawOffset=0,mUseDst=false],firstDayOfWeek=1 ,minimalDaysInFirstWeek=4,ERA==1,YEAR==2012,MONTH==8, WEEK_OF_YEAR==1 ,WEEK_OF_MONTH==4,DAY_OF_MONTH==18,DAY_OF_YEAR==262, DAY_OF_WEEK==1 ,DAY_OF_WEEK_IN_MONTH==3, AM_PM==1,HOUR==11,HOUR_OF_DAY=23,MINUTE==18,SECOND==28,MILLISECOND==802,ZONE_OFFSET==0,DST_OFFSET==0]
2012.09.16
上記のように、フィールドの値は変更されますが、内部時間は と表示され?
、 とtime
同期されていないことがわかりますfields
。
time
メソッドを使用して非同期にgetTime()
なり、印刷しました。
Android のカレンダーは、本当に必要になるまで同期を遅らせるように設計されていると思います。
追加した
Java API で次のことがわかりました。
カレンダー フィールドは、set()、add()、roll() の 3 つのメソッドを使用して変更できます。
set(f, value) は、フィールド f を value に変更します。さらに、フィールド f が変更されたことを示す内部メンバー変数を設定します。フィールド f はすぐに変更されますが、get()、getTime()、または getTimeInMillis() への次の呼び出しが行われるまで、カレンダーのミリ秒は再計算されません。したがって、set() を複数回呼び出しても、不要な計算が複数回トリガーされることはありません。set() を使用してフィールドを変更した結果、フィールド、フィールド値、暦体系によっては、他のフィールドも変更される場合があります。さらに、get(f) は、フィールドが再計算された後に必ずしも値を返すとは限りません。詳細は、具体的なカレンダー クラスによって決まります。
追加した
「内容は具体的なカレンダークラスで決まる」が正しいかどうかを確認するために、Dalvik と JDK 6 の実際のコードを調べてみました。
Dalvik のカレンダーでメソッドを設定する
https://www.codeaurora.org/git/projects/qrd-gb-dsds-7225/repository/revisions/cc99b832a941dc8cbb86f1607d04eb87935ddbfd/entry/android/dalvik/libcore/luni/src/main/java/java/util/Calendarから.java
public void set(int field, int value) {
fields[field] = value;
isSet[field] = true;
areFieldsSet = isTimeSet = false;
if (field > MONTH && field < AM_PM) {
lastDateFieldSet = field;
}
if (field == HOUR || field == HOUR_OF_DAY) {
lastTimeFieldSet = field;
}
if (field == AM_PM) {
lastTimeFieldSet = HOUR;
}
}
JDK 6 のカレンダーの set メソッド
public void set(int field, int value) {
if (isLenient() && areFieldsSet && !areAllFieldsSet) {
computeFields();
}
internalSet(field, value);
isTimeSet = false;
areFieldsSet = false;
isSet[field] = true;
stamp[field] = nextStamp++;
if (nextStamp == Integer.MAX_VALUE) {
adjustStamp();
}
}
特定の実装はかなり異なります。問題の正確な理由を理解するには、両方の実装を詳細に調べる必要があります。