为什么Java中没有常量特性?

我试图找出Java中的常量背后的原因我已经了解到,Java允许我们通过使用final关键字来声明常量。

我的问题是为什么没有引入一个常量( const )function。 由于很多人说它来自C ++,所以在C ++中我们有const关键字。

请分享你的想法。

每当我从繁重的C ++编码转换到Java时,我都需要一点时间来适应Java中缺乏const正确性的情况。 在C ++中这种用法与仅仅声明常量variables大不相同,如果你不知道的话。 从本质上讲,它确保了一个对象在通过一个称为const-pointer的特定types的指针进行访问时是不可变的。当在Java中,在我通常要返回一个const指针的地方,我反而返回一个带有接口types的引用只包含不应有副作用的方法。 不幸的是,这不是由语言强制执行。

维基百科提供关于这个问题的以下信息:

有趣的是,Java语言规范将const视为一个保留关键字 – 即不能用作variables标识符的一个保留关键字,但是没有赋予它任何的语义。 据认为,关键字的保留发生,以允许扩展Java语言,包括C ++风格的常量方法和指向常量types的指针。 Java Community Process中用于实现const正确性的Java中的增强请求票据在2005年closures,这意味着const正确性可能永远不会进入官方Java规范。

什么是const意思
首先,认识到“const”关键字的语义对不同的人意味着不同的事物:

  • 只读引用 – Java final语义 – 引用variables本身不能被重新分配指向另一个实例(内存位置),但实例本身是可修改的
  • 只读引用 – C const指针/引用语义 – 意味着这个引用不能用于修改实例(例如不能分配给实例variables,不能调用可变方法) – 只影响引用variables,所以指向同一个实例可以修改实例
  • 不可变的对象 – 意味着实例本身不能被修改 – 适用于实例,所以任何非const引用将不被允许或不能被用来修改实例
  • 上面的一些组合
  • 别人

为什么或为什么不是const
其次,如果你真的想挖掘一些“pro”和“con”的论点,请参阅这个增强请求(RFE)“bug”的讨论。 此RFE请求“只读参考”types“常量”function。 在1999年开放,然后在2005年closures/被孙拒绝,“常量”议题激烈辩论:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070

虽然双方都有很多好的论点,但是一些经常被引用(但不一定是引人注目或者明确的)反对const理由包括:

  • 可能会混淆可能被滥用和/或滥用的语义(请参阅上面的const是什么意思
  • 可能会复制其他可用的function(例如,使用不可变的接口devise一个不可变的类)
  • 可能是蠕变特性,导致需要其他语义变化,如支持按值传递对象

在任何人试图辩论我是否是好的或坏的原因之前,请注意这些不是我的原因 。 他们仅仅是我从掠夺RFE讨论中收集到的一些原因的“主旨”。 我不一定同意他们自己 – 我只是想引用为什么有些人(而不是我)可能会觉得const关键字可能不是一个好主意。 就个人而言,我更愿意以更明确的方式将更多的“常量”语义引入到语言中。

Const没有被使用,因为你不能强制Java中的值是常量。 因此,这将是一个误导。 最后可以说(虽然主观上)是一个更好的名字,因为它表明variables是最后的参考(它不能被重新分配)。

另外,const是Java中一个保留但未使用的关键字。

在C ++中的const并不意味着一个值是一个常量。

C ++中的const意味着合同的客户承诺不改变其价值。

如果您处于支持基于线程的并发性的环境中, constexpression式的值是否更改变得更加明显。

由于Java从一开始就被devise为支持线程和锁并发,所以它没有通过重载该术语来增加final的语义。

例如:

 #include <iostream> int main () { volatile const int x = 42; std::cout << x << std::endl; *const_cast<int*>(&x) = 7; std::cout << x << std::endl; return 0; } 

输出42然后是7。

尽pipex标记为const ,但是创build非const别名时, x不是常量。 并不是每一个编译器都需要这种行为的volatile (尽pipe每个编译器都可以内联这个常量)

有了更复杂的系统,你可以在不使用const_cast情况下获得const / non-const别名,所以养成一个习惯就是不会改变const的东西变得越来越危险。 const仅仅意味着你的代码不能在没有强制转换的情况下改变它,而不是值不变。

这是一个古老的问题,但是我认为自从今天讨论这个话题以来,我会贡献我的2分钱。

这并不完全回答为什么没有常量? 但是如何让你的类不可变。 (不幸的是,我还没有足够的声誉发布作为评论接受的答案)

保证对象不变的方法是更仔细地devise你的类是不可变的。 这需要比可变类更多的关心。

这可以追溯到Josh Bloch的有效Java 项目15 – 最小化可变性 。 如果你还没有阅读这本书,拿起一个副本,并阅读了几次,我保证它会提高你的比喻“Java游戏”

在第15项中,Blochbuild议你应该限制类的可变性以确保对象的状态。

直接引用这本书:

一个不可变的类只是一个其实例不能被修改的类。 包含在每个实例中的所有信息在创build时提供,并在对象的生命周期中被固定。 Java平台库包含许多不可变的类,包括string,盒装原语类,BigInteger和BigDecimal。 有很多很好的理由:不可变类比可变类更容易devise,实现和使用。 他们不太容易出错,更安全。

然后Bloch描述如何使你的类不可变,遵循5个简单的规则:

  1. 不要提供任何修改对象状态的方法(即setter,aka mutators
  2. 确保类不能被扩展(这意味着将类本身声明为final )。
  3. 使所有的领域final
  4. 使所有的字段private
  5. 确保独占访问任何可变组件。 (通过制作对象的防御副本)

欲了解更多详情,我强烈build议拿起本书的副本。

const的C ++语义与Java final有很大不同。 如果devise师使用了const那将会不必要的混淆。

const是一个保留字的事实表明devise者有实施const想法,但是他们已经决定了这个想法。 看到这个封闭的错误 。 上述原因包括增加对C ++样式const支持会导致兼容性问题。

定义常量有两种方法 – conststatic final ,具有完全相同的语义。 而且, static finalconst更好地描述行为

我听说有一个传言说在Java中使用Enums对游戏性能不利。 我不知道为什么。 Const会performance得更好…

在Java中使用真实生活CONST的例子…只是像这样编码…然后你的switch语句不会抱怨..

 protected static final int cOTHER = 0; protected static final int cRPM = 1; protected static final int cSPEED = 2; protected static final int cTPS = 3; protected int DataItemEnum = 0; public static final int INVALID_PIN = -1; public static final int LED_PIN = 0; 

 switch (this.DataItemEnum) { case cRPM: percent = (Value - 0.001*Min)/(Max - Min); break; default: percent = (Value - Min)/(Max - Min); break } 

有一种方法可以在Java中创build“const”variables,但仅限于特定的类。 只需定义一个具有最终属性的类并将其inheritance。 然后使用你想使用“const”的基类。 同样,如果你需要使用“const”方法,将它们添加到基类。 编译器不会允许你修改它认为是基类的最终方法,但它会读取和调用子类的方法。