Java 中没有 private 继承这个语法。

你无法像这样写代码:
// 这是错误的,Java 编译器会报错
private class SubClass extends SuperClass {
// ...
}
当人们讨论 "Java private 继承" 时,他们通常指的是如何实现与 C++ 中的 private 继承类似的效果。
C++ 中的 private 继承是什么?
为了理解 Java 的替代方案,我们先看看 C++ 中的 private 继承:
-
语法:
(图片来源网络,侵删)class Derived : private Base { // ... }; -
核心效果:
- 访问控制:
Base类中的public和protected成员(方法和变量)在Derived类中会变成private访问级别,这意味着Derived类的成员函数可以访问Base的成员,Derived类的外部代码(main函数中创建的Derived对象)无法通过Derived对象访问这些Base成员。 - “is-implemented-in-terms-of”(根据...实现)关系:
private继承表达的是一种实现关系,而不是一种类型关系,它意味着Derived类在内部使用了Base类的功能来完成自己的工作,但它不是一个Base,这通常被称为组合 的一种形式。
- 访问控制:
为什么 Java 不支持 private 继承?
Java 的设计哲学与 C++ 不同,Java 的继承模型更加纯粹和简单:
- 单一继承:一个类只能直接继承一个父类。
- 接口:Java 提供了
interface机制,用于实现多重继承的行为(即实现多个接口)。 - 明确的“is-a”(是一个)关系:Java 的
extends关键字强烈暗示着子类是父类的一种,它们之间是 "is-a"(是一个)的关系。private继承会破坏这种清晰的语义。
Java 设计者认为,如果需要实现 "is-implemented-in-terms-of"(根据...实现)这种关系,组合(Composition) 是比 private 继承更清晰、更灵活、更推荐的方式。
在 Java 中如何实现 private 继承的效果?
在 Java 中,你可以通过以下两种主要技术来模拟 C++ private 继承的行为,它们的核心思想都是组合。

组合(Composition)- 最推荐的方式
这是最直接、最符合 Java 思想的方式,你在 SubClass 中创建一个 SuperClass 的实例,并显式地调用其方法来完成任务。
示例:
// 父类
class SuperClass {
public void superMethod() {
System.out.println("This is a public method from SuperClass.");
}
}
// 子类,通过组合实现功能
class SubClass {
// 1. 创建一个父类的私有实例(成员变量)
private SuperClass superInstance = new SuperClass();
// 2. 提供自己的公共方法,内部调用父类实例的方法
public void myMethod() {
System.out.println("SubClass is doing something.");
// 3. 通过调用父类实例的方法来完成工作
this.superInstance.superMethod();
}
}
// 使用
public class Main {
public static void main(String[] args) {
SubClass sub = new SubClass();
sub.myMethod(); // 可以调用 SubClass 的方法
// sub.superInstance.superMethod(); // 错误!superInstance 是 private 的,外部无法访问
// sub.superMethod(); // 错误!SubClass 没有 superMethod 方法
}
}
分析:
SubClass并不是一个SuperClass,它只是拥有一个SuperClass。SuperClass的方法在SubClass的外部是不可见的,完美模拟了private继承的封装性。- 优点:
- 高内聚、低耦合:
SubClass只依赖于它需要使用的SuperClass的特定功能,而不是整个SuperClass的结构。 - 灵活性高:你可以轻松地在运行时替换
SuperClass的实现(通过依赖注入),这在继承中很难做到。 - 代码清晰:关系非常明确,
SubClass使用了SuperClass。
- 高内聚、低耦合:
内部类(Inner Class)- 一种特殊的组合
这种方式稍微复杂一些,但也能达到类似的效果,你可以将 SuperClass 的功能封装在一个 private 内部类中,然后让外部类去使用它。
示例:
// 父类
class SuperClass {
public void superMethod() {
System.out.println("This is a public method from SuperClass.");
}
}
// 外部类
class SubClass {
// 1. 定义一个 private 内部类,继承自 SuperClass
private class MySuperClass extends SuperClass {
// 内部类可以覆盖或扩展父类的方法
@Override
public void superMethod() {
System.out.println("This is an overridden method in the private inner class.");
}
}
// 2. 外部类持有内部类的实例
private MySuperClass innerInstance = new MySuperClass();
// 3. 外部类提供自己的方法,调用内部类的方法
public void myMethod() {
System.out.println("SubClass is doing something via an inner class.");
this.innerInstance.superMethod();
}
}
// 使用
public class Main {
public static void main(String[] args) {
SubClass sub = new SubClass();
sub.myMethod(); // 输出 SubClass 的信息,然后是内部类覆盖后的 superMethod 信息
// MySuperClass inner = new MySuperClass(); // 错误!MySuperClass 是 private 的,外部无法访问
}
}
分析:
MySuperClass是SubClass的一个私有实现细节,外部世界只知道SubClass,不知道也不关心MySuperClass的存在。- 这种方式提供了更强的封装性,并且内部类可以直接访问外部类的成员(如果需要)。
- 适用场景:当你不仅需要隐藏父类的实现,还想让这个隐藏的实现能够访问外部类的私有成员时,这种方式很有用。
总结与对比
| 特性 | C++ private 继承 |
Java 组合 (Composition) | Java 内部类 |
|---|---|---|---|
| 核心思想 | "is-implemented-in-terms-of" (根据...实现) | "has-a" (有一个) | "has-a" (有一个,但更内聚) |
| 语法 | class Derived : private Base |
class SubClass { private SuperClass sc; ... } |
class SubClass { private class Inner extends SuperClass ... } |
| 访问控制 | Base 的 public/protected 成员在 Derived 中变为 private。 |
SuperClass 的方法仅通过 SubClass 提供的公共接口暴露。 |
内部类完全对外部隐藏。 |
| "is-a" 关系 | 不是 is-a 关系。 |
不是 is-a 关系。 |
不是 is-a 关系。 |
| 灵活性 | 较低,编译时绑定。 | 高,可以运行时替换组件。 | 较低,编译时绑定。 |
| 推荐度 | - | ★★★★★ (强烈推荐) | ★★★☆☆ (适用于特定场景) |
在 Java 中,当你想表达一种“我使用你的功能来完成我的事,但我不是一个你”的实现关系时,应该放弃使用 extends,你应该首选组合(Composition)的方式,因为它更清晰、更灵活,也更符合 Java 的设计哲学,内部类是实现组合的一种高级形式,适用于需要更强封装和内部访问的场景。
