如果存在内部类,则包含美元符号的Java类名无法编译

Grz*_*ski 18 java

我已经定义了以下Java类:

mac-grek:javajunk grek$ cat A\$B.java
class A$B {}
mac-grek:javajunk grek$ cat A.java
public class A {
  public static class B {}
}
mac-grek:javajunk grek$ cat Main.java 
public class Main {

  public static void main(String[] args) {
    System.out.println(A.B.class.getName());
    System.out.println(A$B.class.getName());
  }

}
Run Code Online (Sandbox Code Playgroud)

当我尝试编译它们时,我得到以下错误:

mac-grek:javajunk grek$ javac 'A$B.java' A.java Main.java
A.java:2: duplicate class: A.B
  public static class B {}
                ^
Main.java:4: cannot find symbol
symbol  : class B
location: class A
    System.out.println(A.B.class.getName());
                        ^
Main.java:5: cannot find symbol
symbol  : class A$B
location: class Main
    System.out.println(A$B.class.getName());
                       ^
3 errors
Run Code Online (Sandbox Code Playgroud)

如果我删除A.java文件并System.out.println(A.B.class.getName());Main.java所有编译:

mac-grek:javajunk grek$ cat A\$B.java 
class A$B {}
mac-grek:javajunk grek$ cat Main.java 
public class Main {

  public static void main(String[] args) {
    System.out.println(A$B.class.getName());
  }

}
mac-grek:javajunk grek$ javac A\$B.java Main.java
mac-grek:javajunk grek$ 
Run Code Online (Sandbox Code Playgroud)

所以Java允许我定义一个包含美元符号的类.我该如何编译原始示例?

JB *_*zet 34

您有名称冲突,因为您定义了一个顶级类A $ B,其名称与A类的静态内部类B的生成名称相同.由于您同时具有这两个类,因此编译器无法解决冲突.

JLS说:

$字符只能用于机械生成的源代码,或者很少用于访问遗留系统上预先存在的名称.

既然你决定不尊重这条规则,你就被javac咬了.我只想将A $ B重命名为其他东西.


Ste*_*n C 12

这个规则很模糊.

我不同意.对我而言,它说"不要这样做......除非你知道你在做什么".它没有说明原因,但它不需要.实际上,它无法完全解释为什么,因为'$'标识符中的某些用法可能来自第三方软件.

为什么javac会关心我的代码是来自某个生成器还是手写?

它不"关心".但另一方面,如果您选择忽略JLS建议,它会假设您知道自己在做什么.

关键是编写生成器的人应该知道内部类的二进制类名称是使用该'$'字符表示的.其他人应该只遵循JLS中的建议.

Java语言规范没有说明JVM如何使用的原因'$'是"关注点分离".从JLS的角度来看,这只是一个实现细节.实际上,可以想象有人会为虚拟机平台实现Java语言,以不同方式处理内部类.


我想知道在哪些情况下我可以在我的课程名称中使用$.

最终无法回答这个问题.它是不可能的,这可能是一件好事; 见下文.

JLS应该非常精确和正式,在解释它的陈述时不应该提到读者的心理状态.

  1. 在某些方面,JLS的正式和精确是不好的.这是其中之一.例如,如果你遵循规则X,Y和Z,他们宣称'$'可以安全地使用,这将限制他们在未来版本的Java中使用'$'.更改有关哪些标识符可行的规则可能会导致主要的源代码兼容性问题.

    (这个原则适用的其他领域是内存模型和垃圾收集的语义.)

  2. JLS不涉及您的精神状态.那是我的话.