Java继承与多态
基本概念
被继承的类称为基类或父类或超类,而新的类被称为派生类或子类。
一般把基类和派生类实例的集合称作类继承层次结构。
Java中的类只支持单一继承(即一个类只有一个父类)。
在需要多重继承的场合,可以使用接口机制来实现。
子类会自动继承父类中的非private成员(是否继承静态成员??)。但不会继承父类中的构造方法。
继承是可以传递的,如 类B继承类A,类C又继承类B,类C相当于拥有了类A中的可继承的那些成员,这些继承而来的成员就好像在类C中定义的一样。
属性隐藏和方法覆盖
当子类的成员属性和父类的成员属性同名时(和属性的类型无关),称为父类的成员属性(变量)被隐藏。
当子类的成员方法和父类的成员方法同名时(和属性的类型无关),称为父类的成员方法(行为)被覆盖。
子类中的同名属性允许与父类的同名属性在 访问权限、数据类型、常/变量(final)、实例/静态 等方面完全不同,最终以子类的属性特性为准。
所以,对于属性,只要同名就能隐藏,没有任何限制。
覆盖必须满足两个条件: 1. 方法名称必须相同 2. 返回值类型必须相同,方法的参数必须完全相同,包括参数的个数、类型、顺序。
如果只满足第1条而不满足第二条,则是方法的重载。
覆盖时,子类方法的访问权限必须不比父类中同名方法更严格,否则报错(注意是报错,而不是方法重写)。 例如 父中为public ,则子类中覆盖时也必须是public。
如果父类中的方法是一个final方法,则子类对其进行覆盖会报错。如果父类中的方法不是final方法,在子类中可以覆盖为一个final方法。
不允许父类方法和子类方法在覆盖时,static 修饰符发生变化,否则报错(注意是报错,而不是方法重写)。
覆盖也是多态的表现。覆盖需要在运行代码的时候确定调用的是哪个方法。
继承中的构造方法
所有的构造函数都不会被继承。
假设类B继承类A:
1. 如果类B中一个构造方法也没有显示定义,则系统会自动给类B添加一个不带参数的构造方法。
2. 当调用B中的某个构造方法B(...)时(创建B对象时),必然会调用其父类A的某个构造方法来创建A类对象。
如果 B(...)中没有显示调用 super(...);
或 this(...);
, 则自动在方法体的行首添加 super();
(而不是报错)。
如果显示调用了,则什么也不做。注意,如果调用了this(....),就可能在另一个构造函数中调用了super(...)
其中 super 代表父类的构造函数, this 代表本类的构造函数。
super
当super作为方法调用时:
1. 只能在构造方法中调用 super(....)
2. super只能是构造方法中的第一条语句。
3. 一个构造方法中,最多只能有一个super方法调用。
使用 super.父类成员名
可以引用或修改父类成员的属性值 或 调用父类的成员方法。
继承的内部处理
假设类B继承类A:
当创建B类对象时,同时也会新创建一个A类对象,再新创建A的父类, .... , 一直到创建 Object类的对象。 这样就形成一个链条,称为原型链或作用域链。
当 A对象.成员 时,会从A类对象开始,在原型链上依次查找,直到找到第一个同名成员。
原型链上的所有对象,均是完整的对象,每个对象对应类中定义的所有成员都存在于这个对象上,只是这些成员是否对子类可见或不可见而已。
多态:重载
多态是指一个名字拥有多种语义。
一个类中,允许多个方法拥有相同的名字,但参数列表必须不一样,能在调用时根据实参列表推算出应该调用哪个方法,这就是重载。
重载的一组方法必须满足: 1. 方法名相同 2. 参数个数 或 对应位置上的参数类型 不同
不允许参数列表完全相同,仅返回值类型不同的情况出现,否则报错。
重载的过程中区分调用哪个方法是在编译时确定的,所以重载是一种静态绑定的技术。
构造方法也可以重载。
两个方法是否是重载关系,只看规则1和2。不关注 前面的修饰符(也就是说,不管前面出现什么样的修饰符,都可以重载,也不影响重载)。
重载发生在同个类中,或者父类与子类中。
运行时多态
当方法被调用时,系统根据对象本身所属的类来确定调用哪个方法,这种技术称为后期(动态)绑定。
设 类A是类B的父类,在类B中隐藏了实例属性 realHideA,隐藏了静态属性 staticHideA,覆盖了实例方法 realCoverFn(),覆盖了静态方法 staticCoverFn()。
当有代码: A test = new B();
或者 B b = new B(); A test = b;
时
test.realHideA test.staticHideA test.staticCoverFn() 访问的属性和方法是类A中的,而 test.realCoverFn() 则是访问的类B中的方法。
也就是实例属性、静态属性、静态方法,在访问时,是根据这个变量的类型来确定的究竟访问的是哪个类上的。
综上,只有实例方法被覆盖时,才会表现出运行时多态。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?