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

k2fxgqgv  于 2023-02-11  发布在  Java
关注(0)|答案(8)|浏览(142)

我试图找出Java中常量背后的原因,我了解到Java允许我们使用final关键字声明常量。
我的问题是为什么Java没有引入常量(const)特性,因为很多人说它来自C++,所以在C++中我们有const关键字。
请分享你的想法。

h22fl7wq

h22fl7wq1#

每次我从繁重的C代码转到Java,我都要花一点时间来适应Java中const-correctness的缺失。如果你不知道的话,在C中使用const与仅仅声明常量变量有很大的不同。本质上,它确保了一个对象在通过一种称为常量指针的特殊指针访问时是不可变的。在Java中,在我通常想返回常量指针的地方,我返回了一个接口类型的引用,该接口类型只包含不应该有副作用的方法。不幸的是,语言没有强制执行这一点。
维基百科提供了以下关于该主题的信息:
有趣的是,Java语言规范将const视为保留关键字-即,一个不能用作变量标识符的关键字,但没有赋予它任何语义。2人们认为保留这个关键字是为了允许Java语言扩展到包括C++风格的常量方法和指向常量类型的指针。在Java社区进程中用于在Java中实现常量正确性的增强请求票在2005年关闭,这意味着常量正确性可能永远不会进入官方Java规范。

t9aqgxwy

t9aqgxwy2#

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

    • 只读引用 * - Java final语义-引用变量本身不能被重新分配以指向另一个示例(内存位置),但示例本身是可修改的
    • 只读引用 * - C const指针/引用语义-表示此引用不能用于修改示例(例如,不能赋值给示例变量,不能调用可变方法)-仅影响引用变量,因此指向同一示例的非常数引用可以修改示例
  • immutable object -表示示例本身不能修改-适用于示例,因此不允许任何非常数引用,也不能使用任何非常数引用来修改示例
    • 以上各项的某种组合 *?
    • 其他人 *?
      为什么或为什么不const

第二,如果你真的想深入了解一些“赞成”与“反对”的争论,请看下面这个增强请求(RFE)“bug”下的讨论。这个RFE请求一个“只读引用”类型的“const”特性。1999年开放,然后在2005年被Sun关闭/拒绝,“const”主题引起了激烈的争论:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070
虽然双方都有很多好的论据,但反对const的一些经常被引用的(但不一定是令人信服或明确的)理由包括:

  • 可能具有混淆的语义,可能会被误用和/或滥用(请参见上面的 * const是什么意思 *)
  • 可能复制其他可用的功能(例如,设计不可变类,使用不可变接口)
  • 可能是特征蔓延,导致需要其他语义更改,例如支持按值传递对象

在任何人试图就这些理由是好是坏与我争论之前,请注意,这些“不是我的理由”。它们只是我从RFE讨论中略读到的一些理由的“要点”。我自己并不一定同意它们--我只是想说明为什么有些人(不是我)可能会觉得使用const关键字不是个好主意,就我个人而言,我希望能以一种明确的方式将更多的“const”语义引入到语言中。

7rtdyuoh

7rtdyuoh3#

const在C中并不意味着某个值是常量。
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/nonconst别名,因此养成认为const意味着某些东西不会改变的习惯变得越来越危险。const仅仅意味着您的代码在不进行强制转换的情况下无法改变它,而不是值是常量。

1aaf6o9v

1aaf6o9v4#

这是一个有点老的问题,但我想我会贡献我的2美分,无论如何,因为这个线程出现在今天的谈话。
这并没有确切地回答 * 为什么没有常量?* 而是 * 如何 * 使你的类不可变。(不幸的是,我还没有足够的声誉来作为对公认答案的评论)
保证对象的不变性的方法是更仔细地设计类使其不可变,这比可变类需要更多的注意。
这可以追溯到Josh Bloch的《有效的Java》第15条--最小化可变性。如果你还没有读过这本书,拿起一本读几遍,我保证它会成为你的比喻“java游戏”。
在第15条中,Bloch建议您应该限制类的可变性以确保对象的状态。
直接引用这本书:
一个不可变类就是一个示例不能被修改的类。每个示例中包含的所有信息都是在创建时提供的,并且在对象的生命周期内是固定的。Java平台库包含许多不可变类,包括String、装箱的原语类以及BigInte-格尔和BigDecimal。这样做有很多好的理由:不可变类比可变类更容易设计、实现和使用。它们不容易出错,而且更安全。
Bloch接着描述了如何通过以下5条简单的规则使类不可变:
1.不要提供任何修改对象状态的方法(例如setters,又名 mutators
1.确保类不能被扩展(这意味着将类本身声明为final)。
1.使所有字段为final
1.使所有字段为private
1.确保对任何可变组件的独占访问。(通过创建对象的防御性副本)
欲了解更多细节,我强烈建议拿起一本这本书。

aelbi1ox

aelbi1ox5#

const的C语义与Java final有很大的不同,如果设计者使用const,就会造成不必要的混淆。
const是一个保留字这一事实表明设计者有实现const的想法,但他们后来决定放弃它;所述原因包括添加对C
样式const的支持会导致兼容性问题。

yjghlzjz

yjghlzjz6#

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

eeq64g8w

eeq64g8w7#

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

ix0qys7i8#

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

相关问题