在Java中,变量名可以和类名相同
In Java, the variable name can be same with the classname
在 Java 中我可以声明一个变量,其名称与它的 class 名称完全相同。我认为这是一个非常混乱和奇怪的设计。
所以我在下面的代码片段中遇到了问题:编译器如何区分 ClassName
,它引用了 变量 名称或 class名字?
在 运行 结果中,编译器引用 ClassName
作为变量名。
class ClassName{}
public class Test {
public static void main(String[] args){
ClassName ClassName = new ClassName();
System.out.println(ClassName); //ClassName@18fb53f6
}
}
how can the compiler distinguish the "Classname"
因为有两个组成部分:变量类型和变量名。您声明了一个 ClassName
类型的变量 ClassName
。类型总是第一位的。 类 不是 first-class 对象(这意味着你不能引用 class),除非你进入反射(使用 .class
属性 ).
因此,在打印语句中:
System.out.println(ClassName);
那只能是变数。 System.out.println
采用对象引用,并且您有一个由名为 ClassName
的变量引用的对象,因此编译器可以解析它。
我认为编译器唯一不明确的情况是,如果变量引用一个对象,该对象具有与 class.[=18= 上的静态方法同名的实例方法]
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?
}
}
我相信编译器会检测到歧义并以某种指定的方式处理它(在 Java 规范中)。可能是以下之一:
- 不允许静态方法和实例方法同名。
- 允许,在编译时解析引用时,优先使用实例方法。
- 允许,并且在编译时解析引用时,首选静态方法。
如果是最后两个中的任何一个,我想会记录一个编译器警告。
现在抛开编译器问题,代码的唯一其他消费者就是人类。编译器可能能够依靠规范来保证合理的行为,但人类不能。我们很容易混淆。我对此的最好建议就是,不要这样做!
绝对没有理由将变量命名为与 class 相同的变量。事实上,我见过的大多数 Java 编码风格约定使用 lowerCamelCase 命名变量和方法,使用 UpperCamelCase 命名 classes,所以除非你偏离标准,否则它们不可能发生冲突。
如果我在我正在处理的项目中遇到这样的代码,我会立即重命名该变量,然后再做其他事情。
对于我的同名实例和静态方法的模棱两可的情况,那里可能也有人给我们上了一课:不要这样做!
Java 有很多规则迫使你做符合逻辑的事情并使代码易于遵循,但归根结底,它仍然是代码,你可以编写任何你想要的代码.没有任何语言规范或编译器可以阻止您编写令人困惑的代码。
编译器可以根据上下文判断。在您给出的示例中:
ClassName ClassName = new ClassName();
1 2 3
它可以看到 1 是类型名称应该出现的位置,因此它知道您指的是 class。然后,2 是期望变量名的地方,因此它知道这应该是变量名。而 3 是在带括号的 new
关键字之后,所以它必须是 class.
的名称
System.out.println( ClassName );
在这种情况下,ClassName
处于参数传递的上下文中。类型名称不能作为参数传递,因此您必须指的是变量的名称。
自娱自乐,可以将打印语句改成:
System.out.println( ClassName.class );
将鼠标光标悬停在 ClassName
上,您会看到编译器将其识别为 class 的名称。然后将其更改为:
System.out.println( ClassName.getClass() );
再次将光标悬停,现在您会看到它将其识别为变量名。那是因为 .class
只能应用于类型名称,而 getClass()
只能应用于对象引用。 print 语句的结果在两种情况下都是相同的 - 但通过不同的机制。
所以这里编译器没有问题。但是你是对的,它对人类来说是不可读的。约定是变量和方法的名称必须以小写字母开头,而类型名称必须以大写字母开头。遵守此约定将确保不会出现此类可读性问题。
我不能确切地说出为什么 Java 的作者选择不强制执行此约定(也就是说,如果类型名称以小写字母开头或 variable/method 名称开头,则给出编译器错误大写),但我推测他们不想让任何事情成为实际错误,除非它实际上会导致 编译器 产生歧义。编译错误应该表明存在使编译器无法工作的问题。
ClassName ClassName = new ClassName();
如果学过编译器设计课程,就会知道有一个词法分析步骤。在此步骤中,您将为您的语言编写语法。例如:
ClassName variableName = new ClassName();
所以上面的例子,编译器可以理解second ClassName是可变的
当您执行以下操作时:
ClassName.doSomething();
Java 会将 ClassName 理解为变量而不是 class。而且这种设计不会有任何限制。 doSomething()
可以是静态方法也可以只是实例方法。
如果Java把这里的ClassName理解为class,那么doSomething()
就不能是实例方法。可能是因为这样 Java 创建者选择了上面的设计:ClassName 作为变量。
但是如果变量名 不能 与它们的 class 同名,那会有什么问题呢?所以下面的例子:
ClassA ClassB = new ClassA();
ClassB.callMethodInClassB(); // should compile error or not ???!!!
问题仍然存在。误导依然存在。所以新的设计应该是:
No variable name should not has same name with **any** class name.
你会看到,这种说法让一种语言更难理解,也不太好定义。从上面的证明,我认为当你做这样的事情时:A A = new A();
将 A 理解为变量是语言设计中的最佳方式。
希望对您有所帮助:)
在 Java 中我可以声明一个变量,其名称与它的 class 名称完全相同。我认为这是一个非常混乱和奇怪的设计。
所以我在下面的代码片段中遇到了问题:编译器如何区分 ClassName
,它引用了 变量 名称或 class名字?
在 运行 结果中,编译器引用 ClassName
作为变量名。
class ClassName{}
public class Test {
public static void main(String[] args){
ClassName ClassName = new ClassName();
System.out.println(ClassName); //ClassName@18fb53f6
}
}
how can the compiler distinguish the "Classname"
因为有两个组成部分:变量类型和变量名。您声明了一个 ClassName
类型的变量 ClassName
。类型总是第一位的。 类 不是 first-class 对象(这意味着你不能引用 class),除非你进入反射(使用 .class
属性 ).
因此,在打印语句中:
System.out.println(ClassName);
那只能是变数。 System.out.println
采用对象引用,并且您有一个由名为 ClassName
的变量引用的对象,因此编译器可以解析它。
我认为编译器唯一不明确的情况是,如果变量引用一个对象,该对象具有与 class.[=18= 上的静态方法同名的实例方法]
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?
}
}
我相信编译器会检测到歧义并以某种指定的方式处理它(在 Java 规范中)。可能是以下之一:
- 不允许静态方法和实例方法同名。
- 允许,在编译时解析引用时,优先使用实例方法。
- 允许,并且在编译时解析引用时,首选静态方法。
如果是最后两个中的任何一个,我想会记录一个编译器警告。
现在抛开编译器问题,代码的唯一其他消费者就是人类。编译器可能能够依靠规范来保证合理的行为,但人类不能。我们很容易混淆。我对此的最好建议就是,不要这样做!
绝对没有理由将变量命名为与 class 相同的变量。事实上,我见过的大多数 Java 编码风格约定使用 lowerCamelCase 命名变量和方法,使用 UpperCamelCase 命名 classes,所以除非你偏离标准,否则它们不可能发生冲突。
如果我在我正在处理的项目中遇到这样的代码,我会立即重命名该变量,然后再做其他事情。
对于我的同名实例和静态方法的模棱两可的情况,那里可能也有人给我们上了一课:不要这样做!
Java 有很多规则迫使你做符合逻辑的事情并使代码易于遵循,但归根结底,它仍然是代码,你可以编写任何你想要的代码.没有任何语言规范或编译器可以阻止您编写令人困惑的代码。
编译器可以根据上下文判断。在您给出的示例中:
ClassName ClassName = new ClassName();
1 2 3
它可以看到 1 是类型名称应该出现的位置,因此它知道您指的是 class。然后,2 是期望变量名的地方,因此它知道这应该是变量名。而 3 是在带括号的 new
关键字之后,所以它必须是 class.
System.out.println( ClassName );
在这种情况下,ClassName
处于参数传递的上下文中。类型名称不能作为参数传递,因此您必须指的是变量的名称。
自娱自乐,可以将打印语句改成:
System.out.println( ClassName.class );
将鼠标光标悬停在 ClassName
上,您会看到编译器将其识别为 class 的名称。然后将其更改为:
System.out.println( ClassName.getClass() );
再次将光标悬停,现在您会看到它将其识别为变量名。那是因为 .class
只能应用于类型名称,而 getClass()
只能应用于对象引用。 print 语句的结果在两种情况下都是相同的 - 但通过不同的机制。
所以这里编译器没有问题。但是你是对的,它对人类来说是不可读的。约定是变量和方法的名称必须以小写字母开头,而类型名称必须以大写字母开头。遵守此约定将确保不会出现此类可读性问题。
我不能确切地说出为什么 Java 的作者选择不强制执行此约定(也就是说,如果类型名称以小写字母开头或 variable/method 名称开头,则给出编译器错误大写),但我推测他们不想让任何事情成为实际错误,除非它实际上会导致 编译器 产生歧义。编译错误应该表明存在使编译器无法工作的问题。
ClassName ClassName = new ClassName();
如果学过编译器设计课程,就会知道有一个词法分析步骤。在此步骤中,您将为您的语言编写语法。例如:
ClassName variableName = new ClassName();
所以上面的例子,编译器可以理解second ClassName是可变的
当您执行以下操作时:
ClassName.doSomething();
Java 会将 ClassName 理解为变量而不是 class。而且这种设计不会有任何限制。 doSomething()
可以是静态方法也可以只是实例方法。
如果Java把这里的ClassName理解为class,那么doSomething()
就不能是实例方法。可能是因为这样 Java 创建者选择了上面的设计:ClassName 作为变量。
但是如果变量名 不能 与它们的 class 同名,那会有什么问题呢?所以下面的例子:
ClassA ClassB = new ClassA();
ClassB.callMethodInClassB(); // should compile error or not ???!!!
问题仍然存在。误导依然存在。所以新的设计应该是:
No variable name should not has same name with **any** class name.
你会看到,这种说法让一种语言更难理解,也不太好定义。从上面的证明,我认为当你做这样的事情时:A A = new A();
将 A 理解为变量是语言设计中的最佳方式。
希望对您有所帮助:)