Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中,变量名可以与类名相同_Java_Class_Compiler Construction - Fatal编程技术网

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

在Java中,变量名可以与类名相同,java,class,compiler-construction,Java,Class,Compiler Construction,在Java中,我可以声明一个变量,其名称与其类名完全相同。我认为这是一个如此令人困惑和奇怪的设计 因此,我在下面的代码片段中遇到了一个问题:编译器如何区分类名,它引用了变量名称或类名称 在运行结果中,编译器引用ClassName作为变量名 class ClassName{} public class Test { public static void main(String[] args){ ClassName ClassName = new ClassName();

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

因此,我在下面的代码片段中遇到了一个问题:编译器如何区分
类名
,它引用了变量名称或名称


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

class ClassName{}

public class Test {
    public static void main(String[] args){
        ClassName ClassName = new ClassName();
        System.out.println(ClassName); //ClassName@18fb53f6
    }
}
编译器如何区分“类名”

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

因此,在print语句中:

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

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

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

  • 不允许静态方法和实例方法具有相同的名称
  • 允许它,并且在编译时解析引用时,首选实例方法
  • 允许它,并且在编译时解析引用时,首选静态方法
  • 如果是最后两个,我想会记录一个编译器警告

    现在,编译器的问题已经被抛在一边,代码的另一个消费者是人类。编译器可以依靠规范来保证基本原理行为,但人类却不能。我们很容易困惑。对此我最好的建议就是,不要这样做

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

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

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


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

    编译器可以根据上下文进行判断。在您给出的示例中:

    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() );
    
    再次将光标悬停,现在可以看到它将其识别为变量名。这是因为
    .class
    只能应用于类型名称,而
    getClass()
    只能应用于对象引用。在这两种情况下,print语句的结果是相同的,但通过不同的机制

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

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

    ClassName ClassName = new ClassName();
    
    若你们学习编译器设计课程,你们会知道有一个词法分析步骤。在这一步中,您将为您的语言编写语法。例如:

    ClassName variableName = new ClassName();
    
    所以在上面的例子中,编译器可以理解第二个类名是变量

    当您执行以下操作时:

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

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

    但是,如果变量名不能与它们的类同名,那么问题是什么呢。下面是一个例子:

    ClassA ClassB = new ClassA();
    ClassB.callMethodInClassB();  // should compile error or not ???!!!
    
    问题仍然存在。误导仍然存在。因此,新的设计应该是:

    任何变量名称都不应与**任何**类名同名。

    你会看到,这句话使一种语言更难理解,也没有很好的定义。根据以上的证明,我认为当你做一些事情时,比如:
    A A=newa()下方