范围
浏览 类和对象 主题: ) |
类、变量或方法的范围是其可见性和可访问性。可见性或可访问性意味着您可以从给定位置使用该项。
方法参数在整个方法内可见,但在方法外部不可见。
代码清单 3.14:Scope.java
public class Scope {
public void method1(int i) {
i = i++;
method2();
int j = i * 2;
}
public void method2() {
int k = 20;
}
public static void main(String[] args) {
method1(10);
}
}
|
在 代码清单 3.14 中,i
在整个 method1
方法内可见,但在 method2
和 main
方法中不可见。
局部变量在其声明后可见,直到创建局部变量的块结束。
代码部分 3.50:局部变量。
{
...
// myNumber is NOT visible
{
// myNumber is NOT visible
int myNumber;
// myNumber is visible
{
...
// myNumber is visible
}
// myNumber is visible
}
// myNumber is NOT visible
...
}
|
您肯定已经注意到,在本书中使用的类方法声明的开头有 public
、protected
和 private
这些词。这些关键字在 Java 语言语法中被称为 访问修饰符,它们定义了给定项的范围。
- 如果类具有 public 可见性,则该类可以在程序中的任何地方被引用。
- 如果类具有 protected 可见性,则该类只能在定义类的包中被引用。
- 如果类具有 private 可见性(只有当该类在另一个类中定义为嵌套类时才会发生),则该类只能在外部类中被访问。
- 如果变量在 public 类中定义,并且它具有 public 可见性,则该变量可以通过定义它的类在应用程序中的任何地方被引用。
- 如果变量具有 protected 可见性,则该变量只能在子类和同一个包中通过定义它的类被引用。
- 如果变量具有 package 可见性,则该变量只能在同一个包中通过定义它的类被引用。
- 如果变量具有 private 可见性,则该变量只能在定义它的类中被访问。
- 如果方法在 public 类中定义,并且它具有 public 可见性,则该方法可以通过定义它的类在应用程序中的任何地方被调用。
- 如果方法具有 protected 可见性,则该方法只能在子类和同一个包中通过定义它的类被调用。
- 如果一个方法具有 **包** 可见性,则该方法只能通过定义它的类在同一个包中被调用。
- 如果一个方法具有 **私有** 可见性,则该方法只能在定义它的类中被调用。
对于接口
[edit | edit source]接口方法和接口始终是 public
。你不需要指定访问修饰符。它将默认设置为 public
。为了清晰起见,建议使用 public
关键字。
同样,在接口中定义的所有成员变量在继承到类中后,默认将变为 static
final
。
总结
[edit | edit source]类 | 嵌套类 | 方法或成员变量 | 接口 | 接口方法签名 | |
---|---|---|---|---|---|
public
|
从任何地方可见 | 与它的类相同 | 与它的类相同 | 从任何地方可见 | 从任何地方可见 |
protected
|
N/A | 它的类和它的子类 | 它的类和它的子类,以及它的包 | N/A | N/A |
package | 仅从它的包可见 | 仅从它的包可见 | 仅从它的包可见 | N/A | N/A |
private
|
N/A | 仅从它的类可见 | 仅从它的类可见 | N/A | N/A |
粗体部分是默认情况。
实用工具
[edit | edit source]可见性的一个一般准则是只让成员尽可能可见。如果一个成员只需要是私有的,就不要把它设为公有的。
这样做,你可以重写一个类并更改所有私有成员而不会出现编译错误,即使你不知道所有使用你的类的类,只要你不更改公共成员的签名。
字段封装
[edit | edit source]通常,最好将数据设为私有或受保护。对数据的访问由 *setter* 和 *getter* 方法控制。这样可以让程序员控制对数据的访问,允许他们检查和处理无效数据。
代码部分 3.51:封装。
private String name;
/**
* This is a getter method because it accesses data from the object.
*/
public String getName() {
return name;
}
/**
* This is a setter method because it changes data in the object.
*/
public boolean setName(String newName) {
if (newName == null) {
return false;
} else {
name = newName;
return true;
}
}
|
在 代码部分 3.51 中,setName()
方法只有在新名称不为空的情况下才会更改 name
的值。因为 setName()
是有条件地更改 name 的,所以最好返回一个布尔值,让程序知道更改是否成功。
**问题 3.15**: 考虑以下类。
问题 3.15:Question15.java
public class Question15 {
public static final int QKQKQKQK_MULTIPLIER = 2;
public int ijijijijijijijijijAwfulName = 20;
private int unununununununununCrummyName = 10;
private void mememememememeUglyName(int i) {
i = i++;
tltltltltltltltltlBadName();
int j = i * QKQKQKQK_MULTIPLIER;
}
public void tltltltltltltltltlBadName() {
int k = ijijijijijijijijijAwfulName;
}
public static void main(String[] args) {
mememememememeUglyName(unununununununununCrummyName);
}
}
|
列出此类中可以重命名而无需更改或甚至不知道客户端类的字段和方法。
unununununununununCrummyName
mememememememeUglyName()
每个公有的字段或方法都可以被客户端类直接调用,因此如果该字段或方法具有新名称,则该类将返回编译错误。