在 Java 中,变量名可以与类名相同

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27877897/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 12:34:08  来源:igfitidea点击:

In Java, the variable name can be same with the classname

javaclasscompiler-construction

提问by Jimmy Zhang

In Java I can declare a variable, whose name is total same with its classname. I think it is a so confusing and strange design.

在 Java 中,我可以声明一个变量,其名称与其类名完全相同。我认为这是一个如此令人困惑和奇怪的设计。

So I have a problem in the code snippet below: how can the compiler distinguish the ClassName, it is referenced the variablename or classname?

所以我在下面的代码片段中有一个问题:编译器如何区分ClassName, 它是引用的变量名还是名?

In the running result, the compiler references ClassNameas a variable name.

在运行结果中,编译器ClassName作为变量名引用。

class ClassName{}

public class Test {
    public static void main(String[] args){
        ClassName ClassName = new ClassName();
        System.out.println(ClassName); //ClassName@18fb53f6
    }
}

回答by RealSkeptic

The compiler can tell by context. In the example you have given:

编译器可以通过上下文来判断。在您给出的示例中:

ClassName ClassName = new ClassName();
    1         2               3

It can see that 1is where a type name should be, so it knows you mean the class. Then, 2is where a variable name is expected, so it knows that this should be the name of a variable. And 3is coming after the newkeyword with parentheses, so it must be the name of a class.

它可以看到1是类型名称应在的位置,因此它知道您指的是类。然后,2是需要变量名的地方,所以它知道这应该是变量名。并且3new跟在带括号的关键字之后,所以它必须是一个类的名称。

System.out.println( ClassName );

In this instance, ClassNameis in the context of argument passing. A type name can't be passed as an argument, so you must mean the name of the variable.

在这种情况下,ClassName是在参数传递的上下文中。类型名称不能作为参数传递,因此您必须指的是变量的名称。

To amuse yourself, you can change the print statement to:

为了自娱自乐,您可以将打印语句更改为:

System.out.println( ClassName.class );

Hover your mouse cursor on ClassNameand you'll see that the compiler recognizes this as the name of a class. Then change it to:

将鼠标光标悬停在上面ClassName,您会看到编译器将其识别为类的名称。然后将其更改为:

System.out.println( ClassName.getClass() );

Hover your cursor again, and now you see that it recognizes it as the variable name. That's because .classcan only be applied to a type name, while getClass()can only be applied to an object reference. The result of the print statement would be the same in both cases - but through different mechanisms.

再次将光标悬停,现在您会看到它会将其识别为变量名称。那是因为.class只能应用于类型名称,而getClass()只能应用于对象引用。打印语句的结果在两种情况下都是相同的——但通过不同的机制。

So the compiler has no problem here. But you are right that it's not readable to humans. The convention is that names of variables and methods must start with a lowercase letter, while type names must start with an uppercase letter. Adhering to this convention will ensure that no such readability problems arise.

所以这里编译器没有问题。但你是对的,它对人类不可读。约定是变量和方法的名称必须以小写字母开头,而类型名称必须以大写字母开头。遵守此约定将确保不会出现此类可读性问题。

I can't say exactly why the authors of Java chose not to enforce this convention (that is, give a compiler error if type names started with a lowercase letter or variable/method names started with an uppercase), but I speculate that they didn't want to make anything an actual error unless it would actually cause an ambiguity for the compiler. Compilation errors are supposed to indicate a problem that makes the compiler unable to do its work.

我不能确切地说为什么 Java 的作者选择不强制执行这个约定(也就是说,如果类型名称以小写字母开头或变量/方法名称以大写字母开头,则会出现编译器错误),但我推测他们没有不想使任何实际错误,除非它实际上会导致编译器的歧义。编译错误应该表明存在使编译器无法完成其工作的问题。

回答by Brandon

how can the compiler distinguish the "Classname"

编译器如何区分“类名”

Because there are two components: The variable type and variable name. You declare a variable ClassNameof type ClassName. Type always goes first. Classes are not first-class objects (meaning you can't have a reference to a class) unless you get into reflections (with the .classproperty).

因为有两个组成部分:变量类型和变量名称。您声明了一个ClassName类型为 的变量ClassName。类型永远是第一位的。类不是一流的对象(意味着您不能引用类),除非您进入反射(使用.class属性)。

Therefore, in the print statement:

因此,在打印语句中:

System.out.println(ClassName);

That can only be the variable. System.out.printlntakes an object reference, and you have an object referred to by a variable named ClassName, therefore the compiler can resolve it.

那只能是变量。 System.out.println接受一个对象引用,并且您有一个由名为 的变量引用的对象ClassName,因此编译器可以解析它。

The only case I can think that is ambiguous to the compiler is if the variable refers to an object which has an instance method of the same name as a static method on the class.

我认为对编译器来说不明确的唯一情况是变量是否引用了一个对象,该对象具有与类上的静态方法同名的实例方法。

public class SomeClass {
    public void aMethod() {
        System.out.println("A method!");
    }

    public static void aMethod() {
        System.out.println("Static version!");
    }
}

public class TestClass {
    public static void main (String[] args) {
        SomeClass SomeClass = new SomeClass();
        SomeClass.aMethod();  // does this call the instance method or the static method?
    }
}

I am sure the compiler will detect the ambiguity and handle it in some specified manner (in the Java spec). Probably one of:

我确信编译器会检测歧义并以某种指定的方式处理它(在 Java 规范中)。可能是其中之一:

  1. Don't allow a static and instance method to have the same name.
  2. Allow it, and when resolving the reference at compile-time, prefer the instance method.
  3. Allow it, and when resolving the reference at compile-time, prefer the static method.
  1. 不允许静态方法和实例方法具有相同的名称。
  2. 允许它,并且在编译时解析引用时,更喜欢实例方法。
  3. 允许它,并且在编译时解析引用时,更喜欢静态方法。

If either of the last 2, I imagine a compiler warning would be logged.

如果是最后两个中的任何一个,我想会记录编译器警告。

Now that the compiler question is aside, the only other consumer of the code is human beings. Compilers may be able to rely on specifications to guarantee rationale behavior, but humans can't. We get confused easily. The best advice I have for that is simply, don't do it!

既然编译器问题已经搁置一旁,那么代码的唯一其他消费者就是人类。编译器可能能够依靠规范来保证合理的行为,但人类不能。我们很容易混淆。我对此的最佳建议很简单,不要这样做!

There is absolutely no reason to name a variable identically to a class. In fact, most Java coding style conventions I have seen use lowerCamelCase to name variables and methods and UpperCamelCase to name classes, so there is no way for them to collide unless you deviated from the standards.

绝对没有理由将变量命名为与类相同的名称。事实上,我见过的大多数 Java 编码风格约定都使用小写字母来命名变量和方法,使用大写字母来命名类,因此除非您偏离标准,否则它们不会发生冲突。

If I encountered code like that in a project I was working on, I would immediately rename the variable before doing anything else.

如果我在我正在处理的项目中遇到这样的代码,我会在做任何其他事情之前立即重命名变量。

For my ambiguous case of an instance and static method of the same name, there just might be a human lesson in there too: don't do it!

对于我的同名实例和静态方法的模棱两可的情况,那里也可能有一个人的教训:不要这样做!

Java has a lot of rules to force you to do things that are logical and make code easy to follow, but at the end of the day, it's still code and you can write any code you want. No language spec or compiler can prevent you from writing confusing code.

Java 有很多规则迫使你做符合逻辑的事情并使代码易于遵循,但归根结底,它仍然是代码,你可以编写任何你想要的代码。没有任何语言规范或编译器可以阻止您编写令人困惑的代码。

回答by hqt

ClassName ClassName = new ClassName();

If you study compiler design course, you will know there is a Lexical Analysis step. At this step, you will write a grammar for your language. for example:

如果您学习编译器设计课程,您就会知道有一个词法分析步骤。在这一步,您将为您的语言编写语法。例如:

ClassName variableName = new ClassName();

So example above, compiler can understand secondClassNameis variable.

所以上面的例子,编译器可以理解第二个ClassName是变量。

When you do something like:

当您执行以下操作时:

ClassName.doSomething();

Java will understand ClassName as variable rather than a class. And this design won't have any limitation. doSomething()can be both static method or just a instance method.

Java 会将 ClassName 理解为变量而不是类。而且这种设计不会有任何限制。doSomething()既可以是静态方法,也可以只是一个实例方法。

If Java understands ClassName here as class, so doSomething()cannot be a instance method. Maybe because this so Java creator has chosen above design: ClassName as a variable.

如果 Java 将这里的 ClassName 理解为类,那么doSomething()就不能是实例方法。可能是因为这个所以 Java 的创造者选择了上面的设计:ClassName 作为一个变量。

But what the problem if a variable name cannotbe same name with their class. so the following example:

但是如果变量名不能与它们的类同名,那会有什么问题。所以下面的例子:

ClassA ClassB = new ClassA();
ClassB.callMethodInClassB();  // should compile error or not ???!!!

The problem still be here. The misleading still exist. So the new design should be:

问题还是出在这里。误导仍然存在。所以新的设计应该是:

No variable name should not has same name with **any** class name.

No variable name should not has same name with **any** class name.

And you will see, this statement makes one language more complicate to understand and not so well-define. From above proofs, I think when you do something such as: A A = new A();understand A as variable is a best way in language design.

你会看到,这种说法使一种语言更难理解,而且定义不明确。从上面的证明,我认为当你做这样的事情时:A A = new A();将 A 理解为变量是语言设计中的最佳方式。

Hope this help :)

希望这有帮助:)