Calendarクラスで、なぜgetメソッドが必要なのか


Java初心者です。結論は出ていない?ですが、一応メモのために、、

はじめに

Calendarクラスを使っててふと疑問に思ったことがありました。

getメソッドていらなくないか?

Calendarクラスには、年、月、日、曜日などを取り出したり、代入することができるgetterメソッドやsetterメソッドが存在します。
例えば、現在の年を取得したいときは、

import java.util.*;
class CalendarTest {
    public static void main(String args[])
    {
        Calendar cld = Calendar.getInstance();
        System.out.println("YEAR getterメソッド→"+cld.get(cld.YEAR));
    }
}

とgetterメソッドを利用することで、可能となります。

出力
YEAR getterメソッド→2019

ここで、疑問に思ったことがあります。
cld.YEARを呼び出せばよくないか?と。APIリファレンスを見てみても、フィールドYEARのアクセス制御レベルはpublicとなっているため、呼び出しは可能ですし(publicでないと上のcld.get(cld.YEAR)も使えなさそうだが)。
何はともあれ、確認してみます。

import java.util.*;
class CalendarTest {
    public static void main(String args[])
    {
        Calendar cld = Calendar.getInstance();
        System.out.println("YEAR getterメソッド→"+cld.get(cld.YEAR)+",フィールド→"+cld.YEAR);
    }
}
出力
YEAR getterメソッド→2019,フィールド→1

んー、?
YEARフィールドには2019ではなく、1という整数が入っているみたいです。
いろいろ憶測ができそうですがいろいろを確認してみます。

import java.util.*;
class CalendarTest {
    public static void main(String args[])
    {
        Calendar cld = Calendar.getInstance();
        for(int i = 2015; i<2020 ;i++){
            cld.set(Calendar.YEAR,i);
            System.out.println("YEAR("+i+") getterメソッド→"+cld.get(cld.YEAR)+",フィールド→"+cld.YEAR);
        }
    }
}
出力
YEAR(2015) getterメソッド→2015,フィールド→1
YEAR(2016) getterメソッド→2016,フィールド→1
YEAR(2017) getterメソッド→2017,フィールド→1
YEAR(2018) getterメソッド→2018,フィールド→1
YEAR(2019) getterメソッド→2019,フィールド→1

なるほど、フィールドYEARはつねに1という整数を持っているみたいです。
ということで、他のフィールドも確認してみたところ、フィールドMONTHは常に2、フィールドDAY_OF_MONTHは常に5であることが判明しました。

もしや、、と思いAPIリファレンスを確認してみたところ、、、
やはり、それぞれのフィールドはfinal型として、定数宣言されていました。確認不足、、

Calendarクラスの中身を覗いてみた

とりあえずここで、タイトルの通りgetメソッドを使用する必要があることがわかりました。定数宣言されているフィールドは通し番号的なものでしょうか(ちゃんと調べろ

それではgetterメソッドはフィールドではなく何を返しているのでしょうか。
Calendarクラスの内部を確認してみました。
getterメソッドとsetterメソッドはこんな感じになっていました。

Calendar.java
class Calendar {
    public int get(int field)
    {
        complete();
        return internalGet(field);
    }

    protected final int internalGet(int field)
    {
        return fields[field];
    }

    final void internalSet(int field, int value)
    {
        fields[field] = value;
    }

    public void set(int field, int value)
    {
        if (areFieldsSet && !areAllFieldsSet) {
            computeFields();
        }
        internalSet(field, value);
        isTimeSet = false;
        areFieldsSet = false;
        isSet[field] = true;
        stamp[field] = nextStamp++;
        if (nextStamp == Integer.MAX_VALUE) {
            adjustStamp();
        }
    }
}

細かい部分は無視すると、fieldsという配列の添え字(インデックス)としてYEARなどの定数フィールドがあり、フィールドによって特定された要素に値を代入したり取り出したりしてる感じです。

感想

普通に、それぞれのフィールドに値を入れたり(public int YEAR = 2001のような感じ)してもよくないか?という気持ちは払拭できませんでした。

getterメソッド、setterメソッドなどがあることによる利点はどこにあるのだろうか、よくわからなくなってきました。(結局カプセル化とか、オブジェクト指向とかを理解できてない。

ただ、それぞれがバラバラに要素を持っているのではなく、一つの配列に{[年],[月],[日],…}のようにまとまって入っていることは、扱いやすそうで良いなと感じました^^

Javaの勉強、仕方も分からずなかなか捗らない、、