150

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

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

请分享你的想法。

4

8 回答 8

151

每次我从繁重的 C++ 编码转到 Java 时,我都需要一些时间来适应 Java 中缺乏const 正确性的问题。const如果您不知道的话,C++ 中的这种用法与仅声明常量变量有很大不同。本质上,它确保当通过一种称为 const 指针的特殊指针访问时对象是不可变的。在 Java 中,在我通常想要返回 const 指针的地方,我改为返回具有接口类型的引用仅包含不应有副作用的方法。不幸的是,这不是由语言强制执行的。

维基百科提供了有关该主题的以下信息:

有趣的是,Java 语言规范将 const 视为保留关键字——即不能用作变量标识符的关键字——但没有为其分配任何语义。人们认为保留关键字是为了允许对 Java 语言进行扩展,以包括 C++ 风格的 const 方法和指向 const 类型的指针。Java Community Process 中用于在 Java 中实现 const 正确性的增强请求票已于 2005 年关闭,这意味着 const 正确性可能永远不会进入官方 Java 规范。

于 2010-04-29T08:49:57.073 回答
85

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

  • 只读引用- Javafinal语义 - 引用变量本身不能重新分配以指向另一个实例(内存位置),但实例本身是可修改的
  • 只读引用- Cconst指针/引用语义 - 意味着此引用不能用于修改实例(例如,不能分配给实例变量,不能调用可变方法) - 仅影响引用变量,因此指向同一个实例可以修改实例
  • 不可变对象- 意味着不能修改实例本身 - 适用于实例,因此不允许或不能使用任何非常量引用来修改实例
  • 以上的一些组合
  • 别人

为什么或为什么不const
其次,如果您真的想深入研究一些“赞成”与“反对”的论点,请参阅此增强请求(RFE)“错误”下的讨论。此 RFE 请求“只读参考”类型“const”功能。1999 年开放,然后在 2005 年被 Sun 关闭/拒绝,“const”话题引起了激烈的争论:

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

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

  • 可能有可能被误用和/或滥用的令人困惑的语义(请参阅上面的含义const
  • 可能会复制其他可用的功能(例如设计不可变类,使用不可变接口)
  • 可能是特性蠕变,导致需要其他语义更改,例如支持按值传递对象

在有人试图争论这些是好是坏的理由之前,请注意这些不是我的理由。它们只是我从浏览 RFE 讨论中收集到的一些原因的“要点”。我自己不一定同意他们的观点——我只是想说明为什么有些人(不是我)可能觉得const关键字可能不是一个好主意。就个人而言,我希望以明确的方式将更多“const”语义引入语言。

于 2010-04-29T09:44:29.007 回答
8

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

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

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

由于 Java 从一开始就被设计为支持线程和锁并发,所以它并没有因为重载该术语以具有所具有的语义而增加混乱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。

虽然x标记为const,但作为一个非常量别名被创建,x它不是一个常量。并非每个编译器都需要volatile这种行为(尽管每个编译器都允许内联常量)

对于更复杂的系统,您会在不使用 的情况下获得 const/non-const 别名const_cast,因此养成认为 const 意味着某些东西不会改变的习惯变得越来越危险。const仅意味着您的代码在没有强制转换的情况下无法更改它,而不是该值是恒定的。

于 2010-04-29T08:38:13.153 回答
6

这是一个有点老的问题,但我想我无论如何都会贡献我的 2 美分,因为今天这个话题出现在对话中。

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

保证对象不变性的方法是更仔细地设计您的类以使其不可变。这比可变类需要更多的关注。

这可以追溯到 Josh Bloch 的Effective Java Item 15 - Minimize Mutability。如果你还没有读过这本书,那就拿起一本读几遍,我保证它会成为你比喻中的“java 游戏”

在第 15 项中,布洛赫建议您应该限制类的可变性以确保对象的状态。

直接引用这本书:

不可变类只是一个实例不能被修改的类。每个实例中包含的所有信息都是在创建时提供的,并且在对象的生命周期内是固定的。Java 平台库包含许多不可变的类,包括 String、装箱的原始类以及 BigInteger 和 BigDecimal。这有很多很好的理由:不可变类比可变类更容易设计、实现和使用。它们更不容易出错并且更安全。

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

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

有关更多详细信息,我强烈建议您拿起这本书的副本。

于 2016-06-07T19:36:02.050 回答
3

的 C++ 语义const与 Java 非常不同final。如果设计师使用const了它,那将会造成不必要的混乱。

这是一个保留字的事实const表明设计者有实现的想法const,但他们后来决定反对它;看到这个关闭的错误。所述原因包括添加对 C++ 样式的支持const会导致兼容性问题。

于 2010-04-29T08:34:27.563 回答
-1

您可以使用 static final 创建类似于 Const 的东西,我过去曾使用过它。

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;
于 2013-04-13T16:24:43.637 回答
-1

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

于 2016-03-07T02:14:52.187 回答
-2

有两种定义常量的方法 -conststatic final,具有完全相同的语义。此外static final,更好地描述了行为const

于 2010-04-29T08:29:07.137 回答