什么是 default 权限?
default 权限,也常被称为 包私有权限,是 Java 访问修饰符中的一种,当一个类、成员变量(字段)或方法没有显式地使用任何访问修饰符(如 public, protected, private)时,它就拥有了 default 权限。
关键点:
default 权限不是一个关键字,而是没有关键字时的一种默认状态。
访问规则详解
default 权限的核心规则是:只有同一个包内的类才能访问。
让我们通过一个表格来对比四种访问修饰符,会更清晰:
| 修饰符 | 同一类中 | 同一包中不同类 | 不同包的子类 | 不同包的非子类 |
|---|---|---|---|---|
public |
✔️ | ✔️ | ✔️ | ✔️ |
protected |
✔️ | ✔️ | ✔️ | ❌ |
default |
✔️ | ✔️ | ❌ | ❌ |
private |
✔️ | ❌ | ❌ | ❌ |
代码示例
为了更好地理解,我们创建几个类来演示。
项目结构
假设我们有以下包结构:
src/
├── com/
│ └── example/
│ ├── Animal.java
│ ├── Dog.java
│ └── Main.java
└── com/
└── other/
└── Cat.java
示例代码
com.example.Animal.java (同一个包中的基类)
package com.example;
// 这个类没有 public 修饰符,所以它只能在 com.example 包内被访问。
class Animal {
// default 权限的成员变量
String name;
// default 权限的方法
void eat() {
System.out.println("This animal is eating.");
}
// public 权限的方法,用于外部调用
public void displayInfo() {
System.out.println("Animal's name: " + this.name);
}
}
com.example.Dog.java (同一个包中的子类)
package com.example;
// Dog 和 Animal 在同一个包下
public class Dog extends Animal {
public Dog(String name) {
// 可以访问父类的 default 成员
this.name = name;
}
public void bark() {
// 可以调用父类的 default 方法
eat();
System.out.println(name + " says: Woof!");
}
}
com.example.Main.java (同一个包中的其他类)
package com.example;
// Main, Animal, Dog 都在 com.example 包下
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
animal.name = "Generic Animal"; // 可以访问 default 成员
animal.eat(); // 可以调用 default 方法
animal.displayInfo();
System.out.println("--------------------");
Dog dog = new Dog("Buddy");
dog.bark(); // 通过 Dog 类间接访问了 Animal 的 default 成员和方法
}
}
com.other.Cat.java (不同包中的类)
package com.other;
// Cat 和 Animal 不在同一个包下
public class Cat {
public void tryToAccessAnimal() {
Animal animal = new Animal(); // 编译错误!因为 Animal 类是 default 权限,不能跨包访问。
// 以下所有行都会导致编译错误
// animal.name = "Whiskers"; // 编译错误
// animal.eat(); // 编译错误
// animal.displayInfo(); // 编译错误
}
}
运行结果
当你运行 com.example.Main 时,它会正常工作并输出:
This animal is eating.
Animal's name: Generic Animal
--------------------
This animal is eating.
Buddy says: Woof!
当你尝试编译 com.other.Cat.java 时,编译器会报错,提示 Animal 是 public 或在 com.other 包中。
何时使用 default 权限?
default 权限是实现封装和模块化的重要工具。
包内实现细节的隐藏
这是 default 权限最常见的用途,一个包通常代表一个功能模块或一个组件,你可以将模块内部的类、接口、方法和字段设置为 default 权限,以表明它们是模块的内部实现,不应该被模块外的代码直接依赖。
这样做的好处是:
- 降低耦合性:外部代码无法直接访问你的内部实现,当你需要重构或修改内部实现时,不会影响到外部代码。
- 清晰的边界:它向其他开发者明确传达了“这是我的内部API,请勿触碰”的信号。
接口中的 default 方法
从 Java 8 开始,default 关键字有了另一个用途:可以在接口中定义带有 default 实现的方法。
注意:这和访问修饰符的 default 是两个完全不同的概念!
public interface MyInterface {
// 这是一个抽象方法,没有实现
void abstractMethod();
// 这是一个 default 方法,有默认实现
// 它可以被实现该接口的类直接继承,也可以被覆盖
default void defaultMethod() {
System.out.println("This is a default method in the interface.");
}
}
public class MyClass implements MyInterface {
// 必须实现 abstractMethod
@Override
public void abstractMethod() {
System.out.println("Implementing abstractMethod.");
}
// 可以选择不实现 defaultMethod,直接使用默认实现
}
public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.abstractMethod(); // 输出: Implementing abstractMethod.
obj.defaultMethod(); // 输出: This is a default method in the interface.
}
}
| 特性 | 描述 |
|---|---|
| 名称 | default 权限,也称为包私有权限。 |
| 修饰符 | 不使用任何访问修饰符(public, protected, private)。 |
| 访问范围 | 仅限于同一个包内的类可以访问。 |
| 类 | 可以声明 default 类,该类只能被同包内的其他类访问和继承。 |
| 成员(变量/方法) | 可以声明 default 成员,该成员只能被同包内的类访问。 |
| 接口 | 接口本身必须是 public 的,不能是 default 的。 |
| 接口方法 | 接口中的 default 方法(Java 8+)是一种带有默认实现的方法,与访问修饰符的 default 无关。 |
| 核心思想 | 封装,用于隐藏包的实现细节,保护模块的完整性,降低外部依赖。 |
理解 default 权限是编写健壮、可维护 Java 代码的基础,它帮助你构建清晰的模块边界,是良好封装实践的一部分。
