和现实世界中:子女能够继承父母的一些特征(如:基因)、财产等同样。OOP 中也有提供相似的特性,一个类彻底能够从其它类里得到一些属性和方法,而不须要咱们本身从新定义。这种特性简单但强大 (Simple and powerful)。java
在 Java 的继承关系里:子类能够从获取父类的全部的公共和受保护成员(字段、方法和内部类)。固然,构造方法不是成员 (members) ,因此不能被继承。同时,在 Java 的继承里,子类能够作以下事情:安全
当子类拥有和父类(或接口)一样方法签名的方法,这种现象叫作覆盖。如如下代码:ide
class Father { public void doSomthing(){ // Father do something } } class Son extends Father{ @Override public void doSomething(){ // Son do something } }
对于实例方法的覆盖,实际是子类拥有本身的方法。
对于静态方法的覆盖,要记住:静态方法时属于类的,在多态中,调用的始终是类的方法。接口里的静态方法永远不会被覆盖。优化
Father father = new Son(); Father.staticMethod(); // 这里使用的是父类Father的静态方法
对于接口方法的覆盖,遵循如下原则:
1.实例方法的优先级大于接口方法 (JDK8+)code
interface Animal{ default void saySomething(){ // Animal say something } } interface Cow extends Animal{ default void saySomething(){ // Cow say something } } class MyCow implements Cow{ @Override public void saySomething(){ // MyCow say something } Animal myCow = new MyCow(); myCow.saySomething(); // MyCow say something }
2.有共同祖先的接口,先被覆盖的方法(继承深度低)会被后覆盖的方法(继承级别高)覆盖对象
interface Animal{ default void saySomething(){ // Animal say something } } interface Pig extends Animal{ default void saySomething(){ // Pig say something } } interface BigPig extends Pig{ default void saySomething(){ // BigPig say something } } class MyPig implements Pig, BigPig{ public static void main(String...args){ MyPig myPig = new MyPig(); myPig.saySomething(); // BigPig saySomething() } }
P.S. 若是出现同一继承级别(上例中 BigPig 和 Pig 都继承 Animal 接口)或者子类继承的接口无相关关系,可是接口间有同方法签名的方法,就会出现覆盖冲突。须要用 super
关键字指明具体实现哪一个接口的方法或者直接覆盖。继承
interface Run{ default void run(){ // Run run } } interface Car{ default void run(){ // Car run } } class MyCar implements Run, Car{ @Override public void run(){ Car.super.run(); } }
同时,咱们须要注意,Java 子类覆盖父类方法,应该:接口
若是子类定义和父类同方法签名的方法,会有以下结果:ip
x | 父类的实例方法 | 父类的静态方法 |
---|---|---|
子类的实例方法 | 覆盖父类方法 | 编译错误 |
子类的静态方法 | 编译错误 | 隐藏父类方法 |
咱们已经知道,子类能够覆盖父类的方法。若是有一个类继承自另一个类,咱们彻底能够用一个父类来引用一个子类,如:get
class Person{ public void saySomething(){ // Person say something } } class Father{ @Override public void saySomething(){ // Father say something } } class Test{ pubilc static void main(String...args){ Father father = new Father(); Person person = father; // 父类引用子类对象 } }
像这种父类引用子类对象的现象,Java 里叫作多态 (Polymorphism)。在 Java 里,只有知足以下三个条件,才能叫多态:
对于多态方法的运行,编译器会列举全部父类和子类符合调用方法签名(方法名+参数列表)的方法,而后以如下原则编译、调用方法:
其中,调用 private, final, static 方法的过程叫静态绑定,不然叫动态绑定。
在使用多态的过程当中,最有效的判断语句可否经过编译的方法是:
右边的类是不是(IS-A)左边的类
如示例代码里的 father(Father) IS-A Person。
有些状况下,咱们可能不但愿子类覆盖父类的方法,这时候,用 final 关键字修饰方法便可实现该目的。编译器能够对用final的方法进行内联操做优化处理。
在多态里,咱们知道一个父类能够引用一个子类对象:
Father father = new Son();
可是,反过来就不行了:
Son son = new Father();
若是须要让编译器不报错,咱们就得进行强制类型转换操做:
Son son = (Son)new Father();
不过,这么作有风险,咱们通常要使用 instanceof
关键字先判断,可否将父类“安全”转换成子类:
Father f = ...; if (f instanceof Son){ Son son = (Son)f; }
在继承体系里,比较经常使用的就是抽象类和接口。它们比较类似:
然而,它们仍是有不一样的,例如:
而后,抽象类和接口有不一样的使用场景:P
抽象类:
接口:
在 Java 里,咱们通常按照以下规则使用继承:
is-a
原则