目录
7.1、继承的概念
继承是面向对象的三大特性之一,继承可以解决编程中代码冗余的问题,是实现代码重要的手段之一。继承是软件可重用性的一种表现,新类可以在不增加自身代码的情况下,通过从现有的类中继承其属性和方法,来充实自身内容,这种现象或行为就称为继承。此时新类成为子类,现有的类称为父类。
继承最基本的作用就是使得代码可重用,增加软件的可扩充性。
Java中只支持单继承,即每个类只能有一个直接父类。
继承表达的是“XX is a XX”的关系,或者说是一种特殊的一般的关系,如Dog is a Pet。同样可以让“学生”继承“人”,让“苹果”继承“水果”,让“三角形”继承“几何图形”。
7.2、继承的语法格式
继承的语法格式如下:
[访问修饰符] class <SubClass> extends <SuperClass>{
}
(1)在Java中,继承通过extends关键字实现,其中SubClass称为子类,Super称为父类或基类。
(2)访问修饰符如果是public,那么该类在整个项目中可见
(3)若不写访问修饰符(默认修饰符),则该类只在当前包中可见
(4)在Java中,子类可以从父类中继承以下内容。
1)可以继承public和protected修饰的属性和方法,不论子类和父类是否在同一个包里;
2)可以继承默认修饰符的属性和方法,但是子类和父类必须在同一个包里;
3)无法继承父类的构造方法。
7.3、继承实现电子宠物系统
父类Animal:Dog类和Penguin类中都存在的属性
子类Dog类:Dog类自身所独有的属性,Penguin类中没有的属性
子类Penguin类:Penguin类自身独有的属性,Dog类中没有的属性
1、创建父类,用来存储子类中共有的属性、方法
父类Animal类
package com.bdqn.demo01; public class Animal { /* * Animal为父类,Dog类和Penguin类中都存在的属性,将其提取出来 */ // 定义属性 private String name; // 名字 private int health; // 健康值 private int love; // 亲密度 // 无参构造方法 public Animal() { super(); } // 有参构造方法 public Animal(String name, int health, int love) { super(); this.name = name; this.health = health; this.love = love; } // getter()、setter()方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getHealth() { return health; } public void setHealth(int health) { this.health = health; } public int getLove() { return love; } public void setLove(int love) { this.love = love; } // 定义一个输出动物信息的方法(子类Dog类和Penguin类共有的方法) public void print() { System.out.println("动物昵称:" + this.name + ",健康值:" + this.health + ",亲密度" + this.love); } }
2、创建子类Dog类和Penguin类:自身所独有的属性提取出来
Dog子类:
package com.bdqn.demo01; public class Dog extends Animal{ //Dog类自身所独有的属性,Penguin类中没有的属性 private String strain;//品种 public Dog() { super();//调用父类Animal类里的无参构造方法 } public Dog(String name, int health, int love, String strain) { super(name, health, love); //调用父类Animal类里的有参构造方法 this.strain = strain; } //getter()和setter()方法 public String getStrain() { return strain; } public void setStrain(String strain) { this.strain = strain; } }
Penguin子类:
package com.bdqn.demo01; public class Penguin extends Animal{ //Penguin类自身独有的属性,Dog类中没有的属性 private String sex; // public Penguin() { super();//调用父类Animal类中无参构造方法 } public Penguin(String name, int health, int love, String sex) { super(name, health, love);//调用父类Animal类中的有参构造方法 this.sex = sex; } //getter()和setter()方法 public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
测试类Test:
package com.bdqn.demo01; public class Text { public static void main(String[] args) { //通过无参构造方法创建Dog类对象 Dog dog1=new Dog(); dog1.setStrain("泰迪"); dog1.setName("Happy"); dog1.setHealth(90); dog1.setLove(88); //System.out.println("品种:"+dog1.getStrain()+","); //输出Dog类独有的属性Strain-->品种 dog1.print(); //通过有参构造方法创建对象 Penguin penguin1=new Penguin("QQ", 95, 90, "Q妹"); //Penguin penguin1=new Penguin(name, health, love, sex) //System.out.println("性别:"+penguin1.getSex()+","); //输出Penguin类独有的属性Sex-->性别 penguin1.print(); } }
输出结果:
7.4、Java只能够实现单根继承
继承是Java中实现代码的重要手段之一。Java中只支持单根继承,即一个类只能有一个直接父类,但是可以多层次的继承,也就是子类可以继承父类里的资源。
案例:
创建三个类,GeandFather、Father、Son和一个测试类;
①:其中Son类是Father类的子类,Father类是Son的父类
②:其中Father类是GeandFather类的子类,GeandFather类是Father类的父类
即:可以多层次的继承。
代码解析:
GeandFather类独有的属性是money,
Father类独有的属性是antique,
Son类独有的属性是hobby,
GeandFather类
package com.bdqn.demo05; public class GrandFather { private double money;// 钱 public GrandFather() { super();// 调用父类Object类里的无参构造方法 } public GrandFather(double money) { super();// 调用父类Object类里的无参构造方法 this.money = money; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } // 定义一个普通方法 public void print() { System.out.println("我是GrandFather类里的print()方法"); } }
Father类
package com.bdqn.demo05; public class Father extends GrandFather { private String antique; // 古董 public Father() { super();// 调用父类GrandFather类里的无参构造方法 } public Father(double money, String antique) { super(money);// 调用父类GrandFather类里的有参构造方法 this.antique = antique; } public String getAntique() { return antique; } public void setAntique(String antique) { this.antique = antique; } public void test() { System.out.println("我是Father类里的test()方法"); } }
Son类
package com.bdqn.demo05; public class Son extends Father { private String hobby; // 爱好 public Son() { super();// 调用父类Father类里的无参构造方法 } public Son(double money, String antique, String hobby) { super(money, antique);// 调用父类Father类里的有参构造方法 this.hobby = hobby; } public String getHobby() { return hobby; } public void setHobby(String hobby) { this.hobby = hobby; } public void demo() { System.out.println("我是Son类里的demo()方法"); } }
测试类Test
package com.bdqn.demo05; public class Test { public static void main(String[] args) { Son son1 = new Son(); son1.setHobby("买跑车");// 调用Son类里的setXxx()方法 son1.setAntique("蒙娜丽莎");// 调用Father类里的setXxx()方法 son1.setMoney(10000000);// 调用GrandFather类里的setXxx()方法 son1.print(); son1.test(); son1.demo(); /* * 继承是Java中实现代码重用的重要手段之一。 * Java中只支持单根继承,即一个类只能有一个直接父类,但是可以多层次的继承,也就是子类可以继承父类的父类里的资源 */ } }
输出结果:
7.5、Super关键字浅谈
super关键字来访问父类的成员
(1)super只能出现在子类的方法和构造方法中
(2)super调用构造方法时,只能是第一句
(3)super不能访问父类的private成员解析:
(1)super只能出现在子类的方法和构造方法中
(2)super调用构造方法时,只能是第一句
(3)super不能访问父类的private成员
7.6、继承条件下的构造方法
实例化子类对象
在Java中,一个类的构造方法在如下两种情况下总是会被执行。
- 创建该类的对象(实例化)
- 创建该类的子类的对象(子类的实例化)
因此,子类在实例化时,会首先执行其父类的构造方法,然后才执行子类的构造方法。换言之,当在Java语言中创建一个对象时,Java虚拟机会按父类--->子类的顺序执行一系列的构造方法。
子类继承父类时构造方法的调用规则如下:
(1)如果子类的构造方法中没有通过super显式调用父类的有参构造方法,也没有通过this显式调用自身的其他构造方法,则系统会默认先调用父类的无参构造方法。在这种情况下,是否写"super();"语句,效果是一样的。
(2)如果子类的构造方法中通过super显式地调用了父类的有参构造方法,那么将执行父类相应的构造方法,而不执行父类的无参构造方法。
(3)如果子类的构造方法中通过this显式地调用自身的其他构造方法,在相应构造方法中遵循以上两条规则。
注意:一个类在创建对象的时候,至少会调用2次构造方法
补充:在类没有提供任何构造方法时,系统会提供一个无参的方法体为空的默认构造方法,一旦提供了自定义构造方法,系统将不再提供这个默认构造方法。如果要使用它,程序员必须手动添加。
对以上规则通过代码进行解析:
(1)如果子类的构造方法中没有通过super显式调用父类的有参构造方法,也没有通过this显式调用自身的其他构造方法,则系统会默认先调用父类的无参构造方法。在这种情况下,是否写"super();"语句,效果是一样的。
(2)如果子类的构造方法中通过super显式地调用了父类的有参构造方法,那么将执行父类相应的构造方法,而不执行父类的无参构造方法。
7.5、继承访问权限的问题
理解继承-1
(1)子类继承父类的什么?
①继承public和protected修饰的属性和方法,不管子类和父类是否在同一个包里
②继承默认权限修饰符修饰的属性和方法,但子类和父类必须在同一个包里理解继承-2
(2)子类可以继承父类的所有资源吗?
不能被继承的父类成员
①:private成员
②:子类与父类不在同包,使用默认访问权限的成员
③:构造方法(构建对象)
上述进行代码解析:
(1)首先创建两个包:
com.bdqn.demo07(包括:父类Father、子类Son、测试类Test)
com.bdqn.demo08(包括:Son类)
com.demo.demo07包中的:父类Father
package com.bdqn.demo07; public class Father { //使用四种权限修饰符定义属性 public String name; protected int age; double height; private double weight; }
com.demo.demo07包中的:子类Son
package com.bdqn.demo07; public class Son extends Father { }
com.demo.demo07包中的:测试类Test
package com.bdqn.demo07; public class Test { public static void main(String[] args) { Son son = new Son(); son.name = "张三"; //name是使用public进行修饰的 son.age = 18; //age是使用protected进行修饰的 son.height = 175; //height是使用默认修饰符进行修饰的(默认修饰符包级私有) /* * weight是使用private进行修饰的, * 不能直接访问(只能在本类中Father中进行直接访问,其他类中不能直接访问) * */ //son.weight = 55; } }
com.demo.demo08包中的:Son类
package com.bdqn.demo08; import com.bdqn.demo07.Father; public class Son extends Father { public static void main(String[] args) { Son son = new Son(); /* * name是使用public进行修饰的,age是使用protected进行修饰的, * 该Son类继承的属性是com.bdqn.demo07包里的父类Father的属性, * 即:继承public和protected修饰的属性和方法,不管子类和父类是否在同一个包里 * */ son.name = "李四"; son.age = 19; /* * height是使用默认修饰符进行修饰的(默认修饰符包级私有), * 该Son类是包com.bdqn.demo08包内的类, * 该Son类继承的是com.bdqn.demo07包里的父类Father的属性, * 但是该Son类(子类)和Father类不在同一个包内,故不能进行访问,访问失败 * * */ //son.height = 180; /* * weight是使用private进行修饰的, * 不能直接访问(只能在本类中Father中进行直接访问,其他类中不能直接访问) * */ //son.weight = 70; } }
总结: