代码之家  ›  专栏  ›  技术社区  ›  gmhk

为什么Java中没有固定的特征?

  •  132
  • gmhk  · 技术社区  · 14 年前

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

    我的问题是为什么Java没有引入一个常数? const 特征。因为很多人说它来自C++,C++中有 康斯特 关键字。

    请分享你的想法。

    8 回复  |  直到 7 年前
        1
  •  134
  •   Gunslinger47    14 年前

    每次我从繁重的C++代码转换到Java,我需要一段时间来适应 const-correctness 在Java中。这种用法 const 在C++中,不同于仅仅声明常数变量,如果你不知道的话。本质上,它确保对象在爪哇中通过特殊类型的指针访问const指针时是不可变的,在我通常想要返回const指针的地方,我用一个只包含不应该有边的方法的接口类型返回引用。影响。不幸的是,这并不是兰戈强制执行的。

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

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

        2
  •  81
  •   Bert F    14 年前

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

    • 只读引用 -爪哇 final 语义-不能重新分配引用变量本身以指向另一个实例(内存位置),但实例本身是可修改的
    • 只读引用 -C 康斯特 指针/引用语义-表示此引用不能用于修改实例(例如,不能分配给实例变量,不能调用可变方法)-仅影响引用变量,因此指向同一实例的非常量引用可以修改实例
    • 不可变对象 -表示无法修改实例本身-应用于实例,因此不允许或无法使用任何非常量引用来修改实例
    • 以上的一些组合 ?
    • 其他 ?

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

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

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

    • 可能有可能被误用和/或滥用的混淆语义(参见 什么? 康斯特 意思是 以上)
    • 可能会复制其他可用的功能(例如,使用不可变接口设计不可变类)
    • 可能是特性爬行,导致需要其他语义更改,例如支持按值传递对象

    在有人想和我争论这些理由是好是坏之前,请注意 不是我的理由 . 它们仅仅是我从浏览rfe讨论中获得的一些原因的“要点”。我不一定同意他们自己-我只是想说明为什么有些人(不是我)可能会觉得 康斯特 关键字可能不是一个好主意。就我个人而言,我希望以一种明确的方式向语言介绍更多的“const”语义。

        3
  •  7
  •   Pete Kirkham    14 年前

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

    康斯特 在C++中,契约的委托人承担不改变其价值的义务。

    是否 康斯特 如果您所处的环境支持基于线程的并发,则表达式更改将变得更加明显。

    由于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 标记为 康斯特 ,创建非常量别名时, X 不是常数。不是每个编译器都需要 volatile 对于这种行为(尽管允许每个编译器内联常量)

    对于更复杂的系统,不使用 const_cast 因此,养成认为const意味着某些事情不会改变的习惯变得越来越危险。 康斯特 仅仅意味着代码不能在没有强制转换的情况下更改它,而不是说值是常量。

        4
  •  5
  •   grego    8 年前

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

    这不完全符合 为什么没有警察? 但是 怎样 使您的类不可变。(不幸的是,我还没有足够的声誉来发表评论,对接受的答案)

    保证对象不可变的方法是更仔细地将类设计为不可变的。这需要比可变类更小心一点。

    这要追溯到乔希·布洛赫的 通用程序设计 第15项-最小化易变性 . 如果你还没读过这本书,就拿起一本再读几遍,我保证这本书会让你想起 “Java游戏” .

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

    直接引用这本书:

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

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

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

    关于更多细节,我强烈建议你买一本书。

        5
  •  3
  •   RustyTheBoyRobot MatCas    11 年前

    C++的语义 const 与Java非常不同 final . 如果设计师使用 康斯特 这将是不必要的混乱。

    事实上 康斯特 是一个保留词,表示设计者有实现的想法 康斯特 ,但他们后来决定反对;看 this closed bug . 说明的原因包括增加对C++风格的支持。 康斯特 会导致兼容性问题。

        6
  •  -1
  •   user1122069    8 年前

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

        7
  •  -2
  •   Bozho    14 年前

    定义常数有两种方法- const static final ,具有完全相同的语义。此外 静态最终 康斯特

        8
  •  -2
  •   koral    10 年前

    我听到一个谣言,使用Java中的枚举对游戏性能是不利的。我不知道为什么。康斯特会表现得更好…

    现实生活中使用爪哇的例子…就这样编码… 然后你的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
    }