一.什么是继承?
在 Java 中,继承是面向对象编程的一个重要特性。
继承允许一个类(称为子类或派生类)获取另一个类(称为父类或基类)的属性和方法。通过继承,子类可以复用父类的代码,并且可以在父类的基础上添加新的属性和方法,或者修改父类的方法实现(方法重写),继承使用 extends
关键字来实现。
例如:
这个代码就表示了cat类继承了animal类。
二.继承的一些特性
1.继承的特点
子类继承父类时,子类可以使用父类除了构造方法外的所有方法。子类可以有父类的内容,子类还可以有自己特有的内容。
注意:
在 Java 中,父类中的 private
方法不能被直接访问,包括子类。private
修饰符限制了方法的访问范围仅限于其所在的类内部。
如果您希望在子类中使用父类的某些功能,可以通过以下方式:
-
如果父类中的方法是
protected
或public
,则子类可以直接访问或调用。 -
对于父类中被私有化但又希望在子类中使用的逻辑,可以在父类中创建
protected
或public
的方法来调用这些private
方法,然后子类通过调用父类提供的这些方法间接使用相关逻辑。总之,按照 Java 的访问控制规则,无法直接访问父类中的private
方法。 -
也无法通过实例化对象访问static修饰的方法。
父类中有两个方法eat和fire方法。
子类通过实例化对象cat就可以直接调用父类中的方法。
但当有private和static是就无法通过子类实例化对象访问了。
如图此时无法访问那两个方法了,private被限制在animal类中访问,而static进入了animal类的方法区中,需要通过类名来调用。
2.继承的优缺点
继承在 Java 中的优点包括:
- 代码复用:子类可以直接使用父类中已有的属性和方法,减少了代码的重复编写,提高了开发效率。
- 易于扩展:通过继承,可以在父类的基础上添加新的功能和特性,方便地扩展系统的功能。
- 统一接口:父类可以定义一组公共的方法和属性,使得子类具有一致的行为和接口,增强了代码的可读性和可维护性。
- 层次结构清晰:能够建立清晰的类层次结构,反映出类之间的关系,便于理解和管理复杂的系统。
然而,继承也存在一些缺点:
- 强耦合:子类与父类紧密耦合,如果父类发生改变,可能会影响到所有的子类,增加了维护的复杂性。
- 有限的灵活性:有时继承关系可能限制了代码的灵活性,某些情况下组合可能更适合解决问题。
- 破坏封装:子类可能意外地依赖于父类的实现细节,从而破坏了父类的封装性。
- 钻石问题:在多重继承(Java 不支持,但在其他语言中存在)中可能出现“钻石问题”,导致歧义性和复杂性。
在实际开发中,需要根据具体的需求和场景来权衡是否使用继承,以及如何合理地设计继承关系。
3.super关键字
super 关键字的用法和 this 关键字的用法相似
- this:代表本类对象的引用(this关键字指向调用该方法的对象一般我们是在当前类中使用this关键字所以我们常说this代表本类对象的引用)
- super:代表父类存储空间的标识(可以理解为父类对象引用)
- 但需要注意的是this和super都无法在静态方法中使用。
- 可以直接调用父类中的成员。
- 如图super无法在静态中方法中被使用,也无法调用private修饰的方法。
4.访问权限关系图
派生类就是那些互相有联系的类,例如继承等。
这种就成为类。
这就称为包。
5.继承中构造方法的访问特点
当都没有写构造方法时,Java虚拟机会自动产生一个无参的构造方法,但当你写了构造方法,Java虚拟机就不会再提供构造方法了。
没有构造方法,Java虚拟机自动提供了。
这就证明提供了父类的无参构造方法。
但当你提供完之后,就又出现了两个问题。
我们看一下逐个解决一下。
第一个就是咱上面所说到的父类中有有参构造方法了,此时无参构造方法就被Java虚拟机收回了,我们得实例化带一个参数的构造方法。
第二个问题就是子类继承父类时,父类只要没有无参构造方法,就必须初始化一下父类的有参构造方法中内容。
第一个解决办法:添加无参构造方法。
此时就不报错了。
第二种解决方法:实例化带参的方法,再初始化父类的有参构造方法。
通过super关键字实例化父类的构造方法,下面再给实例化父类对象一个参数。
6.方法的重写
在 Java 中,方法的重写(Override)是指子类中的方法与父类中的某个方法具有相同的方法名、参数列表和返回类型,从而覆盖父类方法的实现。
方法重写需要满足以下规则:
-
方法名相同:子类重写的方法与父类被重写的方法名称必须完全相同。
-
参数列表相同:参数的个数、类型和顺序必须与父类被重写的方法完全一致。
-
返回类型相同或子类型:返回类型要么与父类被重写的方法相同,要么是父类返回类型的子类型(对于 Java 5 及以后的版本,支持协变返回类型)。
-
访问权限不能更严格:子类重写方法的访问权限不能小于父类被重写方法的访问权限。例如,如果父类方法是
protected
,子类重写的方法不能是private
。
方法重写的主要目的是在子类中根据具体的需求对父类的方法进行修改或扩展,以实现更具体或更适合子类的行为。
@Override是一个注解可以帮助我们检查重写方法的方法声明的正确性。(可加可不加)
下面是一个简单的重写方法的例子。
子类重写了父类的eat方法,当子类实例化对象调用eat方法时,调用的是子类的eat方法。
注意:就是当子类和父类的任何东西相同时,子类的实例化对象都优先调用自己的方法,遵循一个相当于就近原则。
7.重写方法的注意事项
在进行方法重写时,有以下一些注意事项:
-
访问修饰符:重写方法的访问修饰符不能比被重写方法更严格。例如,父类方法是
public
,子类重写的方法不能是protected
或private
。 -
静态方法不能被重写为非静态方法,反之亦然。因为静态方法属于类,而非静态方法属于对象实例。
-
重写方法不能抛出新的检查型异常,或者比被重写方法声明的检查型异常范围更广。可以抛出更少或相同的异常。
-
父类的私有方法不能被重写,因为私有方法对子类不可见。
-
重写方法时,方法的参数列表必须与被重写方法完全相同,包括参数的数量、类型和顺序。
-
重写的方法返回值类型要与被重写方法的返回值类型相同或是其子类。
-
8.继承中的注意事项
在 Java 继承中,有以下一些重要的注意事项:
-
单一继承原则:Java 只支持单继承,即一个类只能直接继承自一个父类,但可以实现多个接口。
-
构造函数调用顺序:创建子类对象时,会先调用父类的构造函数(默认或有参数的)进行父类部分的初始化,然后再执行子类的构造函数。
-
成员变量的隐藏:如果子类中有与父类同名的成员变量,子类对象访问该变量时,使用的是子类中的变量,父类中的同名变量被隐藏。
-
方法重写的规则:如前面提到的,要满足方法名、参数列表、返回类型、访问修饰符和异常等方面的规则。
-
向上转型和向下转型:向上转型(把子类对象赋值给父类引用)是安全的,但向下转型(把父类引用强制转换为子类引用)需要进行类型检查,否则可能会抛出
ClassCastException
异常。 -
避免过度继承:继承层次不宜过深,否则会增加代码的复杂性和维护成本。
-
谨慎修改父类:修改父类的行为可能会影响到所有的子类,所以对父类的修改要非常谨慎。
-
考虑使用组合代替继承:在某些情况下,组合(通过包含其他类的对象来实现功能)可能比继承更灵活和合适。
-
注意父类和子类的初始化顺序:父类的静态成员和静态初始化块先于子类执行,然后是父类的实例成员和实例初始化块,最后是子类的静态成员、静态初始化块、实例成员和实例初始化块。 结束语
感谢大家的查看,希望可以帮助到大家,做的不是太好还请见谅,其中有什么不懂的可以留言询问,我都会一一回答。 感谢大家的一键三连。