继承的本质:复用已存在的方法和域
一、概念:
继承是java面向对象编程的基石,继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
public class Person { public void run() { System.out.println("任何人都可以跑。。。"); } } class Student extends Person{ private void eat() { System.out.println("学生正在吃。。。。"); } public static void main(String[] args) { Student student = new Student(); student.run(); student.eat(); } }
由以上代码我们可以看出:关键字extends表明正在构造的新类Student派生于一个已经存在的类Person,已存在的类称为超类或者父类;子类称为子类。我们还可以看出子类可以调用父类的方法,而且子类可以拥有自己的方法,功能比超类更丰富
(子类可以调用父类的方法,但是父类不能调用子类的方法)
二、明确方法重载和方法重写
1.方法重载
方法重载:在一个类里面出现多个方法名字相同,参数不同便会产生方法重载。
public void method() { System.out.println("1"); } public void method(String a) { System.out.println("1"); } public void method(int a) { System.out.println("1"); } public void method(int a,int b) { System.out.println("1"); }
方法重写:在有些时候,子类当中需要调用父类当中的方法,但是父类当中的方法对子类来说并不一定适用。这个时候我们就需要使用到方法的覆盖。在子类中重写父类方法
//父类 public class Person { public void run() { System.out.println("任何人都可以跑。。。"); } } //子类 public class Student extends Person { public void run() { System.out.println("学生都可以跑"); } }
我们可以看到子类和父类当中都有run方法,而我们实际调用的却是子类自己的run方法,这就是方法的覆盖,子类通过重写和父类一样的方法实现方法的覆盖。
2.方法覆盖
在有些时候,子类当中需要调用父类当中的方法,但是父类当中的方法对子类来说并不一定适用。这个时候我们就需要使用到方法的覆盖。
//方法的覆盖 //子类和父类当中都有相同的方法, //子类通过重写父类方法实现方法的覆盖 public void getRun() { System.out.println("所有小猫杜能跑。。。。"); } //一个方法的签名是由方法名称以及参数列表所组成 //方法的重载是指在一个类当中有相同的方法名不同的参数列表 public void getRun(int s) { System.out.println("所有小猫杜能跑。。。。"+s); } public static void main(String[] args) { Cat cat = new Cat(); cat.getRun(); }
三、super关键字
super 关键字有两个用途:一是调用超类的方法,二是调用超类的构造器。调用构造器语句的时候只能作为另一个构造器的第一条语句出现。
四、继承层次
java只支持单继承
继承并不限于一个层次。
public class Person { public void run() { System.out.println("任何人都可以跑。。。"); } } class Student extends Person{ public void run() { super.run(); System.out.println("这个学生在跑。。。"); } private void eat() { System.out.println("学生正在吃。。。。"); } public static void main(String[] args) { Student student = new Student(); student.run(); student.eat(); } } class XiaoMing extends Student{ } class XiaoHong extends Student{ }
由一个公共超类派生出来的所有类的集合被称为继承层次,在继承层次当中,从某个特定的类到其祖先的路径被称为继承链,但是一定要注意java是单继承的。
五、类的加载顺序
public class Test extends Base{ static{ System.out.println("test static"); } public Test(){ System.out.println("test constructor"); } public static void main(String[] args) { new Test(); } } class Base{ static{ System.out.println("base static"); } public Base(){ System.out.println("base constructor"); } } /* base static test static base constructor test constructor*/
先来想一下这段代码具体的执行过程,在执行开始,先要寻找到main方法,因为main方法是程序的入口,但是在执行main方法之前,必须先加载Test类,而在加载Test类的时候发现Test类继承自Base类,因此会转去先加载Base类,在加载Base类的时候,发现有static块,便执行了static块。在Base类加载完成之后,便继续加载Test类,然后发现Test类中也有static块,便执行static块。在加载完所需的类之后,便开始执行main方法。在main方法中执行new Test()的时候会先调用父类的构造器,然后再调用自身的构造器。因此,便出现了上面的输出结果。
public class Demo { public Demo(String aa){ System.out.println("===="+aa); } static { System.out.println("11"); } public static Demo demo = new Demo("+++"); static { System.out.println("22"); } } class Test{ public static void main(String[] args) { Demo demo = new Demo("----"); } } /* 11 ====+++ 22 ====---- */
所有的静态的类的初始化都交给类的第一个对象去执行