【发布时间】:2011-02-13 17:04:21
【问题描述】:
我试图找出 Java 中常量背后的原因
我了解到Java允许我们使用final关键字来声明常量。
我的问题是为什么 Java 没有引入常量 (const) 功能。由于很多人说它来自C++,所以在C++中我们有const关键字。
请分享你的想法。
【问题讨论】:
-
有是一个
const关键字,但没有底层特征。相应地更正了您的标题和标签。
我试图找出 Java 中常量背后的原因
我了解到Java允许我们使用final关键字来声明常量。
我的问题是为什么 Java 没有引入常量 (const) 功能。由于很多人说它来自C++,所以在C++中我们有const关键字。
请分享你的想法。
【问题讨论】:
const关键字,但没有底层特征。相应地更正了您的标题和标签。
您可以使用 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;
【讨论】:
这是一个有点老的问题,但我想无论如何我都会贡献我的 2 美分,因为今天这个话题出现在对话中。
这并不能完全回答 为什么没有 const? 而是 如何 让你的类不可变。 (不幸的是,我还没有足够的声誉来发布对已接受答案的评论)
保证对象不变性的方法是更仔细地设计你的类以使其不可变。这比可变类需要更多的关注。
这可以追溯到 Josh Bloch 的 Effective Java 第 15 条 - 最小化可变性。如果你还没有读过这本书,请拿起一本读几遍,我保证它会成为你的比喻“java游戏”。
在第 15 条中,布洛赫建议您应该限制类的可变性以确保对象的状态。
直接引用该书:
不可变类只是一个实例不能被修改的类。每个实例中包含的所有信息都是在创建时提供的,并且在对象的生命周期内是固定的。 Java 平台库包含许多不可变的类,包括 String、装箱的原始类以及 BigInteger 和 BigDecimal。这有很多很好的理由:不可变类比可变类更容易设计、实现和使用。它们不易出错且更安全。
然后,Bloch 描述了如何通过以下 5 条简单规则使您的类不可变:
final)。final。private。 如需了解更多详情,我强烈建议您阅读本书。
【讨论】:
有一种方法可以在 Java 中创建“const”变量,但仅限于特定的类。只需定义一个具有最终属性的类并将其子类化。然后在你想使用“const”的地方使用基类。同样,如果您需要使用“const”方法,请将它们添加到基类中。编译器不允许你修改它认为是基类的最终方法,但它会读取和调用子类上的方法。
【讨论】:
const 的 C++ 语义与 Java final 非常不同。如果设计师使用了const,那将会造成不必要的混乱。
const 是保留字这一事实表明设计者有实现const 的想法,但他们后来决定不这样做;见this closed bug。所述原因包括添加对 C++ 样式 const 的支持会导致兼容性问题。
【讨论】:
const 是什么意思
首先,意识到“const”关键字的语义对不同的人意味着不同的东西:
final 语义 - 引用变量本身不能重新分配以指向另一个实例(内存位置),但实例本身是可修改的const 指针/引用语义 - 表示此引用不能用于修改实例(例如,不能分配给实例变量,不能调用可变方法) - 仅影响引用变量,因此指向同一个实例的非常量引用可以修改该实例为什么或为什么不const
其次,如果您真的想深入研究一些“赞成”与“反对”的论点,请参阅此增强请求(RFE)“错误”下的讨论。此 RFE 请求“只读参考”类型“const”功能。 1999 年开放,然后在 2005 年被 Sun 关闭/拒绝,“const”话题引起了激烈的争论:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070
虽然双方都有很多很好的论据,但反对const 的一些经常被引用(但不一定令人信服或明确)的理由包括:
const 是什么意思)在有人试图争论我这些是好是坏的理由之前,请注意这些不是我的理由。它们只是我从浏览 RFE 讨论中收集到的一些原因的“要点”。我自己不一定同意他们的观点——我只是想说明为什么有些人(不是我)可能觉得const 关键字可能不是一个好主意。就个人而言,我希望以明确的方式将更多“const”语义引入语言。
【讨论】:
volatile这么简单好理解吗?还是final?嗯。
C++ 中的const 并不意味着值是常量。
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_cast 的情况下获得 const/non-const 别名,因此养成认为 const 意味着某些东西不会改变的习惯变得越来越危险。 const 仅表示您的代码在没有强制转换的情况下无法更改它,而不是该值是恒定的。
【讨论】:
const 并不意味着值是恒定的。这意味着一个值的客户端被约束不能改变它。在您的示例中,没有别名,因此所有用户都受到相同的约束。一般情况并非如此。 const 影响客户,而不是价值 - 它说你不能改变它,而不是它不会改变。
immutable interface 和immutable object 之类的设计模式是在 Java 中模仿 const 的另一种方式(可通过强制转换和反射击败)。 "True" const 可以用SealedObject 完成,可惜它破坏了我们对象的用例。
outputs 42 then 7是错误的;行为未定义。关键是x 被声明 const(因此,例如,它可以放在只读内存中)。在此示例中,编译器完全忽略分配并打印 42 两次是有效的。如果 x 被声明为 没有 const 并作为 const 引用传递给另一个函数,则 const_cast 是合法的。
每次我从繁重的 C++ 编码转到 Java 时,我都需要一点时间来适应 Java 中 const-correctness 的不足。如果您不知道,C++ 中const 的这种用法与仅声明常量变量有很大不同。本质上,它确保当通过一种称为 const 指针的特殊指针访问时对象是不可变的。在 Java 中,在我通常想要返回 const 指针的地方,我改为返回具有接口类型的引用仅包含不应有副作用的方法。不幸的是,这不是由语言强制执行的。
维基百科提供了有关该主题的以下信息:
有趣的是,Java 语言规范将 const 视为保留关键字——即不能用作变量标识符的关键字——但没有为其分配任何语义。人们认为保留关键字是为了允许对 Java 语言进行扩展,以包括 C++ 风格的 const 方法和指向 const 类型的指针。 Java Community Process 中用于在 Java 中实现 const 正确性的增强请求票已于 2005 年关闭,这意味着 const 正确性可能永远不会进入官方 Java 规范。
【讨论】:
final 类似。
final 方法的工作方式与 C++ const 方法完全不同。
final 关键字在属性或变量上 只是确保属性或变量只分配给一次。仍然可以通过例如调用具有副作用的某些方法来更改此对象的状态。 final 在引用对象而不是指针方面有点类似于 C++ 的堆栈分配,但仅此而已。这当然是 dom0 已经说过的。
final 在 Java 中似乎像 C++ const 用于值类型,但更像是 C++ 非常量 T& 用于引用类型
定义常量的方法有两种——const 和static final,语义完全相同。此外,static final 比const 更好地描述了这种行为
【讨论】:
static(不属于特定实例)和final - 无法更改。