第六章继承
继承是面向对象编程的重要特征之一。继承就是在现有类的基础上构建新类以满足新的要求。在继承过程中,新的类继承原来的方法和实例变量,并且能添加自己的方法和实例变量。
6.1子类(派生类)
面向对象语言的一个重要特性就是继承。继承是指声明一个类,可以再进一步声明这些类的子类,子类具有父类已经拥有的一些方法和属性,这与现实中的父子关系有点像,所以面向对象把这种机制称为继承,子类也称为派生类。
6.1.1继承的使用
继承就是在现有类的基础上构建新类,已有类称为超类、父类或者基类,产生的新类是子类或派生类。使用关键字extends比如:
public class Animal{ String name; int age; public void eat(){ System.out.println("动物吃饭"); } } public class Bird extends Animal{ String wing; void fly(){ System.out.println("鸟会飞"); } public void eat(){ System.out.println("鸟吃食");//方法重写 } } --------------------------------测试-------------------------------------------- public class TestBird{ public ststic void main(String[] args){ Bird bird = new Bird(); bird.fly(); bird.age = 2; bird.eat();//调用的是Bird类里的eat方法(父类子类都有eat方法,在调用子类的对象的方法时,会直接调用子类的方法) } }
6.1.2子类对象的构建
Java中不支持多继承,一个类的直接父类只能有一个。
子类对象的创建过程是宠最顶层的基类开始往下一层层的调用默认构造函数。如:
class A{ A(){ System.out.println("调用A的构造函数"); } A(int i){ System.out.println("调用A的有参构造函数"); } } //类B继承A class B extends A{ B(){ //super(1); System.out.println("调用B的构造函数"); } } public class CallConstructor{ public ststic void main(String[] args){ B b = new B(); } } //super(1);注释这一行那运行结果就是先调用A的构造函数,在调用B的构造函数 如果想调用父类的有参构造函数,使用super关键字。打开super(1);运行结果就是先调用A的有参构造函数,在调用B的构造函数
6.1.3方法的重写
覆写(override)是指可以重新写一个和父类中方法名参数都一样的方法,在子类中调用该方法时将会调用子类里重写的这个方法,要想在调用父类中的方法只能使用super关键字才可以。
与重载(overload)的相同点是方法名是一样的,区别在于覆写是重新写父类中的方法,重载是一个类里面的方法参数不一样。覆写举例:
class Parent{ void method(){ System.out.println("父类中的方法"); } } class Child extends Parent{ void method(){ super.method();//这里是super的第二种方法,直接调用父类的函数 System.out.println("子类中的方法"); } } public class OverrideDemo{ public ststic void main(String[] args){ Child child = new Child(); child.method(); } }
6.1.4多态与动态绑定
多态是面向对象语言的又一重要特性。多态是指同一种方法根据上下文使用不同的定义的能力。从这一点上看方法覆写和方法重载都可以看做是多态。
动态绑定是一种机制,通过这种机制,对一个已经被重写的方法的调用将会发生在运行时,而不是在编译时解析。比如:
class P{ void method(){ System.out.println("父类中的method"); } } class C extends P{ void method(){ System.out.println("子类中的method"); } void method1(){ System.out.println("子类中的method1"); } } public class DuotaiDemo{ public ststic void main(String[] args){ P c = new C(); c.method(); //c.method1();是不允许的 //((C)c).method1(); } } 注意这一句P c = new C();对象c是父类P类型,实例化的时候用的是子类C.所以c.method1();是不允许的,只有强制类型转换父类为子类((C)c).method1();才可以调用method1() <P c = new C();>这句代码Java中经常使用 不注释((C)c).method1();运行结果是子类中的method1 注释((C)c).method1();运行结果是只会调用 子类中的method
6.2抽象类
抽象类是指在类中定义方法,但是并不去实现它,而是在它的子类中去具体的实现。定义的抽象的方法不过是一个方法占位符。继承抽象类的子类必须实现父类的抽象方法,除非子类也被定义为一个抽象类。
定义抽象类通过关键字abstract实现。在抽象类中的方法不一定是抽象方法,但是含有抽象方法的类必须被定义为抽象类。
定义
-----------------------------这是子类不实现父类抽象方法。--------------------------- public class Animal{ String name; int age; public abstract void eat(); } public abstract class Bird extends Animal{ String wing; void fly(){ System.out.println("鸟会飞"); } } -------------------------------这是子类实现父类抽象方法。--------------------------- public class Animal{ String name; int age; public abstract void eat(); } public class Bird extends Animal{ String wing; void fly(){ System.out.println("鸟会飞"); } @Override public void eat(){ System.out.println("鸟吃食");//方法重写 } }
使用
抽象类不可以实例化,比如Animal animal = new Anima();这是无法编译通过的,但是可以创建抽象类的对象变量,只是这个变量只能用来指向它的非抽象子类对象,注意该抽象类变量不可以调用抽象类中没有的方法。比如:
public class TestBird{ public ststic void main(String[] args){ //Animal animal = new Animal();错误 因为这个变量只能用来指向它的非抽象子类对象 Animal bird = new Bird(); //bird.fly();错误 fly是抽象子类中没有的方法 需要类型转换 ((Bird)bird).fly(); bird.age = 2; bird.eat();//调用的是Bird类里的eat方法(父类子类都有eat方法,在调用子类的对象的方法时,会直接调用子类的方法) } }
6.3Object类
Object类是所有类的祖先类。在Java中如果定义了一个类并没有继承任何类,那么它默认继承Objec类。如果继承了一个类,则它的父类甚至是父类的父类必然是继承自Objec类,所有说任何类是Object类的子类。
Object对象
定义一个Object对象,根据继承的知识,它可以存放任何类型:
public class ObjectTest{ public ststic void main(String[] args){ Object object1 = new Bird(); //要使用具体对象Bird子类的方法必须强制类型转换 ((Bird)object1).eat(); } }