Java编程中的作用域、遮蔽与访问控制
立即解锁
发布时间: 2025-08-18 02:21:28 阅读量: 2 订阅数: 16 

### Java 编程中的作用域、遮蔽与访问控制
#### 1. 遮蔽(Obscuring)
在 Java 编程里,声明可能会被隐藏、遮蔽或模糊化。模糊化与隐藏和遮蔽不同,它涉及不同类型的实体,主要是包名和类型名可能被模糊。具体有以下三种情况:
- 变量名模糊包名
- 类型名模糊包名
- 变量名模糊类型名
由于 Java 命名约定,后两种情况比较少见,所以这里主要讨论变量名模糊包名的情况。
模糊化基于 JLS 中对上下文歧义名称的重新分类。有时候,名称的语法分类并不完美,在某些上下文中,名称可能指代不同类型的实体,造成歧义。例如下面的代码:
```java
package test; //test 是一个包
class x {
static final String length = "test is a package name";
static Widget test = new Widget(); //test 是一个变量
public static void main(String[] args) {
int[] x = new int[10];
int length = 0;
System.out.println(test.x.length); //What is test?
}
static class test { //test 是一个类型
static String[] x = { "test is a", " type name" };
}
}
class Widget {
String[] x = { "test is a variable name" };
}
```
在这个例子中,`test` 可能是变量、类型或包名。执行这个程序,最初会打印 `1`,这是 `Widget` 类中 `x` 数组的长度。如果删除 `Widget` 类型的 `test` 变量声明,程序会打印 `2`,即嵌套顶级 `test` 类中 `x` 数组的长度。若再删除该类的声明,程序会打印 `test is a package name`。
还有一个涉及方法调用表达式的例子:
```java
class Test {
public static void main(String[] args) {
String Widget = "Test is a variable name";
System.out.println(Widget.length());
}
}
class Widget {
static int length() {
return 0;
}
}
```
执行这个程序会打印 `23`,即 `Widget` 字符串的长度。在这两个例子中,编译器会优先将歧义名称解析为变量,而不是类型或包名。
当包名被模糊时,JLS 给出了两条建议:
- 如果包名被字段声明模糊,可以使用导入声明来引入该包中声明的类型名。
- 如果包名被参数或局部变量声明模糊,可以更改参数或局部变量的名称,而不影响其他代码。
同时,JLS 还警告,由两到三个小写字母组成的局部变量或参数名不应与唯一包名的第一个组件(如常见的顶级域名)冲突,像 `com`、`net`、`org` 等,应避免将这些作为局部变量或参数名。
#### 2. 可观察的编译单元和包
一个存储在德国或日本软盘上名为 `fubar` 的包,显然不能被美国的开发者使用。最初的 JLS 从作用域和可访问性方面解决这个问题:
- 顶级包名的作用域由主机系统的约定决定,包名不会隐藏其他名称。
- 对包成员的访问是否允许由主机系统决定,`java` 包及其标准子包 `lang`、`io` 和 `util` 应始终可访问。
在第二版 JLS 中,包(和编译单元)现在分为可观察和不可观察。一个包可观察的条件如下:
- 包含该包声明的编译单元是可观察的。
- 该包的子包是可观察的。
由此可以得出,`java`、`java.lang` 和 `java.io` 包始终是可观察的。可观察顶级包声明的作用域是所有可观察的编译单元,不可观察的包声明不在作用域内,子包声明也不在作用域内。
#### 3. 限定访问(Qualified Access)
JLS 中访问的定义存在两个问题。首先,该定义没有考虑构造函数。访问与作用域是不同的概念,访问指定了程序文本中可以通过限定名称、字段访问表达式或方法调用表达式(方法不是由简单名称指定)引用已声明实体的部分。
合格访问的定义与访问的定义相似,限定名称是访问包和引用类型成员的一种方式,相关的访问方式还包括字段访问表达式和方法调用表达式。这三种访问方式在语法上相似,都有一个 “.” 符号,前面是包、类型或具有类型的表达式的指示,后面是命名包或类型成员的标识符,它们统称为限定访问构造。
实际上,构造函数是第四种访问方式,但 JLS 在访问定义中遗漏了这一点。访问控制适用于限定访问以及通过类实例创建表达式和显式构造函数调用对构造函数的调用,具体包括以下方面:
1. 任何类型名的使用(类型特权)
2. 构造函数调用(实例化),包括:
- 类实例创建表达式
- 使用 `super` 关键字的显式构造函数调用
- `java.lang.Class` 中的 `newInstance()` 方法
3. 字段访问和方法调用表达式(访问对象的实现)
在导入类型时,通常使用简单类型名,而 JLS 中限定访问的定义没有涵盖这种最常见的访问方式。为了解决这个问题,引入了 “类型特权” 这个术语,它定义为任何类型名的使用,不区分简单名称和限定名称。类型特权进一步分为类类型特权和接口类型特权,由于接口类型不能实例化且其所有成员都是隐式公共的,所以接口类型特权与访问控制讨论无关。只有完全限定的类型名包含包名,才能 “访问” 包的成员。
#### 4. 访问控制
Java 中有三种访问修饰符:
0
0
复制全文
相关推荐









