抽象类可以继承实体类吗?

本文探讨了Java中抽象类继承实体类的具体规则,特别是关于实体类构造函数的要求。通过实例解析了Java类继承机制中构造函数调用的细节。

一道java 常见面试题,网上找到的几乎每个 java 面试笔试题大全或集锦里都能找到这道题。

题目如下:

问: 抽象类是否可继承实体类 (concrete class)

答: 抽象类是可以继承实体类,但前提是实体类必须有明确的构造函数

答案很明确,可以继承。其实从Object就是个实体类,java的API文档里,每个抽象类的条目里都明确写着直接或间接继承自Object,所以这点是没有疑问的。

关键在于这答案里所说的“前提是实体类必须有明确的构造函数”一句,是什么意思。

一般学习者会写的简单试验代码:

class A{}

abstract class B extends A{}

结果完全正常,编译通过。似乎和“实体类必须有明确的构造函数”完全没有关系。

这个问题涉及到两个个基础知识:

1.

所有的class都必须有一个构造方法,如果你没有在代码里声明构造方法,系统会自动给你生成一个公有无参的构造方法。而只要你自己声明了一个构造方法,无论有参无参,私有公有,系统就不再帮你生成默认无参构造器了。

2.

所有的子类构造器都要求在第一行代码中调用父类构造器,如果不写,系统默认去调用父类的无参构造器。

所以,如果把系统默认配给的方法也算进去,class A{}的代码实际上是

class A{

public A(){}

}

B继承 A 的时候,则是

abstract class B extends A{

public B(){

super();

}

}

要试验出这继承规则的内部情况,也很简单,在最上面那个简单试验代码里,加上个私有构造器,有参无参都行。

class A{

private A(){}

}

这个时候,如基础知识(1) 中所说,系统不再给你默认无参构造器, B的构造器根据(2)中的规则去调用super(),却找不到A的无参构造器,所以导致abstract class B extends A{} 编译不能通过。(因为A中没有任何构造器可供子类调用,其实这个时候A只能够供内部类继承,我用的Eclipse的3.4版本会建议给B改名,但是这解决不了这个问题。)

现在,你应该了解了资料给的那句语焉不详的“实体类必须有明确的构造函数”的含义:

1.没写构造器的,那是拥有默认无参公有构造函数的,子类可以什么都不写,让默认构造器去调用它。这是最初那两行代码的情况。

2.写了子类可访问的无参构造器的,也是一样,子类里可以什么都不写,用默认机制调用。

3.写了 有参构造器却没写无参构造器的,父类里没有子类可访问的无参构造器,子类必须在子类构造器里的第一句写明,调用父类有参构造器,并把参数传进去。

4.声明为final的以及所有构造器都不在子类访问权限之内的类无法继承

其实只要是在类的继承中,无论抽象还是实体,都需要符合这个规则的。在这个继承试验中随时删掉或是加上abstract的前缀,结果都没有变化。个人觉得“实体类必须有明确的构造函数”一句实在是无法把这个情况表达清楚,所以广大求职者还是写得清楚些好。

我喜欢的写法是“可以继承,但是和实体类的继承一样,也要求父类可继承,并且拥有子类可访问到的构造器。”


<think> 我们正在讨论Java中的类继承问题。用户之前询问了关于父类未加public的原因,现在用户的新问题是:“非抽象类是否可以被继承”。我们需要参考用户提供的引用内容,并结合Java知识来回答。 引用[1]提到C#中接口继承抽象类实现接口和抽象类继承实体类的情况,但用户现在关心的是Java中非抽象类是否可以被继承。 引用[2]明确指出Java中抽象类可以被继承(用abstract关键字修饰的类,是包含一个或多个抽象方法的类,也可以包含非抽象方法)。 在Java中,非抽象类(即普通类)是可以被继承的,除非这个类被声明为final。因为final类不能被继承。 因此,回答要点: 1. 在Java中,非抽象类(普通类)可以被继承,除非它被声明为final。 2. 继承抽象类时,子类会自动继承父类的非私有成员(public, protected, 以及默认访问修饰符且同一包下的成员)。 3. 如果父类没有无参构造函数,子类构造函数需要通过super调用父类的有参构造函数。 但注意:引用[1]虽然讨论的是C#,但关于类继承的基本概念在Java和C#中是相似的。引用[2]则明确说明抽象类可以被继承,同样普通类也可以被继承。 因此,我们可以这样回答: ### 非抽象类是否可以被继承? 在Java中,**非抽象类(即普通类)可以被继承**,除非该类被`final`关键字修饰。以下是具体说明: 1. **普通类的可继承性**: - 普通类默认可以被继承,不需要任何特殊关键字(与抽象类不同,抽象类需要用`abstract`修饰)。 - 例如: ```java class Parent { // 普通父类 public void display() { System.out.println("Parent method"); } } class Child extends Parent { // 继承Parent // 可以添加新方法或重写父类方法 } ``` 这里`Child`类继承了`Parent`类,并可以使用其`display`方法。 2. **阻止继承:final类**: - 如果类被声明为`final`,则无法被继承。这是Java出于安全或设计考虑提供的机制[^2]。 ```java final class CannotInherit { // final类,禁止继承 // ... } // class TryExtend extends CannotInherit { } // 编译错误 ``` 3. **继承的规则**: - **成员继承**:子类自动继承父类的非私有成员(`public`、`protected`以及默认访问级别且在同一包内的成员)。 - **构造函数**:子类构造函数必须调用父类构造函数(通过`super()`),如果父类没有无参构造函数,子类必须显式调用父类的有参构造函数。 ```java class Parent { private String name; public Parent(String name) { this.name = name; } } class Child extends Parent { public Child(String name) { super(name); // 必须调用父类有参构造 } } ``` 4. **与抽象类的区别**: - 抽象类(`abstract class`)可以包含抽象方法(无实现),普通类不能包含抽象方法。 - 抽象类必须被继承才能实例化(通过子类),而普通类可以直接实例化。 - 但两者在“可被继承”这一点上是相同的,除非它们被声明为`final`。 总结: **非抽象类在Java中可以被继承**,这是面向对象的基本特性。除非使用`final`修饰符显式禁止继承。设计类时应根据需求决定是否允许继承,以控制扩展性和封装性。 §§相关问题§§ 1. Java中final关键字有哪些用法? 2. 如何正确重写父类的方法? 3. 抽象类和普通类在继承时有哪些不同? </think> ### 非抽象类是否可以被继承? 在面向对象编程中(包括Java、C#等语言),**非抽象类(普通类)是完全可以被继承的**,这是面向对象继承机制的核心特性之一。以下是关键要点: 1. **继承机制的本质** 继承允许子类获得父类的属性和方法(非private成员)。无论父类是抽象类还是普通类,只要满足以下条件: - 父类未被`final`修饰(Java/C#中final类不可继承) - 子类与父类在可访问范围内(如Java中非public类只能被同包类继承) 示例(Java): ```java class Animal { // 普通父类(非抽象) public void eat() { System.out.println("Animal eating"); } } class Cat extends Animal { // 继承普通类 @Override public void eat() { System.out.println("Cat eating fish"); } } ``` 2. **与抽象类的区别** 虽然抽象类和非抽象类都可被继承,但二者有本质差异: | **特性** | **非抽象类** | **抽象类** | |------------------------|--------------------|--------------------| | **能否直接实例化** | ✓ 可实例化 | ✗ 不可实例化 | | **是否需实现抽象方法** | 不包含抽象方法 | 子类必须实现 | | **继承限制** | 无特殊限制 | 必须被子类继承 | 3. **继承普通类的优势** - **代码复用**:直接继承已实现的完整功能 - **渐进扩展**:子类只需添加或修改特定方法 - **多态支持**:父类引用可指向子类对象(如`Animal a = new Cat()`) 4. **注意事项** - **构造方法**:子类需通过`super()`调用父类构造函数[^1] - **访问控制**:子类不能继承父类的private成员 - **final类**:被`final`修饰的类禁止继承(如Java的String类) ### 总结 **非抽象类可以被正常继承**,这是实现代码复用和多态性的基础。设计时应遵循: 1. 优先通过继承复用已有功能 2. 使用`@Override`注解确保正确重写方法 3. 避免过度继承导致层级过深(组合优于继承
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值