为什么Java中的变量名不能与关键字同名?

为什么Java中的变量名不能与关键字同名?,java,parsing,syntax,compiler-construction,Java,Parsing,Syntax,Compiler Construction,在我所知道的大多数编程语言中,不能声明名称也是关键字的变量 例如,在Java中: public class SomeClass { Class<?> clazz = Integer.class; // OK. Class<?> class = Integer.class; // Compilation error. } 公共类SomeClass { Class clazz=Integer.Class;//确定。 Class=Integer.Class;/

在我所知道的大多数编程语言中,不能声明名称也是关键字的变量

例如,在Java中:

public class SomeClass
{
    Class<?> clazz = Integer.class; // OK.
    Class<?> class = Integer.class; // Compilation error.
}
公共类SomeClass
{
Class clazz=Integer.Class;//确定。
Class=Integer.Class;//编译错误。
}
但是很容易弄清楚什么是什么。阅读它的人不会混淆变量名和类声明,编译器也不会混淆它

如果我们谈论Java编程语言的话,变量名如“for”、“extends”、“goto”或其他任何名称也是一样的


我们有这个限制的原因是什么?

它允许词法分析器在不必消除上下文歧义的情况下对符号进行分类-这反过来又允许根据语法规则解析语言,而不需要了解编译过程的其他(“更高”)部分,包括类型分析

作为一个并发症(和歧义)的例子,删除这样的区别会增加解析,请考虑以下几点。在标准的Java规则下,它声明并分配一个变量——对于如何解析它没有任何歧义

final Foo x = 2;   // roughly: <keyword> <identifier> <identifier> = <value>
但如果final是“final type”,则读数可能是:

final Foo = 2;     // hypothetical: <identifier> <identifier> = <value>
final Foo=2;//假设:=
对来源的哪种解释是正确的

由于单独编译,Java使得这个问题更难回答。在命名空间中添加(或意外导入)新的“final type”是否应该改变代码的解析方式?报告一个未解析的符号是一回事——根据这种解析改变语法的解析方式是另一回事

这类问题只是通过明确区分保留字来绕过


可以说,可以使用特殊的产品动态地更改关键字的识别(某些语言允许可控的运算符优先级),但主流语言中没有这样做,Java肯定不支持这样做。至少,它需要额外的语法,并增加了系统的复杂性,但没有带来足够的好处

我见过的解决这类问题的最“干净”的方法是C#,它允许在保留字前面加一个前缀,并删除特殊含义,例如
class@class{float@int=2;}
——尽管这样做应该很少,而且

现在,Java中保留的一些单词可以“仅在上下文中保留”,例如
extends
。这在SQL中一直可见;有保留字(例如,
超过
),然后是在给定语句结构中只有特殊意义的字(例如,
行号
)。但更容易说保留就是保留,去选别的吧

除了像LISP方言这样一种非常容易解析的语言,它有效地将每一个裸词都视为标识符之外,关键字以及与标识符的区别在语言语法中非常普遍

我们有这个限制的原因是什么

一般来说,有两个原因:

  • 正如你在你的问题中所指出的那样:这对人类读者来说是非常令人困惑的。一种设计混乱的编程语言,作为一种实用的编程语言,不会有太大的吸引力

  • 如果标识符可以与关键字相同,那么编写该语言的正式语法就困难得多。(当然,带有消歧规则的语法不能用BNF/EBNF或类似的语言表示。)这意味着为这种语言编写解析器要复杂得多

无论如何,尽管这两个原因都不是完全的“止步符”,但它们足以导致大多数尝试新编程语言设计/实现的人拒绝这个想法

这当然是你(几乎)从未见过关键字可以用作标识符的语言的真正原因。编程语言设计师几乎总是拒绝这个想法

(在Java的例子中,人们有意识地努力使使用C语言的人能够访问语法。C不支持这一点。如果他们正在寻找,这可能是第三个原因。)


主流编程语言中有一个有趣的(半)反例。在FORTRAN的早期版本中,标识符中的空格并不重要。因此

    I J = 1

意思是一样的。这很酷(取决于你的“品味”…)。但比较这两个:

    DO 20 I = 10, 1, -2

    DO 20 I = 10

一个是赋值,另一个是“DO循环”语句。作为一名读者,你会注意到这一点吗?

你说得不太对。关键字是在语言语法中有意义的词,保留词是不允许用作标识符的词。在Java中,它们基本上是相同的,但是'true'和'goto'是保留字,而不是关键字('true'是一个文本,不使用'goto')

在语言中保留关键字的主要原因是为了简化语法分析和避免歧义。例如,如果
return
可能是一种方法,这意味着什么

return(1);

在我看来,Java已经走得太远了。有一些关键词只有在没有歧义的特定语境中才有意义。也许避免读者产生混淆是有好处的,但我把它归因于编译作者的习惯。还有一些其他语言的关键词和/或保留词要少得多,而且效果很好。

评论不错,听起来像是一个答案。那么编译速度是不是原因呢?它只是一种语言设计选择。Java采用了明确、清晰的语法,因为这使代码更易于阅读。当然,其他语言以可读性为代价做出了不同的选择,不仅仅是速度。它简化了编译器代码并提高了可靠性。此外,必须存在病毒感染的病例
    DO 20 I = 10
return(1);