为什么 Java 中没有 Constant 特性?

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

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

请分享你的想法。

143947 次浏览

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

const的 C + + 语义与 Javafinal非常不同。如果设计者使用了 const,那将会是不必要的混乱。

事实上,const是一个保留字表明,设计人员有实现 const的想法,但他们后来决定反对它; 见 这个封闭的窃听器。原因包括添加对 C + + 样式 const的支持会导致兼容性问题。

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

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

如果您所处的环境支持基于线程的并发性,那么 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仅仅意味着您的代码不能在没有强制转换的情况下更改它,而不是说值是常量。

每次我从繁重的 C + + 编码转向 Java,都要花一点时间来适应 Java 中缺少 常量正确性的情况。如果您不知道,那么在 C + + 中使用 const与仅仅声明常量变量有很大不同。从本质上说,它确保了对象在通过一种叫做 const 指针的特殊指针访问时是不可变的。在 Java 中,在我通常想要返回 const 指针的地方,我会返回一个只包含不应该有副作用的方法的接口类型的引用。不幸的是,语言并没有强制这样做。

维基百科提供了关于这一主题的以下信息:

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

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

  • 只读引用 -Javafinal语义-引用变量本身不能被重新分配指向另一个实例(内存位置) ,但实例本身是可修改的
  • 只能读的引用 -C const指针/引用语义-意味着这个引用不能用来修改实例(例如,不能赋值给实例变量,不能调用可变方法)-只影响引用变量,因此指向同一个实例的非常量引用可以修改实例
  • 不可变物件 -表示不能修改实例本身-适用于实例,因此不允许或不能使用任何非常量引用修改实例
  • 以上几点的组合?
  • 其他人?

为什么或为什么不 const
其次,如果您真的想深入研究一些“赞成”与“反对”的争论,请参阅这个增强请求(RFE)“ bug”下的讨论。这个 RFE 请求一个“只可读的引用”类型的“ const”特性。1999年开放,2005年被孙中山关闭或拒绝,“常量”这个话题引起了激烈的争论:

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

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

  • 可能有混淆的语义,可能被滥用和/或滥用(见上面的 const是什么意思)
  • 可能会重复其他可用的功能(例如,设计一个不可变的类,使用一个不可变的接口)
  • 可能是特性爬行,导致需要其他语义变化,例如支持按值传递对象

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

你可以使用静态 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;

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

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

这并不完全回答 为什么没有常量?而是 怎么做,使您的类成为不可变的。(不幸的是,我还没有足够的声誉作为评论发表在接受的答案)

保证对象不可变的方法是更仔细地将类设计为不可变的。与可变类相比,这需要更多的关注。

这要追溯到 Josh Bloch 的 有效的爪哇 第十五项-尽量减少可变性。如果你还没有读过这本书,拿起一本来读几遍,我保证它会提高你的 “ Java 游戏”

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

直接引用这本书:

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

Bloch 然后描述了如何通过以下5个简单的规则使类不变:

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

对于更多的细节,我强烈建议拿起一本书的副本。