17-面向对象编程-继承
面向对象编程有三大特征:封装、继承和多态
访问修饰符可以控制属性的访问范围
public:表示公共访问级别,可以被任何类访问。
protected:表示受保护访问级别,可以被类本身、子类和同一包中的类访问。
default(缺省):表示默认访问级别,即如果没有使用访问修饰符,默认是此级别,可以被同一包中的类访问。
private:表示私有访问级别,只能在类内部访问。
修饰符
|
类
|
包
|
子类
|
其他包
|
---|---|---|---|---|
public
|
√
|
√
|
√
|
√
|
protected
|
√
|
√
|
√
|
×
|
default
|
√
|
√
|
×
|
×
|
private
|
√
|
×
|
×
|
×
|
继承介绍
继承可以解决代码复用问题,当多个类存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。
换句话说,继承就是类与类之间产生关系(子父类关系),子类可以直接使用父类中非私有的成员属性和方法。
继承的好处
代码的复用性提高了,同时代码的扩展性和维护性也提高了。
继承的基本语法
修饰符 class 子类 extends 父类{
}
1) 子类会自动拥有父类定义的属性和方法
2) 父类又称超类、基类,子类又称派生类
3) 不能同时继承多个类,只能继承一个类
public class Extends01 { public static void main(String[] args) { Pupil pupil = new Pupil("马铃薯1",6,100); pupil.testing(); //小学生正在考小学数学... pupil.showInfo(); //学生名:马铃薯1 年龄:6 成绩:100.0 Graduate graduate = new Graduate("马铃薯2",26,95); graduate.testing(); //大学生正在考高等数学... graduate.showInfo(); //学生名:马铃薯2 年龄:26 成绩:95.0 } } //父类 class Student{ //共有的属性 public String name; public int age; private double score; //父类构造方法 public Student(String name, int age, double score) { this.name = name; this.age = age; this.score = score; System.out.println("父类Student的构造方法"); } //共有的方法 public void setScore(double score){ this.score = score; } public void showInfo(){ System.out.println("学生名:" + name + "\t年龄:" + age + "\t成绩:" + score); } } //子类,小学生类 class Pupil extends Student{ //子类构造方法 public Pupil(String name, int age, double score) { super(name, age, score); System.out.println("子类Pupil的构造方法"); } //子类特有的方法 public void testing(){ System.out.println("小学生正在考小学数学..."); } } //子类,大学生类 class Graduate extends Student{ //子类构造方法 public Graduate(String name, int age, double score) { super(name, age, score); System.out.println("子类Graduate的构造方法"); } //子类特有的方法 public void testing(){ System.out.println("大学生正在考高等数学..."); } }
继承的使用细节
1. 子类继承了父类所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有的属性和方法不能在子类直接访问,要用通过父类提供的公共方法进行访问,例如 getXxx()方法。
2. 子类必须调用父类的构造器,完成父类的初始化
3. 创建子类对象时,不管使用子类的哪个构造器,默认情况总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super,去指定使用父类的哪个构造器完成对父类的初始化工作,否则编译不会通过。
4. 如果希望指定去调用父类的某个构造器,则显示的调用一下:super(参数列表)
5. super在使用时,必须放在构造器的第一行(super只能在构造器中使用)
6. Java所有类都是Object类的子类,也就是Object类是所有类的基类
7. 父类构造器的调用不限于直接父类,将一直往上追溯到Object类
8. 子类最多只能继承一个父类(指直接继承),即Java中的单继承机制
9. 不能滥用继承,子类父类之间必须满足 is-a 的逻辑关系
super() 和 this()
super() 是调用父类的构造器,this() 是调用本类的构造器,这两个都只能放在构造器的第一行,因此不能同时出现在一个构造器。
is-a 关系
is-a关系,表示子类和父类之间的继承关系
比如:一个Student类,继承了父类Person类,我们就可以说一个学生就是一个人,也就是Student is a Person。
继承的内存示意图
注意:这里需要注意的是,如果子父类中出现了重名的成员变量,使用的时候根据就近原则,优先使用子类的(如果一定要使用父类的,可以通过super关键字)
public class ExtendsDemo1 { public static void main(String[] args){ // 创建子类对象 Zi z = new Zi(); z.show(); } } class Fu{ int num = 10; } class Zi extends Fu{ int num = 20; public void show(){ int num = 30; System.out.println(num); // 30 System.out.println(this.num); // 20 System.out.println(super.num); // 10 } }