类是对象的抽象,继承是面向对象的特点之一
拿一个学校来说,一个学校有必然有三类人,一类是学生,一类是教师,一类是员工。
定义一个学生类Student,属性可以有: 姓名,年龄,身高和学生编号。方法可以有: 吃饭,睡觉,讲话,学习
定义一个教师类Teacher,属性可以有: 姓名,年龄,身高,教师编号。方法可以有: 吃饭,睡觉,讲话,教学
定义一个员工类Employee,属性可以有: 姓名,年龄,身高,员工编号。方法可以有: 吃饭,睡觉,讲话,工作
这些类的方法和属性有很多重复,如果一一实现上述三个类多少有点繁琐,可以提取三者的共性,抽象出一个类
三者共同的东西: 人类,属性: 姓名,年龄,身高。方法: 吃饭,睡觉,讲话。
上述三个类都可以继承自这个人类,三者都具有人类的属性和方法,就无须在每个类中重复定义一些属性和方法了,提高了代码复用性。将人类这个类称为父类,基类或超类,将上述的三个类称为子类或派生类。
建立继承关系是在合理的范围中进行抽取,抽取出子类和父类的关系。
上面的案例中: 学生、员工和老师都是人,方法和属性上具有许多共同点,因此可以基于此抽象出一个基类。
实现基类Person
public class Person { private int age; // 年龄 private String name; // 姓名 private double height; // 身高 public double getHeight() { return height; } public void setHeight(double height) { this.height = height; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void eat() { System.out.println("Eating food"); } public void sleep() { System.out.println("Sleeping"); } public void talk() { System.out.println("Talking"); } }
实现学生类时就可以直接使用extends关键字继承自人类
public class Student extends Person { private int sno; // 学号 public int getSno() { return sno; } public void setSno(int sno) { this.sno = sno; } }
并且继承后可以额外实现属性和方法
在主类中创建Student对象
public class demo { public static void main(String[] args) { Student s = new Student(); s.setSno(1001); s.setName("Tom"); s.setAge(18); s.setHeight(1.78); System.out.println(s.getSno()); System.out.println(s.getName()); System.out.println(s.getAge()); System.out.println(s.getHeight()); } }
即使在Student中未定义上述的一些的方法和属性,但因为其父类Person实现了,所以其子类Student也具有了这些方法和属性,此处可见对父类代码的复用。
输出
1001 Tom 18 1.78
可见父类private修饰的属性,子类也继承了。
可见继承有几点好处:
提高代码的复用性,父类定义的内容,子类可以直接用,无须重复定义
便于代码的扩展
多态性的前提
有几个注意点:
一个子类只能有一个直接父类,也就是说只能直接继承一个
一个父类可以有多个子类
父类private修饰的内容,子类也继承
发生在子类和父类中,当父类的某个方法可以不满足子类的要求时,可对这个父类方法进行重写。重写有严格的格式要求,子类的方法名字和父类必须一致,参数列表(个数,类型,顺序)也要和父类一致。
public class Student extends Person { private int sno; // 学号 public int getSno() { return sno; } public void setSno(int sno) { this.sno = sno; } public void study() { System.out.println("Studying"); } public void eat() { System.out.println("Eating fish"); } }
如上在Student类中对方法进行重写
java中的 super 关键字是一个引用变量,用于引用直接父类对象
使用Super关键字来调用父类的东西
public void eat() { super.eat(); // 调用父类的eat函数 System.out.println("Eating fish"); }
这时就会多打印一行"eat food"
要注意的是,当子类和父类的属性或方法重名时,想要使用父类属性或方法就必须加上super。类中的构造器会默认调用父类空构造器。
如果构造器中已经显示的调用super父类构造器,那么空构造器就没有默认分配的super()了
在父类中定义构造函数
public class Person { private int age; private String name; private double height; public Person(int age,String name) { this.age = age; } public Person() { } public double getHeight() { return height; } public void setHeight(double height) { this.height = height; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void eat() { System.out.println("Eating food"); } public void sleep() { System.out.println("Sleeping"); } public void talk() { System.out.println("Talking"); } }
子类中使用super调用super调用父类构造器
public class Student extends Person { private int sno; // 学号 private int score; public int getSno() { return sno; } public void setSno(int sno) { this.sno = sno; } public void study() { System.out.println("Studying"); } public void eat() { super.eat(); System.out.println("Eating fish"); } public Student() { super(); } public Student(int age, String name,int score) { super(age,name); // 子类构造器调用父类构造器 this.score = score; } }