【问题标题】:Confusion about constants in JavaJava中常量的困惑
【发布时间】:2014-11-11 10:41:49
【问题描述】:

我正在学习 java 编程,我对常量有点困惑。从我目前所读到的内容来看,常量是最终的,与变量不同,不能重新分配新值。但是,当我使用 Calender 类时,有 set 方法似乎改变了一个常量字段。例如:

Calendar cal = Calendar.getInstance();
System.out.println("The year is " + cal.get(Calendar.YEAR));
cal.set(Calendar.YEAR, 2001);
System.out.println("The year is " + cal.get(Calendar.YEAR));

如果Calendar.YEAR 字段在Calendar 类中声明为final,那么为什么我可以使用set 方法将其更改为另一个值?

【问题讨论】:

  • 这就是你“获取”常量的方式:Calendar.YEAR。这就是你“设置”它的方式:Calendar.YEAR = 3。试试看它失败了。

标签: java constants


【解决方案1】:

Calendar.YEAR 只是一个常量,表示您要在日历中设置哪个逻辑字段。

目的是避免使用 API

setYear
setDay
setMonth
...

回想起来,我会说这是一个非常糟糕的主意 - 以及 java.util.Calendarjava.util.Date 的其他大部分设计。

所以这个电话:

cal.set(Calendar.YEAR, 2001)

不会更改 Calendar.YEAR 的值...它会更改 Calendar 对象中的一些其他(私有)字段。

【讨论】:

  • 可以说,拥有任何类型的 set 是一个非常糟糕的主意 :)
  • @Unihedron 这是一个坏主意,因为 Java 没有留下一个 date 值类,这在今天被广泛认为是唯一理智的方法。 Calendar 的设计源于小程序的鼎盛时期,并且到处都有 Swing 的指纹:它唯一适用的用例是 GUI 日期控件。在那里,可变性以及 int 键字段是有意义的,并且允许对任何字段进行任意更改,然后重新计算为“规范化”形式。另一个例子是缺少有用的构造函数,这对 GUI 来说很好,但对其他一切都是愚蠢的。
  • @tomasb:正如 Marko 所说,一开始就让它可变是一个坏主意。但是随着时间的推移,整个“领域和一种方法而不是多种方法”已经导致如此许多问题。基本上 java.util.* time API 是个灾区。
  • 另外我们可以争辩说,由于 Calendar.YEAR 是一个 int,我们只能在 Java 支持 Call-by-reference 的情况下更改它的值
  • 这只是表面问题。日期和时间是一个足够疯狂的领域,没有额外的技术怪癖。
【解决方案2】:

实际上calendar.set(blah, blahVal) 并没有更新第一个参数(Calendar.YEAR),它更新了日历内部维护的值, 例如,如果你给cal.set(Calendar.YEAR, 2001) Calendar.YEAR 是一个常量,它是数组的索引。该数组包含指定的值。该值正在急剧更新。

【讨论】:

  • 哦,好吧,这是有道理的。这是您所指的数组Calendar 类中的protected int[] 字段吗?
【解决方案3】:

Calendar.set(Calendar.YEAR, xx) 更改年份的值(对于日历实例),而不是 Calendar.YEAR 的值(which is 1),请参阅javadoc

注意:创建short program 来验证这一点很容易。

【讨论】:

    【解决方案4】:

    Calendar.YEAR 只是一个在Constant Field Values 中定义的int,参见docs

    public static final int YEAR
    

    它没有改变常量字段,这个int定义了应该改变什么字段,见source code

    1196    public void set(int field, int value)
    1197    {
    1198        if (isLenient() && areFieldsSet && !areAllFieldsSet) {
    1199            computeFields();
    1200        }
    1201        internalSet(field, value);
    1202        isTimeSet = false;
    1203        areFieldsSet = false;
    1204        isSet[field] = true;
    1205        stamp[field] = nextStamp++;
    1206        if (nextStamp == Integer.MAX_VALUE) {
    1207            adjustStamp();
    1208        }
    1209    }
    

    查看docs Calendar#set 以更好地了解它的作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-19
      • 1970-01-01
      • 2021-09-27
      • 2012-06-16
      • 1970-01-01
      相关资源
      最近更新 更多