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

2022-09-03 01:00:10

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

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

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

class ClassName{}

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

答案 1

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

ClassName ClassName = new ClassName();
    1         2               3

它可以看到 1 是类型名称应该位于的位置,因此它知道你指的是类。然后,2 是变量名称的预期位置,因此它知道这应该是变量的名称。3 在带有括号的关键字之后,因此它必须是类的名称。new

System.out.println( ClassName );

在本例中,是在参数传递的上下文中。类型名称不能作为参数传递,因此必须表示变量的名称。ClassName

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

System.out.println( ClassName.class );

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

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

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

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

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


答案 2

编译器如何区分“类名”

因为有两个组件:变量类型和变量名称。声明类型的变量 。类型总是排在第一位。类不是一等对象(意味着您不能对类的引用),除非您进入反射(使用属性)。ClassNameClassName.class

因此,在打印语句中:

System.out.println(ClassName);

这只能是变量。 获取一个对象引用,并且您有一个由名为 的变量引用的对象,因此编译器可以解析它。System.out.printlnClassName

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

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规范中)处理它。可能是以下之一:

  1. 不允许静态方法和实例方法具有相同的名称。
  2. 允许它,并且在编译时解析引用时,首选实例方法。
  3. 允许它,并且在编译时解析引用时,首选静态方法。

如果最后2个中的任何一个,我想编译器警告将被记录。

现在撇开编译器问题不谈,代码的唯一另一个消费者是人类。编译器可能能够依靠规范来保证基本原理行为,但人类不能。我们很容易感到困惑。我对此最好的建议很简单,不要这样做!

绝对没有理由将变量命名为与类完全相同的名称。事实上,我见过的大多数Java编码风格约定都使用lowerCamelCase来命名变量和方法,UpperCamelCase来命名类,所以除非你偏离标准,否则它们没有办法发生冲突。

如果我在我正在处理的项目中遇到这样的代码,我会立即重命名变量,然后再执行任何其他操作。

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

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