转帖:
http://blog.csdn.net/ckw1988/archive/2009/10/07/4639514.aspx
关于“抽象类是否可继承实体类”的辨析。
一道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的前缀,结果都没有变化。个人觉得“实体类必须有明确的构造函数”一句实在是无法把这个情况表达清楚,所以广大求职者还是写得清楚些好。
我喜欢的写法是“可以继承,但是和实体类的继承一样,也要求父类可继承,并且拥有子类可访问到的构造器。”
---------------------
如果有哪位朋友发现本文的纰漏,还望不吝赐教。在此谢过。
分享到:
相关推荐
根据给定的信息,我们可以深入探讨C++中的抽象类与继承机制。...综上所述,通过合理的抽象类设计和继承机制,可以有效地提高代码的可维护性和扩展性,同时也能更好地支持面向对象编程中的多态特性。
在这个系统中,"表面积和体积_抽象类Shape_shape类继承_"这个主题涉及到的是OOP中的一个重要概念——抽象类和类的继承。 首先,让我们来理解抽象类(Abstract Class)。抽象类是一种特殊的类,它不能被实例化,主要...
3. **继承性**:抽象类可以被其他类继承,一个类可以继承多个抽象类的功能(通过多层继承实现)。 4. **方法实现**:抽象类中的非抽象方法具有实际的实现,而抽象方法需要由子类提供实现。 #### 四、接口 **定义**...
"Java抽象类和接口和继承之间关系" Java抽象类和接口是两种不同的概念,它们之间存在着继承关系。在Java中,抽象类(abstract class)和接口(interface)都是用来描述对象的行为和状态的,但它们之间有着明显的...
抽象类是一种不能被实例化的类,它用于定义共同接口,供其他类继承。在C#中,我们使用`abstract`关键字声明抽象类。例如,我们可能有一个`Animal`抽象类,其中包含一个抽象方法`MakeSound()`: ```csharp public ...
在编程世界中,继承、虚函数和抽象类是面向对象编程(OOP)中的核心概念。这三者共同构建了类的层次结构,使得代码更加模块化,易于维护和扩展。接下来,我们将深入探讨这三个概念及其相关用法。 首先,**继承**是...
本主题将深入探讨如何使用普通类、接口和抽象类来实现这些继承方式,并应用到“增、删、改、查”(CRUD,Create, Read, Update, Delete)操作中。 首先,单继承是指一个子类只能继承一个父类的特性。这种方式使得...
类可以分为抽象类和具体类,以及主动类和非主动类。 1. **抽象类与具体类**: 抽象类(abstract classes)是一种特殊的类,它通常包含了抽象方法(即没有实现的方法)或者没有完全定义的行为。抽象类不能直接实例...
Java 类、抽象类、接口和继承是面向对象编程的核心概念,它们构成了 Java 语言的基石。在 Java 中,类是用来封装数据和行为的结构,而对象则是类的实例,具有具体的属性和行为。 1. **类与对象的区别** 类是模板...
任何继承自`Animal`的类都必须提供`makeSound()`的具体实现,除非它们也是抽象类。 接口则更侧重于定义行为规范。它是一个完全抽象的类型,包含一组无实现的方法声明。接口使用`interface`关键字声明,如: ```...
在这个例子中,`Dog`类继承了`Animal`抽象类,并提供了`MakeSound`方法的具体实现。使用`override`关键字确保了`Dog`类覆盖了`Animal`类中的抽象方法。 C#中的抽象类还有以下几点需要注意: 1. **抽象类不能被实例...
然后,我们可以定义一个抽象类 B,继承自类 A,并且也继承了抽象方法 E: public abstract class B : A { //因为类 B 继承了类 A 中的抽象方法 E,所以类 B 也变成了抽象类 } 最后,我们可以定义一个具体类 C,...
1. **抽象类**:抽象类是一种不能被实例化的类,它可以包含抽象方法(没有实现的方法)和具体方法(有实现的方法)。抽象类的主要目的是为子类提供一种共有的基本结构,子类必须实现所有抽象方法才能被实例化。 2....
抽象类的主要目的是提供一个基类,以便其他类继承并实现其抽象方法或重写其具体方法。抽象类通过使用`abstract`关键字进行声明。 #### 特性 - 抽象类可以包含抽象方法和非抽象方法(具体方法)。 - 可以包含构造器...
总的来说,虽然Java中的抽象类不能直接实例化,但我们可以通过继承并实现其抽象方法,或者利用字节码工具和注解处理器在运行时或编译时动态生成新的类来间接达到实例化抽象类的目的。这样的设计允许我们创建更加灵活...
子类继承抽象类时,必须提供抽象方法的具体实现,除非子类本身也是抽象类。如果子类没有实现所有抽象方法,那么子类也必须声明为抽象的。 4. **final类与抽象类** `final`关键字用于防止类被继承,而抽象类是设计...
抽象类在计算机编程,尤其是面向对象编程中,是一种重要的概念,它用来表示一种不完整的类,其中包含了未实现的方法,通常用于定义一个...理解并熟练运用抽象类和适配器模式,对于编写高效、可扩展的Java代码至关重要。
通过这些理解,我们可以更好地利用抽象类和接口来设计灵活且可扩展的软件架构。在选择使用抽象类还是接口时,应根据项目需求和设计原则来权衡。例如,如果需要共享部分实现并有继承关系,可以选择抽象类;如果需要多...
3. **不能密封**:抽象类不能用`sealed`关键字修饰,这意味着它们可以被继承。 4. **派生类的义务**:如果一个非抽象类从抽象类派生,它必须实现抽象类中的所有抽象成员,除非它自己也是抽象类。 接下来,我们来看...