面向对象三大特征之二:继承
继承概述
- 继承是类与类之间的一种关系
- 多个类继承单独的某个类,多个类就可使用单独的这个类的属性和行为了
- 多个类称为子类(派生类),单独的这个类称为父类(基类 或超类)
使用继承的好处:提高代码的复用
public class People {
private String name;
private int age;
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 class Student extends People{
/**
* 独有的行为
*/
public void study(){
System.out.println("学生"+getName()+getAge()+"岁了,能好好学习了~~~");
}
}
public class Teacher extends People{
/**
* 独有的行为
*/
public void teach(){
System.out.println("老师"+getName()+getAge()+"岁了,在教书育人~~~");
}
}
public class Test {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("张三");
s1.setAge(22);
s1.study();
Teacher t1 = new Teacher();
t1.setName("李四");
t1.setAge(30);
t1.teach();
}
}
继承的设计规范、内存运行原理
继承设计规范
子类们相同特征放在父类中定义,子类独有的属性和行为应该定义在子类自己里面
案例——继承的规范
需求
在教育的tlias的教学资源管理系统中,存在学生,老师角色会进入系统
分析
- 学生信息和行为(名称,年龄,所在班级,查看课表,填写听课反馈)
- 老师信息和行为(名称,年龄,部门名称,查看课表,发布问题)
- 定义角色类作为父类包含属性(名称,年龄),行为(查看课表)
- 定义子类:学生类包含属性(所在班级),行为(填写听课反馈)
- 定义子类:老师类包含属性(部门名称),行为(发布问题)
public class People {
private String name;
private int age;
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 viewSchedule(){
System.out.println(name+"查看课程表");
}
}
public class Student extends People{
private String aclass;
public String getAclass() {
return aclass;
}
public void setAclass(String aclass) {
this.aclass = aclass;
}
public void Feedback(){
System.out.println(getName()+"在"+getAclass()+"班今天学习也是美美的");
}
}
public class Teacher extends People{
private String ePart;
public String getePart() {
return ePart;
}
public void setePart(String ePart) {
this.ePart = ePart;
}
public void postQues(){
System.out.println(getName()+"在"+getePart()+"教学感觉有点问题!");
}
}
public class Test {
public static void main(String[] args) {
Student s1=new Student();
s1.setName("张三");
s1.setAclass("11班");
s1.setAge(22);
s1.viewSchedule();
s1.Feedback();
Teacher t1=new Teacher();
t1.setName("李四");
t1.setAge(30);
t1.setePart("教师部");
t1.viewSchedule();
t1.postQues();
}
}
继承的特点
- 子类可以继承父类的属性和行为,但是子类不能继承父类的构造器
- Java是单继承模式:一个类只能继承一个直接父类
- Java不支持多继承,但是支持多层继承
- Java中所有的类都是Object类的子类
注意
- 子类不可以继承父类的构造器
- 子类可以继承父类的私有成员,只是不能直接访问
- 子类可以直接使用父类的静态成员,只是共享,不算继承
Object特点
- Java中所有类,要么直接继承了Object,要么默认继承了Object,要么间接继承了Object,Object是祖宗类
public class test{
public static void main(String[] args) {
Tiger t=new Tiger();
t.speak();
t.say();
System.out.println(Tiger.location);
}
}
class Animal{
public void speak(){
System.out.println("我是动物");
}
public static String location="长隆动物园";
}
class Tiger extends Animal{
public void say(){
System.out.println("我是老虎");
}
}
继承后:成员变量、成员方法的访问特点
在子类方法中访问成员(成员变量、成员方法)满足 就近原则
- 先子类局部范围找
- 然后子类成员范围找
- 然后父类成员范围找,如果父类范围还没有找到则报错
如果子父类中,出现了重名的成员,会优先使用子类的,如果要使用父类的,可以通过super关键字,指定访问父类的成员
public class demo3 {
public static void main(String[] args) {
Dog d=new Dog();
d.run();
d.dogLookDoor();
d.showMess("笨笨");
}
}
class Animal{
public String name="动物名";
public void run(){
System.out.println("动物可以跑步~~");
}
}
class Dog extends Animal{
public String name="狗名";
public void dogLookDoor(){
System.out.println("狗可以看门");
}
public void run(){
System.out.println("狗可以跑步");
}
public void showMess(String name){
System.out.println("name:"+name);
System.out.println("this.name:"+this.name);
System.out.println("super.name:"+super.name);
run();
super.run();
}
}
继承后:方法重写
在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法
方法重写的应用场景
当子类需要父类的功能,但父类的该功能不完全满足自己的需求时
子类可以重写父类中的方法
案例演示
- 旧手机的功能只能是基本的打电话,发信息
- 新手机的功能需要能够:基本的打电话下支持视频通话,基本的发信息下支持发送语音和图片
重写方法注解
@Override
- 重写校验注解,加上之后,这个方法必须是正确重写的,这样更安全
- 提高程序的可读性,代码优雅!
package com.echo.demo;
import junit.framework.TestCase;
public class demo4 extends TestCase {
public static void test(){
NewPhone newPhone = new NewPhone();
newPhone.call();
newPhone.send();
}
}
class OldPhone{
public void call(){
System.out.println("打电话");
}
public void send(){
System.out.println("发信息");
}
}
class NewPhone extends OldPhone{
@Override
public void call(){
super.call();
System.out.println("还能视频通话");
}
@Override
public void send(){
super.send();
System.out.println("还能发送语音和图片");
}
}
方法重写注意事项和要求
- 重写方法的名称、形参列表必须与被重写方法的名称和参数列表一致
- 私有方法不能被重写
- 子类重写父类方法时候,访问权限不行大于或者等于父类
- 子类不能重写父类的静态方法,如果重写会报错的
继承后:子类构造器的特点
特点
子类中所有的构造器默认都会先访问父类中无参的构造器,再执行自己
原因:
- 子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据
- 子类初始化之前,一定要调用父类构造器先完成父类数据空间的初始化
子类构造器的第一行语句默认都是:super(),不写也存在
package com.echo.demo;
public class demo5 {
public static void main(String[] args) {
Girl girl = new Girl();
System.out.println(girl);
Girl girl1 = new Girl("小芳");
System.out.println(girl1);
}
}
class Person{
public Person(){
System.out.println("父类的无参构造器");
}
}
class Girl extends Person{
public Girl(){
// super(); 不写也存在
System.out.println("子类的无参构造器");
}
public Girl(String name){
System.out.println("子类的有参数构造器");
}
}
super调用父类有参数构造器
作用:
初始化继承自父类的数据
package com.echo.demo;
public class demo6 {
public static void main(String[] args) {
Teacher t = new Teacher("张三", 20);
System.out.println(t.getName());
System.out.println(t.getAge());
}
}
class People{
private String name;
private int age;
public People() {
}
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 People(String name, int age) {
this.name = name;
this.age = age;
}
}
class Teacher extends People{
//调用父类的有参数构造器,初始化继承自父类的数据
public Teacher(String name,int age){
super(name,age);
}
}
如果父类中没有无参数构造器,只有有参构造器,会报错的,因为子类默认是调用父类无参数构造器的,除非子类构造器中通过书写super(…)手动调用父类的有参数构造器。
案例需求
- 在学员信息登记系统中,后台创建对象封装数据的时候如果用户没有输入学校,则默认使用“西安中学”
- 如果用户输入了学校则使用用户输入的学校信息
public class demo7 {
public static void main(String[] args) {
User u1=new User("张三","西安一中");
User u2=new User("李四");
System.out.println("u1.getName:"+u1.getName());
System.out.println("u1.getSchool:" + u1.getSchool());
System.out.println("u2.getName:"+u2.getName());
System.out.println("u2.getSchool:" + u2.getSchool());
}
}
class User{
private String name;
private String school;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
//有参数构造器
public User(String name,String school){
this.name=name;
this.school=school;
}
//如果用户没有输入学校则这样写
public User(String name){
this(name,"西安中学");
}
}
this()和super()使用注意点
子类通过this(…)去调用本类的其他构造器,本类其他构造器会通过super去手动调用父类的构造器,最终还是会调用服了的构造器的
注意
this(…)和super(…)都只能放在构造器的第一行,所以二者不能共存在同一个构造器中