2个月前 (12-02)  Java系列 |   抢沙发  21 
文章评分 0 次,平均分 0.0

考虑以下Java类:

public class ClassMembers {
  ;
  
  int field;;;
  
  void method() {} ;;
  
  ;
  ;;
  ;;;
  
  class Inner {}
  
  ;  
}

它包含许多零散的分号。

这是合法的Java代码吗?换句话说,它能编译吗?

让我们学习。

类成员和杂散分号

当您得知前面的示例编译时没有错误时,您可能会也可能不会感到惊讶。

杂散分号是允许的类成员。

一切都在JLS

所有这些都在Java语言规范JLS(https://docs.oracle.com/javase/specs/jls/se21/html/)中定义。

第8.1.7节(https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.1.7)称为“类主体和成员声明”。它定义了以下产品:

ClassBody:
  { {ClassBodyDeclaration} }
  
ClassBodyDeclaration:
  ClassMemberDeclaration
  InstanceInitializer
  StaticInitializer
  ConstructorDeclaration
  
ClassMemberDeclaration:
  FieldDeclaration
  MethodDeclaration
  ClassDeclaration
  InterfaceDeclaration
  ;

它说一个类的主体可能包含零个或多个类主体声明。

允许的类体声明是:

  • 类成员;
  • 实例初始化器;
  • 静态初始化器;
  • 构造函数

反过来,允许的类成员是:

  • 字段;
  • 方法;
  • 类;
  • 接口;
  • 分号字符

因此,分号字符是允许的类“成员”。

然而,他们不是真正的成员。

零散的分号和生成的类文件

虽然源代码中允许使用杂散分号,但它们不会对编译的类文件产生任何影响。

下面的Java类:

public class OnlySemiColons {
  ;
  ;;
  ;;;
}

相当于以下Java类:

public class Empty {}

换句话说,它们的区别仅在于类名。

这是两个类的javap-v输出之间的区别:

1,5c1,5
< Classfile /tmp/blog/OnlySemiColons.class
<   Last modified Feb 10, 2024; size 207 bytes
<   SHA-256 checksum 7ab6fcd28276909c579669b2f0a6401ee9785c1bb1afb3119dcd7fd829907ba2
<   Compiled from "OnlySemiColons.java"
< public class blog.OnlySemiColons
---
> Classfile /tmp/blog/Empty.class
>   Last modified Feb 10, 2024; size 189 bytes
>   SHA-256 checksum b276e6806d458674f9178b351dd486b20943d7bf7b72634545140f03c94c0346
>   Compiled from "Empty.java"
> public class blog.Empty
9c9
<   this_class: #7                          // blog/OnlySemiColons
---
>   this_class: #7                          // blog/Empty
19,20c19,20
<    #7 = Class              #8             // blog/OnlySemiColons
<    #8 = Utf8               blog/OnlySemiColons
---
>    #7 = Class              #8             // blog/Empty
>    #8 = Utf8               blog/Empty
24c24
<   #12 = Utf8               OnlySemiColons.java
---
>   #12 = Utf8               Empty.java
26c26
<   public blog.OnlySemiColons();
---
>   public blog.Empty();
37c37
< SourceFile: "OnlySemiColons.java"
---
> SourceFile: "Empty.java"

因此,除了类的名称之外,它们的类文件的内容是相同的。

顶级声明和零散的分号

以下Java代码编译时没有错误:

public class TopLevel {
};

;;;;

interface Foo {};;

;

record Bar() {};

杂散分号是允许的顶级声明。

一切都在JLS中

再一次,这一切都在Java语言规范中定义。

第7.3节定义了编译单位。

以下是普通编译单元的制作:

OrdinaryCompilationUnit:
  [PackageDeclaration] {ImportDeclaration} {TopLevelClassOrInterfaceDeclaration}

因此,一个普通的编译单元由以下部分组成:

  • 可选的包声明;
  • 零份或多份import
  • 零个或多个顶级类或接口。

因此,空文件是有效的编译单元。它不会生成类文件,但javac会“编译”它而不会出错。

但我离题了。。。

顶层声明稍后在第7.6节(https://docs.oracle.com/javase/specs/jls/se21/html/jls-7.html#jls-7.6)中定义:

TopLevelClassOrInterfaceDeclaration:
  ClassDeclaration
  InterfaceDeclaration
  ;

允许的顶级声明包括:

  • 类声明;
  • 接口声明;
  • 分号字符。

因此,分号字符是允许的顶级声明。

不允许作为包声明

就像以下代码无法编译一样:

public class Foo {}
// does not compile!
package com.example;
class Example {}

以下内容也无法编译:

;;; // does not compile!
package com.example;
class Example {} 

包声明(如果存在)必须是源文件的第一个声明。

不允许作为进口报关单

就像以下代码无法编译一样:

import java.util.ArrayList;
public class Example {}
// does not compile
import java.util.List;
class Util {}

以下内容也无法编译:

import java.util.ArrayList;
;;; // does not compile
import java.util.List;
class Util {}

导入声明之间不能有顶级声明。

但是。。。

另一方面,以下示例编译时没有错误:

;;;
class Stray {}
;;;

public class TopLevelStart {
}

它是未命名包的类,没有导入声明。

因此,在这种情况下,文件可能以顶级声明开头。而且,由于分号是允许的顶级声明,因此文件可以以分号开头。

仅仅因为你不能,并不意味着你应该

以下是JLS第7.6节(https://docs.oracle.com/javase/specs/jls/se21/html/jls-7.html#jls-7.6)的摘录(重点是我的):

在编译单元中类和接口声明级别出现的额外“;”标记对编译单元的含义没有影响。Java编程语言中允许使用任意分号,这只是对习惯在类声明后放置“;”的C++程序员的让步。它们不应该在新的Java代码中使用。

所以它告诉我们两件事。

首先,它暗示了为什么在语言中添加了零散的分号。这样Java的语法对C++程序员来说就很熟悉了。

其次,它明确指出,在新的Java代码中不应使用杂散分号

这不是惯用语,可能会无缘无故地让代码的读者感到困惑。

结论

不要在代码中使用零散的分号。

它们可能是一个有趣的Java琐事。但是,如前所述:

  • 它们不地道;
  • 它们可能会无缘无故地让代码的读者感到困惑。

您可以在这个GitHub中(https://github.com/objectos/blog-examples/tree/main/2024/02/11)找到示例的源代码。

原文链接:https://www.objectos.com.br/blog/stray-semicolons-in-java.html

  
 

除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/2998.html

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册