Skip to content

Latest commit

 

History

History
969 lines (505 loc) · 367 KB

06-名称.md

File metadata and controls

969 lines (505 loc) · 367 KB

第六章 名称

名称用于表示在程序中声明的实体。

声明的实体是包、类类型(标准或枚举)、接口类型(标准或注解类型)、引用类型的成员(类、接口、字段或方法)、类型参数(类、接口、方法或构造器的)、参数(到方法、构造器或异常处理器的)或局部变量。

程序中的名称是简单的、单个标识符的组成,或限定的、用 "." 记号(6.2)分隔的标识符序列的组成。

每个引入名称的声明具有作用域(6.3),其是程序文本的组成部分,在其中,可以通过简单名称引用声明的实体。

限定的名称 N.x 可以用于引用包或引用类型的成员,其中 N 是简单的或限定的名称,x 是标识符。如果 N 命名包,则 x 是该包的成员,其是类或接口类型或子包。如果 N 命名引用类型或引用类型的变量,则 x 命名该类型的成员,其是类、接口、字段或方法。

在确定名称(6.5)的含义时,出现的上下文用于区分具有相同名称的包、类型、变量和方法。

可以在类、接口、方法、字段声明中指定访问控制(6.6),以控制允许访问成员的时机。访问是与作用域不同的概念。访问指定程序文本中声明的实体可以通过限定的名称引用的部分。声明的实体的访问也与字段访问表达式(15.11)、方法调用表达式其中通过简单的名称(15.12)指定方法、方法引用表达式(15.13)或限定的类实例创建表达式(15.9)相关联。在缺少访问修饰符的情况下,大多数声明具有包访问,允许访问包含其声明的包中的任何位置;其它的可能是 public、protected 和 private。

完全限定的、规范换名称也在此章讨论。

6.1 声明

声明引入实体到程序,并包含在名称中可以用于引用此实体的标识符(3.8)。

声明的实体是以下之一:

    包,在包声明(7.4)中声明的

    导入的类型,在单类型导入声明或按需导入类型声明(7.5.1,7.5.2)中声明的

    导入的 static 成员,在单静态导入声明或按需静态导入声明(7.5.3,7.5.4)中声明的

    类,在类类型声明(8.1)中声明的

    接口,在接口类型声明(9.1)中声明的

    类型参数,作为泛型类、接口、方法或构造器(8.1.2,9.1.2,8.4.4,8.8.4)的部分声明的

    引用类型(8.2,9.2,8.9.3,9.6,10.7)的成员,以下之一:

        成员类(8.5,9.5)

        成员接口(8.5,9.5)

        枚举常量(8.9)

        字段,以下之一:

            在类类型或枚举类型(8.3,8.9.2)中声明的字段

            在接口类型或注解类型(9.3,9.6.1)中声明的字段

            字段 length,其隐式地是每个数组类型(10.7)的成员

        方法,以下之一:

            在类类型或枚举类型(8.4,8.9.2)中声明的方法(abstract 或其它)

            在接口类型或注解类型(9.4,9.6.1)中声明的方法(总是 abstact)

    参数,以下之一:

        类类型或枚举类型(8.4.1,8.8.1,8.9.2)的方法或构造器的形式参数,或 lambda 表达式(15.27.1)的形式参数

        接口类型或注解类型(9.4,9.6.1)的 abstract 方法的形式参数

        try 语句(14.20)的 catch 子句中声明的异常处理器的异常参数

    局部变量,以下之一:

        在块(14.4)中声明的局部变量

        在 for 语句(14.14)中声明的局部变量

构造器(8.8)也通过声明引入,但使用类的名称在类中声明它们而不是引入新的名称。

不是泛型的(类 C ...)类型的声明声明了一个实体:非泛型类型(C)。非泛型类型不是原始类型,尽管句法上相似。反之,泛型类型(类 C ... 或接口 C ...)的声明声明了两个实体:泛型类型(C)和相应的非泛型类型(C)。这种情况下,术语 C 的意义依赖于它出现在的上下文:

    如果泛型不重要,如在以下标识的非泛型上下文中一样,标识符 C 表示非泛型类型 C。

    如果泛型重要,如除了非泛型上下文以外的来自 6.5 的所有上下文中一样,标识符 C 表示:

        原始类型 C,其是泛型类型 C 的擦除(4.6);或

        参数化类型,其是泛型类型 C 的具体的参数化。

13 种非泛型上下文如下:

    1. 在单类型导入声明中(7.5.1)

    2. 在单静态导入声明(7.5.3)中的 . 的左边的

    3. 在按需静态导入声明(7.5.4)中的 . 的左边的

    4. 在构造器声明(8.8)中的 ( 的左边的

    5. 在注解(9.7)中的 @ 符号之后

    6. 在类字面量(15.8.2)中的 .class 的左边的

    7. 在限定的 this 表达式(15.8.4)中的 .this 的左边的

    8. 在限定的父类字段访问表达式(15.11.2)中的 .super 的左边的

    9. 在限定的方法调用表达式(15.12)中的 .Identifier 或 .super.Identifier 的左边的

    10. 在方法引用表达式(15.13)中的 .super:: 的左边的

    11. 在后缀表达式(15.14.1)中的限定的表达式名称中

    12. 在方法或构造器(8.4.6,8.8.5,9.4)的 throws 子句中

    13. 在异常参数声明(14.20)中

前十个非泛型上下文对应于 6.5.1 中的前十个句法上下文的 TypeName。第十一个非泛型上下文是后缀表达式,其中限定的 ExpressionName,如 C.x,可以包含类型名 c,以表示静态成员访问。TypeName 的常用用法很重要:它表示这些上下文涉及类型的次一流的使用。相比之下,第十二和十三个非泛型上下文使用 ClassType,表示 throws 和 catch 从句以一流的按照字段声明的方式使用类型。这两个上下文作为非泛型的特性是由于异常类型无法参数化这一事实。

注意,ClassType 产生式允许注解,因此,可能在 throws 或 catch 从句中注解类型的用法,反之,TypeName 产生式不允许注解,因此,不可能在单类型导入声明中注解类型的用法。

命名约定

只要可能,Java SE 平台的类库尝试使用根据下面介绍的约定选择的名称。这些约定有助于使代码更可读,并避免某些种类的名称冲突。

我们建议在用 Java 编程语言编写的所有程序中使用这些约定。但是,如果长期持有的常规用法另有规定,则不应盲目地遵循这些约定。因此,例如,类 java.lang.Math 的 sin 和 cos 方法具有数学上的常规名称,尽管这些方法名称不遵循在这里建议的约定,因为它们是短的,且不是动词。

包名称

开发者应该设法通过为广泛分发的包选择独一无二名称来避免两个发布的包具有相同名称的可能性。这使得包易于自动安装和登记分类。本节指定用于生成此类独一无二包名称的建议约定。我们鼓励 Java SE 平台的实现提供自动支持,为将一组包从本地和临时的包名称转换这描述的独一无二的名称格式。

如果不使用唯一包名称,则可能导致在原理创建冲突包的点发生包名称冲突。这可能会造成用户或程序员很难或不可能解决的情况。类加载器可用于从彼此在包具有受约束的交互的情况下隔离具有相同名称的包,但不能以对原生程序透明的方式。

通过首先具有(或属于一个组织拥有的)一个互联网域名,如 oracle.com,来形成唯一的包名称。然后,你可以按组件反转此名称,以获取本例中的 com.oracle,并将这个作为你的包名称的前缀使用,使用组织内开发的约定进一步管理包名称。这样的约定可能将具体的包名称组件指定为部门、部、项目、计算机或登录名。

avatar

唯一包名称的第一个组件总是以所有小写 ASCII 字母编写,并且应该是顶级域名之一,如 com、edu、gov、mil、net 或 org,或标识在 ISO 标准 3166 中指定的国家的英文两位字母代码。

包名称并不意味着包在互联网上的存储位置。建议的生成唯一包名称的约定仅是一种在现有的、广泛已知的唯一名称注册表之上背负包命名约定的方式,而不必为包名称单独创建注册表。

    例如,命名为 edu.cmu.cs.bovik.cheese 的包不一定能从互联网地址 cmu.edu 或 cs.cmu.edu 或 bovik.cs.cmu.edu 上获得。

某些情况下,互联网域名可能是非法的包名称。这有一些建议的约定来解决这些情况:

    如果域名包含连字符或任何其它的不允许出现在标识符(3.8)中的特殊字符,则将其转换为下划线。

    如果任何已生成的包名称组件是关键字(3.9),在它们后面追加一个下划线。

    如果任何已生成的包名称组件以数字或任何其它不允许作为标识符初始字符的字符开头,则将一个下划线作为组件的前缀。

仅用于本地使用的包名称应具有以小写字母开头的第一个标识符,但第一个标识符具体不应是标识符 java;以标识符 java 开头的包名称是为 Java SE 平台的包保留的。

类和接口类型名称

类类型名称应该是描述性名次或名次短语,不能太长,在混合的情况下,每个单词的首字母大写。

avatar

同样,接口类型的名称应该是短的、描述性的,不能太长,在混合情况下,每个单词的第一个字母大写。该名称可以是描述性的名词或名词短语,当接口被用作抽象父类如接口 java.io.DataInput 和 java.io.DataOutput 时,它是适当的;或者它可能是描述行为的形容词,就像接口 Runnable 和 Cloneable 一样。

类型变量名称

类型变量名称应该是简练的(尽可能是单个字符),而且不应该包含小写字母。这使得区分类型参数与普通的类和接口很容易。

容器类型应该使用使用名称 E 作为它们的元素类型。Maps 应该使用 K 作为它们的键的类型,使用 V 作为它们的值的类型。名称 X 应该用于任意异常类型。我们使用 T 表示类型,只要没有更具体的有关类型的信息来区分它。(这通常是在泛型方法中使用的情况。)

如果有多个表示任意类型的类型参数,应该使用字母表中与 T 相邻的字母,如 S。交替地,可以使用数字下标(例如,T1、T2)来区分不同的类型变量。这种情况下,所有具有相同前缀的变量都应使用下标。

如果泛型方法出现在泛型类中,最好避免对方法和类的类型参数使用相同的名称,以避免混淆。这同样适用于嵌套的泛型类。

avatar

当类型参数不方便使用所述类别之一时,应选择在单个字母范围内尽可能有意义的名称。上述名称(E、K、V、X、T)不应该用于不适用于指定类别的类型参数。

方法名称

方法名称应该是动词或动词短语,在混合的情况下,第一个字母小写和任何随后的词的第一个字母大写。下面是一些用于方法名称的附加特定约定:

    用于 get 和 set 被认为是变量 V 的属性的方法应该被命名为 getV 和 setV。例如,类 Thread 的方法 getPriority 和 setPriority。

    返回一些东西的长度的方法应该被命名为 length,就像在类 String 中一样。

    测试关于对象的布尔条件 V 的方法应该被命名为 isV。例如,类 Thread 的方法 isInterrupted。

    将其对象转换为特定形式 F 的方法应该被命名为 toF。例如,类 Object 的方法 toString 和类 java.util.Date 的方法 toLocaleString 和 toGMTString。

只要可能且合适,新类中的方法的名称将基于现存的类似的类中的名称,特别是来自 Java SE 平台 API 的类,将使其更易于使用。

字段名称

不是 final 的字段的名称应该是首字母小写和随后的单词首字母大写的形式。注意,良好设计的类具有很少的 public 或 protected 的字段,除了那些是常量(static final 字段)的字段以外。

字段应具有那些是名词、名词短语或名词缩写的名称。

此约定的示例有类 java.io.ByteArrayInputStream 的字段 buf、pos 和 count,和类 java.io.InterruptedIOException 的字段 byteTransferred。

常量名称

接口类型中的常量名称应该是,以及类类型的 final 变量可能按照惯例是,一个或多个单词、首字母缩略词或缩写的序列,所有都是大写,组件用下划线 "_" 字符分隔。常量名称应该是描述性的,而不是不必要的缩写。通常,它们可能是语言适当的部分。

    常量名称的示例包括类 Character 的 MIN_VALUE、MAX_VALUE、MIN_RADIX 和 MAX_RADIX。

一组表示集合的可选值,或,较不常用地,在整数值中的掩码位,有时有效地用通用的缩写作为名称前缀来指定。

avatar

局部变量和参数名称

局部变量和参数名称应该简短但有意义。它们通常是简短的不是单词的小写字母序列,例如:

    缩写,一系列单词的第一个字母,如在变量 cp 中持有到 ColoredPoint 的引用

    缩写,如在 buf 中持有一个指向某种缓冲区的指针

    助记符术语,以某种方式组织,以帮助记忆和理解,通常是通过使用一组局部变量,其具有规范名称,模仿广泛地使用的类的参数名称。例如:

        in 和 out,只要涉及到一些类型的输入和输出,模仿 System 的字段

        off 和 len,只要涉及到偏移和长度,模仿 java.io 的接口 DataInput 和 DataOutput 的读和写方法的参数

应该避免使用一个字符的局部变量或参数名称,除非是临时循环变量,或者变量持有类型的无法区分的值。常规的一个字符名称是:

    byte 的 b

    char 的 c

    double 的 d

    Exception 的 e

    float 的 f

    int 的 i、j 和 k

    Object 的 o

    String 的 s

    一些类型的任意值的 v

仅由两个或三个小写字母组成的局部变量或参数名称不应该与初始国家代码和为唯一包名称的第一个组件的域名相冲突。

6.2. 名称和标识符

名称用于引用在程序中声明的实体。

由两种形式的名称:简单名称和限定名称。

简单名称是单个标识符。

限定名称由一个名称、一个 "." 记号和一个标识符组成。

在确定名称(6.5)的含义时,将考虑名称出现在的上下文。6.5 的规则区分上下文,其中名称必须表示(引用)包(6.5.3)、类型(6.5.5)、表达式(6.5.6)中的变量或值或方法(6.5.7)。

包和引用类型具有成员,其可以通过限定名称来访问。作为限定名称讨论的背景和名称含义的确定,请参阅 4.4、4.5.2、4.8、4.9、7.1、8.2、9.2 和 10.7 中的成员身份说明。

程序中,不是所有标识符都是名称的一部分。标识符也用于以下情况:

    * 在声明(6.1)中,其中可以出现标识符,以指定名称,通过它可以知道即将声明的实体。

    * 作为标记的语句(14.7)以及 break 和 continue 语句(14.15,14.16)中引用语句标签的标签。

    在标记的语句和与这些标识符相关联的 break 和 continue 语句中使用的标识符是与在声明中使用的那些完全区分的。

    * 在字段访问表达式(15.11)中,其中标识符在 "." 记号之后出现,以指示由 "." 记号之前的表达式表示的对象的成员,或由 "." 记号之前的 super 或
      TypeName.super 表示的对象。

    * 在某些方法调用表达式(15.12)中,其中标识符在 "." 记号之后和 "(" 记号之前出现,以指示由 "." 记号之前的表达式表示的对象的即将被调用的方法,或
      由 "." 记号之前的 TypeName 表示的类型,或由 "." 记号之前的 super 或 TypeName.super 表示的对象。

    * 在某些方法引用表达式(15.13)中,其中标识符在 "::" 记号之后出现,以指示由 "::" 记号之前的表达式表示的对象的方法,或由 "::" 记号之前的
      TypeName 表示的类型,或由 "::" 记号之前的 super 或 TypeName.super 表示的对象。

    * 在限定的类实例创建表达式(15.9)中,其中标识符在 new 记号右边出现,以指示类型,其是在 new 记号之前的表达式的编译时类型的成员。

    * 在注解(9.7.1)的元素值对中,以指示相应的注解类型的元素。

avatar

人们可能会向知道为什么这些类型的表达式使用标识符而不是简单名称,这毕竟只是标识符。原因是简单的表达式名称是根据词法环境定义的;即,简单的表达式名称必须在变量声明(6.5.6.1)的作用域内。另一方面,字段访问、限定的方法调用、方法引用和限定的类实例创建都引用名称不在词法环境内的成员。根据定义,此类名称绑定在仅由字段访问表达式、方法调用表达式、方法引用表达式或类实例创建表达式的 Primary 提供的上下文中;或由字段访问表达式、方法调用表达式或方法引用表达式的 super;等。因此,我们使用标识符而不是简单名称来表示这些成员。

为了使事情进一步复杂化,字段访问表达式不是表示对象字段的唯一方法。出于分析原因,限定的名称用于表示范围内变量的字段。(变量本身用一个简单名称表示,上面提到的。)这是应用于两种字段的表示的访问控制所必需的。

6.3. 声明作用域

声明的作用域是可以使用简单名称引用由此声明声明的实体的程序的区域,假定它是可见的(6.4.1)。

声明被称为在程序的某个特定点的作用域内,当且仅当声明的作用域包含该点。

可观察到的(7.4.3)顶层包的声明的作用域是所有可观察的编译单元(7.3)。

不可见的包的声明从不在作用域内。

子包的声明从不在作用域内。

包 java 总是在作用域内。

由单类型导入声明(7.5.1)或按需类型导入声明(7.5.2)导入的类型的作用域是 import 声明出现在的编译单元内的所有类和接口类型声明(7.6),以及编译单元的包声明(如果有)上的任何注解。

由单静态导入声明(7.5.3)或按需静态导入声明(7.5.4)导入的成员的作用域是 import 声明出现在的编译单元中的所有类和接口类型声明(7.6),还有编译单元的包声明(如果有)上的任何注解。

顶层类型(7.6)的作用域是顶层类型声明在的包中的所有类型声明。

在类类型 C(8.1.6)中声明的或继承自类类型 C(8.1.6)的成员 m 的声明的作用域是 C 的整个 body,包括任何嵌套的类型声明。

在接口类型 I(9.1.4)中声明的或继承自接口类型 I(9.1.4)的成员 m 的声明的作用域是 I 的整个 body,包括任何嵌套的类型声明。

在枚举类型 T 中声明的枚举常量 C 的作用域是 T 的 body 和表达式是枚举类型 T(14.11)的 switch 语句的任何 case 标签。

方法(8.4.1)、构造器(8.8.1)或 lambda 表达式(15.27)的形式参数的作用域是方法、构造器或 lambda 表达式的整个 body。

类的类型参数(8.1.2)的作用域是类声明的类型参数部分、类声明的任何父类或父接口的类型参数部分和类 body。

接口的类型参数(9.1.2)的作用域是接口声明的类型参数部分、接口声明的任何父接口的类型参数部分和接口 body。

方法的类型参数(8.4.4)的作用域是方法的整个声明,包括类型参数部分,但不包括方法修饰符。

构造器的类型参数(8.8.4)的作用域是构造器的整个声明,包括类型参数部分,但不包括构造器修饰符。

由块(14.2)直接封闭的局部类声明的作用域是直接封闭块的余下部分,包括它自己的类声明。

由 switch 块语句组(14.11)直接封闭的局部类声明的作用域是直接封闭 switch 块语句组的余下部分,包括它自己的类声明。

在块(14.4)中的局部变量声明的作用域是声明出现在的块的余下部分,从它自己的初始化器开始,包括局部变量声明语句中右侧的任何进一步声明符。

在基础 for 语句(14.14.1)的 ForInit 部分中声明的局部变量的作用域包括以下所有:

    它自己的初始化器

    for 语句的 ForInit 部分中右侧的任何进一步声明符

    for 语句的 Expression 和 ForUpdate 部分

    包含的 Statement

在增强的 for 语句(14.14.2)的 FormalParameter 部分中声明的局部变量的作用域是包含的 Statement。

在 try 语句(14.20)的 catch 子句中声明的异常处理器的参数的作用域是与 catch 相关联的整个块。

在 try-with-resources 语句(14.20.3)的 ResourceSpecification 中声明的变量的作用域是从声明向右的 ResourceSpecification 的其余部分,和与 try-with-resource 语句相关联的整个 try 块。

try-with-resources 语句的转化意味着上述规则。

avatar

avatar

avatar

avatar

6.4. 遮蔽和模糊

局部变量(14.4)、形式参数(8.4.1,15.27.1)、异常参数(14.20)和局部类(14.3)仅可以使用简单名称来引用,而不是限定名称(6.2)。

一些声明在局部变量、形式参数、异常参数或局部类声明中是不允许的,这是因为无法仅使用简单名称来区分声明的实体。

例如,如果方法的形式参数的名称可以重新声明为方法 body 中的局部变量的名称,则局部变量将遮蔽该形式参数,而形式参数将不再可见 - 这是不可取的结果。

如果形式参数的名称用于声明方法、构造器或 lambda 表达式的 body 中的一个新的变量,除非该新的变量是在由方法、构造器或 lambda 表达式包含的类声明中声明的,否则这是一个编译时错误。

如果局部变量 v 的名称用于声明在 v 的作用域中的一个新的变量,除非该新的变量是在类中声明的,且此类的声明在 v 的作用域中,否则这是一个编译时错误。

如果异常参数的名称用于声明在 catch 子句的 Block 中的一个新的变量,除非该新的变量是在由 catch 子句的 Block 包含的类声明中声明的,否则这是一个编译时错误。

如果局部类 C 的名称用于声明 C 的作用域内的一个新的局部类,除非该新的局部类是在另一个类中声明的,且此类的声明在 C 的作用域内,否则这是一个编译时错误。

这些规则允许在在变量或局部类的作用域中出现的嵌套的类声明(局部类(14.3))和匿名类(15.9)中的变量或局部类的重新声明。因此,在方法、构造器或 lambda 表达式中嵌套的类声明可能会遮蔽形式参数、局部变量或局部类的声明;并且在 catch 子句的 Block 中嵌套的类声明中可能会遮蔽异常参数的声明。

有两种处理由在 lambda 表达式中声明的 lambda 参数或其它变量创建的名称冲突的可选设计。一种是模仿类声明:像局部类一样,lambda 表达式引入了一个新的名称“层次”,并且表达式之外的所有变量名称都可以重新声明。另一个是“局部”策略:像 catch 子句、for 循环和块一样,lambda 表达式在与封闭上下文相同的“层次”上运行,表达式之外的局部变量不能被遮蔽。以上规则使用局部策略;没有特殊的许可允许在 lambda 表达式中声明的变量去遮蔽在封闭方法中声明的变量。

注意,局部类的规则不会为在局部类本身中声明的同名类提供异常。但是,这种情况被单独的规则所禁止:类不能与封装它(8.1)的类同名。

6.4.1. 遮蔽

一些声明可能在其作用域的一部分中被另一个同名声明所遮蔽,在这种情况下,不能使用简单名称来引用声明的实体。

遮蔽不同于隐藏(8.3,8.4.8.2,8.5,9.3,9.5),仅适用于其它将被继承但不是由于子类中的声明的成员。遮蔽也不同于模糊(6.4.2)。

声明 d 被称为在程序的点 p 处是可见的,如果 d 的作用域包括 p,并且 d 没有被 p 处的任何其它声明所遮蔽。

当我们讨论的程序点从上下文中清晰明了时,我们通常会简单地说声明是可见的。

名为 n 的类型的声明 d 在 d 的整个作用域内遮蔽了 d 出现的点的作用域内的名为 n 的任何其它类型的声明。

名为 n 的字段或形式参数的声明 d 遮蔽了,在 d 的整个作用域内,在 d 出现的点处的作用域中的名为 n 的任何其它变量的声明。

名为 n 的局部变量或异常参数的声明遮蔽了,在 d 的整个作用域内,(a)在 d 出现的点处的作用域中的名为 n 的任何其它字段的声明,和(b)在d 出现的点处的作用域中的而不是在 d 被声明的最内部类中声明的名为 n 的任何其它变量的声明。

名为 n 的方法的声明在 d 的整个作用域内遮蔽了 d 出现在的点处的封闭作用域中的名为 n 的任何其它方法的声明。

包声明从不遮蔽任何其它声明。

按需类型导入声明从不导致任何其它声明被遮蔽。

按需静态导入声明从不导致任何其它声明被遮蔽。

导入名为 n 的类型的包 p 的编译单元 c 中的单类型导入声明 d 遮蔽了,在整个 c 中,声明:

    在 p 的另一个编译单元中声明的名为 n 的任何顶层类型

    由 c 中按需类型导入声明导入的名为 n 的任何类型

    由 c 中的按需静态导入声明导入的名为 n 的任何类型

在包 p 的编译单元 c 中的单静态导入声明 d,它导入名为 n 的字段,遮蔽了通过 c 中的按需静态导入声明导入的名为 n 的任何 static 字段的声明,在整个 c 中。

包 p 的编译单元 c 中的单静态导入声明 d,它导入具有签名 s 的名为 n 的方法,遮蔽了通过 c 中的按需静态导入声明导入的具有签名 s 的名为 n 的任何 static 方法的声明,在整个 c 中。

包 p 的编译单元 c 中的单静态导入声明 d,它导入了名为 n 的类型,遮蔽了,在整个 c 中,声明:

    通过 c 中的按需静态导入声明导入的名为 n 的任何 static 类型;

    在 p 的另一个编译单元(7.3)中声明的名为 n 的任何顶层类型(7.6);

    通过 c 中的按需类型导入声明(7.5.2)导入的名为 n 的任何类型。

6.4.2. 模糊

简单名称可能出现在其可能潜在地被解释为变量、类型或包的名称的上下文中。在这些情况下,6.5 的规则指定变量优先于类型被选择,类型优先于包被选择。因此,有时无法通过简单名称来引用可见的类型或包声明。我们称这样的声明是模糊的。

模糊不同于遮蔽(6.4.1)和隐匿(8.3,8.4.8.2,8.5,9.3,9.5)。

6.1 的命名约定有助于减少模糊,但如果确实发生了,下面是一些关于如果避免它的注意事项。

当包名称出现在表达式中:

    如果包名称被字段声明模糊,则导入声明(7.5)通常可用于使在该包中声明的类型名称可用。

    如果包名称被参数或局部变量的声明模糊,则可以改变参数或局部变量的名称而不影响其它代码。

包名称的第一个组件通常不容易被误认为是类型名称,因为类型名称通常以单个大写字母开头。(Java 编程语言实际上不依赖于区分大小写来确定是包名称还是类型名称。)

涉及类和接口类型名称的模糊是罕见的。字段、参数和局部变量的名称通常不会模糊类型名称,因为按照惯例它们以小写字母开头,而类型名称按照惯例以大写字母开头。

方法名称无法模糊或不会被其它名称(6.5.7)模糊。

涉及字段名称的模糊是罕见的;但是:

    如果字段名称模糊了包名称,则导入声明(7.5)通常可用于使在该包中声明的类型名称可用。

    如果字段名称模糊了类型名称,则可以使用类型的完全限定名称,除非类型名称表示局部类(14.3)。

    字段名称无法模糊方法名称。

    如果字段名称被参数或局部变量的声明遮蔽,则可以改变参数或局部变量的名称而不影响其它代码。

涉及常量名称的模糊是罕见的:

    常量名称通常没有小写字母,因此它们通常不会模糊包或类型的名称,通常也不会遮蔽字段,其名称通常包含至少一个小写字母。

    常量名称无法模糊方法名称,因为它们在句法上是不同的。

6.5. 确定名称的含义

名称的含义依赖于它被使用的上下文。名称含义的确定需要三步:

    首先,上下文使名称在语法上分为六类之一:PackageName、TypeName、ExpressiongName、MethodName、PackageOrTypeName 或 AmbiguousName。

    第二,最初被其上下文归类为 AmbiguousName 或 PackageOrTypeName 的名称被重新归类为 PackageName、TypeName 或 ExpressiongName。

    第三,产生的分类决定了名称含义的最终确定(如果名称没有意义,则为编译时错误)。

PackageName:
    Identifier
    PackageName . Identifier

TypeName:
    Identifier
    PackageOrTypeName . Identifier

PackageOrTypeName:
    Identifier
    PackageOrTypeName . Identifier

ExpressiongName:
    Identifier
    AmbiguousName . Identifier

MethodName:
    Identifier

AmbiguousName:
    Identifier
    AmbiguousName . Identifier

上下文的使用有助于减少不同种类实体之间的名称冲突。如果遵守 6.1 中描述的命名约定,此类冲突将是罕见的。然而,随着不同程序员或不同组织开发的类型发展,冲突可能无意中出现。例如,类型、方法和字段可能有相同的名称。始终可以区分具有相同名称的方法和字段,因为使用的上下文总是指示是否是想要的方法。

6.5.1. 根据上下文进行名称的句法分类

在这些上下文中,名称在句法上被归类为 TypeName:

    * 前十个非泛型上下文(6.1):

        1. 在单类型导入声明(7.5.1)中

        2. 单静态导入声明(7.5.3)中的 . 的左侧

        3. 按需静态导入声明(7.5.4)中的 . 的左侧

        4. 构造器声明(8.8)中的 ( 的左侧

        5. 注解(9.7)中的 @ 符号之后

        6. 类字面量(15.8.2)中的 .class 的左侧

        7. 限定的 this 表达式(15.8.4)中的 .this 的左侧

        8. 限定的父类字段访问表达式(15.11.2)中的 .super 的左侧

        9. 限定的方法调用表达式(15.12)中的 .Identifier 或 .super.Identifier 的左侧

        10. 方法引用表达式(15.13)中的 .super:: 的左侧

    作为构成任何在使用类型的 16 个上下文中的 ReferenceType(包括数组类型中的括号左侧的,或参数化类型中的 < 左侧的,或参数化类型的通配符类型参数的 extends 或 super 子句中的 ReferenceType)的 Identifier 或点分 Identifier 序列:

        1. 在类声明(8.1.4,8.1.5,8.5,9.5)的 extends 或 implements 子句中

        2. 在接口声明(9.1.3)的 extends 子句中

        3. 方法(8.4,9.4)的返回类型(包括注解类型(9.6.1)的元素的类型)

        4. 在方法或构造器(8.4.6,8.8.5,9.4)的 throws 子句中

        5. 在泛型类、接口、方法或构造器(8.1.2,9.1.2,8.4.4,8.8.4)的类型参数声明的 extends 子句中

        6. 类或接口(8.3,9.3)的字段声明中的类型

        7. 方法、构造器或 lambda 表达式(8.4.1,8.8.1,9.4,15.27.1)的形式参数声明中的类型

        8. 方法(8.4.1)的接收者参数的类型

        9. 局部变量声明(14.4,14.14.1,14.14.2,14.20.3)中的类型

        10. 异常参数声明(14.20)中的类型

        11. 在到显式的构造器调用语句或类实例创建表达式或方法调用表达式(8.8.7.1,15.9,15.12)的显式的类型参数列表中

        12. 在不合格的类实例创建表达式中,要么作为要实例化的类类型(15.9),要么作为要实例化的匿名类的直接父类或直接父接口(15.9.5)

        13. 数组常见表达式(15.10.1)中的元素类型

        14. 强制转换表达式(15.16)的强制转换运算符中的类型

        15. 跟在 instanceof 关系运算符(15.20.2)后的类型

        16. 在方法引用表达式(15.13)中,作为要查找成员方法的引用类型或作为要构造的类类型或数组类型

        来自以上 16 中上下文中的 ReferenceType 标识符的 TypeName 的提取的旨在递归地应用于 ReferenceType 的所有子术语,例如它的元素类型和任何类型参数。

        例如,假定一个字段声明使用类型 p.q.Foo[]。数组类型的括号被忽略,术语 p.q.Foo 被提取为点分的数组类型中的括号左侧的标识符序列,并被分类为 TypeName。随后的步骤确定 p、q 和 Foo 哪一个是类型名称,哪一个是包名称。

        作为另一个示例,假定一个强制转换运算符使用类型 p.q.Foo<? exnteds String>。术语 p.q.Foo 再次被提取为一个标识符术语的点分序列,这一次是在参数化类型中的 < 的左侧,并归类为 TypeName。术语 String 被提取为参数化类型的通配符类型参数的 extends 子句中的一个 Identifier,并归类为 TypeName。

名称在句法上被归类为这些上下文中的 ExpressionName:

    作为限定的父类构造器调用(8.8.7.1)中的限定表达式

    作为限定的类实例创建表达式(15.9)中的限定表达式

    作为数组访问表达式(15.10.3)中的数组引用表达式

    作为 PostfixExpression(15.14)

    作为赋值运算符(15.26)的左侧操作数

名称在句法上被归类为这个上下文中的 MethodName:

    方法调用表达式(15.12)中的 "(" 前面

名称在句法上被归类为这些上下文中的 PackageOrTypeName:

    到限定的 TypeName 中的左侧

    在按需类型导入声明(7.5.2)中

名称在句法上被归类为这些上下文中的 AmbiguousName:

    到限定的 ExpressionName 中的左侧

    到在方法调用表达式中的 "(" 前面出现的最右侧的 . 的左侧

    到限定的 AmbiguousName 中的 "." 的左侧

    在注解类型元素声明(9.6.2)的默认值子句中

    到元素值对(9.7.1)中的 "=" 的右侧

    到方法引用表达式(15.13)中的 :: 的左侧

句法分类的作用是将某些种类的实体限制在表达式的某些部分:

    字段、参数或局部变量的名称可以用作表达式(15.14.1)。

    方法的名称只能作为方法调用表达式(15.12)的一部分出现在表达式中。

    类或接口类型的名称只能作为类字面量(15.8.2)、限定的 this 表达式(15.8.4)、类实例创建表达式(15.9)、数组创建表达式(15.10.1)、强制转换表达式(15.16)、instanceof 表达式(15.20.2)、枚举常量(8.9)的一部分或作为限定的字段或方法的名称的一部分出现在表达式中。

    包的只能作为限定的类或接口类型的名称的一部分出现在表达式中。

6.5.2. 上下文中引起歧义的名称重新分类

然后将 AmbiguousName 重新归类如下。

如果 AmbiguousName 是简单名称,由单个 Identifier 组成。

    如果此 Identifier 出现在具有该名称的局部变量声明(14.4)或参数声明(8.4.1,8.8.1,14.20)或字段声明(8.3)的作用域内,则此 AmbiguousName 重新归类为 ExpressionName。

    否则,如果该名称的字段通过单静态导入声明(7.5.3)或按需静态导入声明(7.5.4)声明在包含此 Identifier 的编译单元(7.3)中,则此 AmbiguousName 重新归类为 ExpressionName。

    否则,如果此 Identifier 出现在具有该名称的顶层列(8(Classes))或接口类型声明(9(Interfaces))、局部类声明(14.3)或成员类型声明(8.5,9.5)的作用域内,则此 AmbiguousName 重新归类为 TypeName。

    否则,如果该名称的类型通过单类型导入声明(7.5.1)或通过按需类型导入声明(7.5.2)、或通过单静态导入声明(7.5.3)或通过按需静态导入声明(7.5.4)声明在包含此 Identifier 的编译单元(7.3)中,则此 AmbiguousName 重新归类为 TypeName。

    否则,此 AmbiguousName 重新归类为 PackageName。后面的步骤确定该名称的包是否真实存在。

如果此 AmbiguousName 是限定的名称,由一个名称、一个 "." 和一个 Identifier 组成,则首先重新归类 "." 左侧的名称,因为它自己是一个 AmbiguousName。然后有一个选择:

    如果 "." 左侧的名称重新归类为 PackageName,则:

        如果有一个名称是 "." 左侧的名称的包,并且该包包含名称与此 Identifier 相同的类型声明,则此 AmbiguousName 重新归类为 TypeName。

        否则,此 AmbiguousName 重新归类为 PackageName。后面的步骤确定该名称的包是否真实存在。

    如果 "." 左侧的名称重新归类为 TypeName,则:

        如果此 Identifier 是由 TypeName 表示的类型的方法或字段的名称,则此 AmbiguousName 重新归类为 ExpressionName。

        否则,如果此 Identifier 是由 TypeName 表示的类型的成员类型的名称,则此 AmbiguousName 重新归类为 TypeName。

        否则,发生一个编译时错误。

    如果 "." 左侧的名称重新归类为 ExpressionName,则让 T 是由 ExpressionName 表示的表达式的类型。

        如果此 Identifier 是由 T 表示的类型的方法或字段的名称,则此 AmbiguousName 重新归类为 ExpressionName。

        否则,如果此 Identifier 是由 T 表示的类型的成员类型(8.5,9.5)的名称,则此 AmbiguousName 重新归类为 TypeName。

        否则,发生一个编译时错误。

avatar

6.5.3. 包名称的含义

归类为 PackageName 的名称的含义确定如下。

6.5.3.1. 简单包名称

如果一个包名称由单个 Identifier 组成,则此标识符表示名为该标识符的顶层包。

如果作用域(6.3)内没有该名称的顶层包,则发生一个编译时错误。

6.5.3.2. 限定的包名称

如果一个包名称是 Q.Id 形式,则 Q 也必须是一个包名称。包名称 Q.Id 命名一个包,此包是由 Q 命名的包内的命名为 Id 的成员。

如果 Q 未命名一个可观察到的包(7.4.3),或 Id 不是该包的一个可观察到的子包的简单名称,则发生一个编译时错误。

6.5.4. PackageOrTypeNames 的含义


6.5.4.1. 简单的 PackageOrTypeNames

如果 PackageOrTypeNames,Q,出现在名为 Q 的类型的作用域内,则此 PackageOrTypeNames 重新归类为 TypeName。

否则,此 PackageOrTypeNames 重新归类为 PackageName。此 PackageOrTypeNames 的含义是重新归类后的名称的含义。

6.5.4.2. 限定的 PackageOrTypeNames

给定一个限定的形式 Q.Id 的 PackageOrTypeName,如果此由 Q 表示的类型或包具有名为 Id 的成员类型,则此限定的 PackageOrTypeName 名称重新归类为 TypeName。

否则,将它重新归类为 PackageName。此限定的 PackageOrTypeName 的含义是重新归类后的名称的含义。

6.5.5. 类型名称的含义

归类为 TypeName 的名称的含义确定如下。

6.5.5.1. 简单的类型名称

如果一个类型名称由单个 Identifier 组成,则此标识符必须精确地出现在具有此名称的类型的一个可见的声明的作用域内,否则发生一个编译时错误。类型名称的含义是该类型。

6.5.5.2. 限定的类型名称

如果类型名称是 Q.Id 形式,则 Q 必须是类型名称或包名称。

如果 Id 恰好命名一个可访问的类型,此类型是由 Q 表示的类型或包的成员,则此限定的类型名称表示该类型。

如果 Id 未命名 Q(8.5,9.5)内的一个成员类型,或 Q 内的命名为 Id 的成员类型是不可访问的(6.6),或 Id 命名 Q 内的多个成员类型,则发生一个编译时错误。

avatar

6.5.6. 表达式名称的含义

归类为 ExpressionName 的名称的含义确定如下。

6.5.6.1. 简单的表达式名称

如果一个表达式名称由单个 Identifier 组成,则必须恰好有一个声明,表示在此 Identifier 出现的点上可见的局部变量、参数或字段。否则,发生一个编译时错误。

如果此声明表示一个实例变量(8.3),此表达式名称必须出现在实例方法(8.4)、构造器(8.8)、实例初始化器(8.6)或实例变量初始化器(8.3.2)的声明内。如果此表达式名称出现在 static 方法(8.4.3.2)、static 初始化器(8.7)或 static 变量的初始化器(8.3.2,12.4.2)内,则发生一个编译时错误。

如果此声明声明了一个 final 变量,其在此简单表达式之前已明确赋值,此名称的含义是该变量的值。否则,此表达式名称的含义是由此声明声明的变量。

如果此表达式名称出现在赋值上下文、调用上下文或强制转换上下文中,则此表达式名称的类型是捕获转换(5.1.10)后的字段、局部变量或参数的声明类型。

否则,此表达式名称的类型是字段、局部变量或参数的声明类型。

即,如果此表达式名称出现在“右手边”,它的类型受捕获转换的影响。如果此表达式名称是出现在“左手边”的变量,它的类型不受捕获转换的影响。

avatar

6.5.6.2. 限定的表达式名称

如果一个表达式名称是 Q.Id 形式,则 Q 已被归类为包名称、类型名称或表达式名称。

如果 Q 是包名称,则发生一个编译时错误。

如果 Q 是命名一个类类型(8(Classes))的类型名称,则:

    * 如果恰好有一个可访问的(6.6)类类型成员,该成员是名为 Id 的字段,则发生一个编译时错误。

    * 否则,如果此单个可访问的成员字段不是类变量(即,它未被声明为 static),则发生一个编译时错误。

    * 否则,如果此类变量被声明为 final,则 Q.Id 表示此类变量的值。

      此表达式 Q.Id 的类型是捕获转换(5.1.10)后的类变量的声明类型。

      如果 Q.Id 出现在要求变量而不是值的上下文中,则发生一个编译时错误。

    * 否则,Q.Id 表示此类变量。

      此表达式 Q.Id 的类型是捕获转换(5.1.10)后的类变量的声明类型。

      注意,this 子句覆盖了枚举常量(8.9)的使用,因为这些总是具有相应的 final 类变量。

如果 Q 是类型名称,该类型名称命名了一个接口类型(9(Interfaces)),则:

    * 如果恰好没有可访问的(6.6)接口类型的成员,该成员是一个名为 Id 的字段,则发生一个编译时错误。

    * 否则,Q.Id 表示该字段的值。

      表达式 Q.Id 的类型是捕获转换(5.1.10)后的字段的声明类型。

      如果 Q.Id 出现在要求变量而不是值的上下文中,则发生一个编译时错误。

如果 Q 是表达式名称,让 T 是表达式 Q 的类型:

    * 如果 T 不是引用类型,则发生一个编译时错误。

    * 如果恰好没有可访问的(6.6)类型 T 的成员,该成员是名为 Id 的字段,则发生一个编译时错误。

    * 否则,如果此字段是以下任意一种:

        接口类型的字段

        类类型的 final 字段(它可能是类变量或实例变量)

        数组类型(10.7)的 final 字段 length

      那么 Q.Id 表示字段值,除非它出现在要求变量的上下文中,而该字段是明确地未赋值的空白 final 字段,在这种情况下,它会生成一个变量。

      表达式 Q.Id 的类型是捕获转换(5.1.10)后的字段的声明类型。

      如果 Q.Id 出现在要求变量而不是值的上下文中,而由 Q.Id 表示的字段是明确地已赋值的,则发生一个编译时错误。

    * 否则,Q.Id 表示变量,类 T 的字段 Id,它可能是类变量或实例变量。

      表达式 Q.Id 的类型是捕获转换(5.1.10)后的字段成员的类型。

avatar

avatar

6.5.7. 方法名称的含义

分类为 MethodName 的名称的含义确定如下。

6.5.7.1. 简单方法名称

简单方法名称出现在方法调用表达式(15.12)中。简单方法名称由单个 Identifier 组成,其指定了被调用的方法名称。方法调用规则要求,此 Identifier 要么表示在方法调用点处可见的方法,要么表示通过单静态导入声明或按需静态导入声明(7.5.3,7.5.4)导入的方法。

avatar avatar

6.6. 访问控制

Java 编程语言提供了访问控制机制,以防止包或类的用户依赖于该包或类的实现的不必要的细节。如果允许访问,则被访问的实体称为可访问的。

注意,访问性是一个可以在编译时确定的静态属性。它依赖于类型和声明修饰符。

限定的名称是一种访问包和引用类型的成员的方法。当此种成员的名称从上下文(6.5.1)中归类为限定的类型名称时(表示包或引用类型的成员,6.5.5.2),则应用访问控制。

例如,单类型导入语句(7.5.1)使用限定的类型名称,因此命名类型必须是从包含导入语句的编译单元上可访问的。作为另一个示例,类声明可以为父类(8.1.5)使用限定的类型名称,并且命名类型必须是可访问的。

一些明显的表达式在 6.5.1 中的上下文分类中“缺失”:Primary 上的字段访问(15.11.1)、Primary 上的方法调用(15.12)、通过 Primary 的访问引用(15.13)和限定的类实例创建中的实例化的类(15.9)。由于 6.2 中给出的原因,这些表达式中的每个使用标识符,而不是名称。因此,成员(无论是字段、方法还是类型)的访问控制由字段访问成员、方法调用表达式、方法引用表达式和限定类实例创建表达式显式地应用。(注意,字段访问也可能由作为后缀表达式出现的限定名称表示。)

此外,许多语句和表达式允许使用类型而不是类型名称。例如,类声明可以使用参数化类型(4.5)来表示父类。由于参数化类型不是限定的类型名称,因此类声明必须显式地执行表示的父类的访问控制。因此,提供 6.5.1 中上下文的大多数语句和表达式为了分类一个 TypeName 也执行它们自己的访问控制检查。

除了包或引用类型的成员访问,还有引用类型的构造器访问。当构造器被显式或隐式调用时,必须进行访问控制检查。因此,通过显式的构造器调用语句(8.8.7.1)和类实例创建表达式(15.9.3)检查访问控制。此类检查是必要的,因为 6.5.1 没有提到显式构造器调用语句(因为它们间接引用构造器名称),并且不知道由未限定的类实例创建表达式表示的类类型和该类类型的构造器之间的区别。而且,构造器没有限定名称,因此在限定的类型名称的分类时我们不依赖于被检查的访问控制。

可访问性影响类成员(8.2)的继承,包括隐藏和方法重写(8.4.8.1)。

6.6.1. 确定可访问性

    * 包总是可访问的。

    * 如果一个类或接口类型被声明为 public,则任何代码都可以访问它,前提是声明它的编译单元(7.3)是可观察的。

      如果一个类或接口类型被声明为包访问,则仅可以从声明它的包内访问它。

      一个未声明访问修饰符的类或接口类型隐式地具有包访问。

    * 一个数组类型是可访问的,当且仅当它的元素类型是可访问的。

    * 引用类型的成员(类、接口、字段或方法)或类类型的构造器是可访问的,如果此类型是可访问的,并且其成员或构造器被声明为允许访问:

        如果其成员或构造器被声明为 public,则允许访问。

        缺少访问修饰符的接口的所有成员都隐式地是 public。

        否则,如果其成员或构造器被声明为 protected,则仅当以下之一为 true 时,允许访问:

            从包含声明那些 protected 成员或构造器的类的包内出现的成员或构造器访问。

            如 6.6.2 所述正确的访问。

        否则,如果其成员或包被声明为包访问,则仅当访问从声明类型的包内出现时,允许访问。

        未声明访问修饰符的类成员或构造器隐式地具有包访问。

        否则,其成员或构造器被声明为 private,并且当且仅当访问出现在封装该成员或构造器的顶层类(7.6)的 body 中时,允许访问。

6.6.2. protected 访问细节

对象的 protected 成员或构造器可以从包的外部访问,在该包中,它仅由负责实现该对象的代码声明。

6.6.2.1. 访问 protected 成员

让 C 是声明 protected 成员的类。仅允许 C 的子类 S 的 body 内的访问。

此外,如果 Id 表示实例字段或实例方法,则:

    如果通过限定名称 Q.Id 或方法引用表达式 Q :: Id(15.13)访问,其中 Q 是 ExpressionName,则当且仅当表达式 Q 的类型是 S 或 S 的子类时,允许访问。

    如果通过字段访问表达式 E.Id 或 方法调用表达式 E.Id(...) 或方法引用表达式 E :: Id 访问,其中 E 是 Primary 表达式(15.8),则当且仅当 E 的类型是 S 或 S 的子类时,允许访问。

    如果通过方法引用表达式 T :: Id 访问,其中 T 是 ReferenceType,则当且仅当类型 T 是 S 或 S 的子类时,允许访问。

有关访问 protected 成员的更多信息可以在 Checking Access to Protected Members in the Java Virtual Machine by Alessandro Coglio, in the Journal of Object Technology, October 2005 中找到。

6.6.2.2. 限定的访问 protected 构造器

让 C 是类,其中声明一个 protected 构造器,让 S 是最内部的类,在其声明中,使用那个 protected 构造器。则:

    如果通过父类构造器调用 super(...) 或 限定的父类构造器调用 E.super(...) 访问,其中 E 是 Primary 表达式,则允许访问。

    如果通过匿名类实例创建表达式 new C(...){...} 或 限定的匿名类实例创建表达式 E.new C(...){...} 访问,其中 E 是 Primary 表达式,则允许访问。

    如果通过简单类实例创建表达式 new C(...),或限定的类实例创建表达式 E.new C(...) 访问,其中 E 是 Primary 表达式,或方法引用表达式 C :: new,其中 C 是 ClassType,则不允许访问。可以通过类实例创建表达式(未声明匿名类)或方法引用表达式,仅从定义它的包内。

avatar avatar

6.7. 完全限定的名称和规范名称

每个基元类型、命名的包、顶层类和顶层接口具有完全限定的名称:

    基元类型的完全限定的名称是该基元类型的关键字、即 byte、short、char、int、long、float、double 或 boolean。

    命名的包,其不是一个命名的包的子包,的完全限定的名称是其简单名称。

    命名的包,其是另一个命名的包的子包,的完全限定名称由包含的包的完全限定名称,后跟 ".",后跟子包的简单名称,组成。

    顶层类或顶层接口,其声明在未命名的包中,的完全限定名称是类或接口的简单名称。

    顶层类或顶层接口,其声明在命名的包中,的完全限定名称由包的完全限定名称,后跟 ".",后跟类或接口的简单名称,组成。

每个成员类、成员接口和数组类型可能具有完全限定名称:

    另一个类或接口 C 的成员类或接口 M 具有完全限定名称,当且仅当 C 具有完全限定名称时。

    这种情况下,M 的完全限定名称由 C 的完全限定名称,后跟 ".",后跟 M 的简单名称,组成。

    数组类型具有完全限定名称,当且仅当其元素类型具有完全限定名称时。

    这种情况下,数组类型的完全限定名称由后跟 "[]" 的数组类型的组件类型的完全限定名称组成。

局部类没有完全限定名称。

每个基元类型、命名的包、顶层类和顶层接口具有规范名称:

    对于每个基元类型、命名的包、顶层类和顶层接口来说,规范名称与完全限定名称相同。

每个成员类、成员接口和数组类型可能具有规范名称:

    在另一个类或接口 C 中声明的成员类或成员接口 M 具有规范名称,当且仅当 C 具有规范名称时。

    这种情况下,M 的规范名称由 C 的规范名称,后跟 ".",后跟 M 的简单名称,组成。

    数组类型具有规范名称,当且仅当其组件类型具有规范名称时。

    这种情况下,数组类型的规范名称由后跟 "[]" 的数组类型的组件类型的规范名称组成。

局部类没有规范名称。

avatar