0
点赞
收藏
分享

微信扫一扫

第十二章 JavaSE专题之面向对象三大特性 -继承

cnlinkchina 2022-02-07 阅读 24
java

1、继承概述

  • 继承:解决代码复用,当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义相同的属性和方法,所有子类不需要重新定义这些属性和方法,只需要通过extends来生命继承父类

(1)继承语法

class 子类 extends 父类{
}

/*
1、子类就会自动拥有父类定义的属性和方法;
2、父类又叫超类,基类;
3、子类又叫派生类
*/
  • 继承示意图

在这里插入图片描述

(2)继承入门范例

  • 目录如下:

在这里插入图片描述

①创建父类

package com.taobao;

public class Person {
    public String name;     //名字公开
    private int age;        //age私有化
    private double salary;  //..

    //alt+insert


    public Person() {
    }

    public Person(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;

        //将set方法写在构造器中,这样仍然可以验证
        setSalary(salary);
        setName(name);
        setAge(age);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        //1、加入对数据的校验,相当于增加了默认逻辑
        if(name.length() >=2 && name.length()<=6) {
            this.name = name;
        } else {
            System.out.println("名字的长度不对,需要2到6字符,默认名字");
            this.name = "青春重新输入";
        }
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age>=1 && age <= 120) {
            this.age = age;
        }else{
            System.out.println("设置年龄不对,需要在(1-120),给默认年龄18");
            this.age = 18;    //给一个默认年龄
        }
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
    //写一个方法,返回属性信息
    public String info(){
        return "信息为 name =" + name + "age = " + age + "薪水为 =" + salary;
    }
}

②创建子类

package com.taobao;

public class Man extends Person {

    public void testing(){
        System.out.println(name);
    }
}

③main方法调用子类

package com.taobao;

public class hello {
    public static void main(String[] args) {
        Man man = new Man();
        man.name = "张三";
        man.testing();
    }
}
  • 运行结果

在这里插入图片描述

2、继承细节

2.1、子类继承了所有的属性和方法

①非私有的属性和方法可以在子类中直接访问;

私有属性和方法不能在子类直接访问,要通过公共方法访问

  • 范例:目录结构如下

在这里插入图片描述

(1)父类Person创建

public class Person {
    public String name;
    private double salary;  //..

    //alt+insert
    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
    //写一个公共方法,返回属性信息
    public String info(){
        return "薪水为 =" + salary;
    }

    //写一个私有方法
    private void info2(){
        System.out.println("姓名:" + name);
    }

    //callTest
    public void callInfo2(){
        info2();
    }
}

(2)子类Man继承Person父类

public class Man extends Person {

    public void testing(){
        System.out.println(name);
    }
}

(3)main方法使用子类

public class hello {
    public static void main(String[] args) {
        Man man = new Man();
        //1、子类继承非私有属性 - 可以直接访问
        man.name = "张三";
        //2、子类继承私有属性 - 通过父类提供公共方法(get)访问属性
        man.setSalary(1000);
        //3、之类继承父类公共方法 - 可以直接访问
        System.out.println(man.info());
        //4、子类继承父类的私有方法 - 通过在父类提供公共方法访问私有方法
        man.callInfo2();
        //5、直接访问子类的方法
        man.testing();
    }
}
  • 运行结果

在这里插入图片描述

2.2、子类必须调用父类构造器,完成父类的初始化
  • 创建子类对象时,不管使用子类的哪个构造器,默认情况下总会调用父类的无参构造器

    • 子类的无参构造器中默认有个 super(),代表调用父类的无参构造器;
    • 当创建子类对象时,不管使用子类的哪个构造器,默认情况下都会调用父类的无参构造器
  • 范例:目录结构如下

在这里插入图片描述

①创建父类

package com.taobao;

public class Person {
    //父类构造器
    public Person() {
        System.out.println("调用父类的构造器...");
    }
}

②创建子类

package com.taobao;

public class Man extends Person {
    //子类构造器
    public Man() {
        //super();                 //默认调用父类的无参构造器
        System.out.println("子类的无参构造器...");
    }
    public Man(String name){
        //super();
        System.out.println("参数"+name);
    }
}

③main方法创建子类对象

package com.taobao;

public class hello {
    public static void main(String[] args) {
        Man man = new Man();
    }
}
  • 运行结果:先创建父类,后创建子类

在这里插入图片描述

2.3、父类没有提供无参构造器
  • 注意事项:必须在子类的构造器中用super去指定使用哪个父类的构造器完成对父类的初始化工作,否则编译不会通过;

  • 范例:目录结构如下

在这里插入图片描述

①创建父类

package com.taobao;

public class Person {
    public Person(String name) {
        System.out.println("调用父类的构造器...");
    }
}

②创建子类

package com.taobao;

public class Man extends Person {

    public Man() {
        super("张三");
        System.out.println("子类的无参构造器...");;
    }
    public Man(String name) {
        super("张三");
        System.out.println("子类的有参构造器...");;
    }
}

③创建对象,分别调用子类的无参构造器和带参构造器

package com.taobao;

public class hello {
    public static void main(String[] args) {

        System.out.println("调用子类无参构造器!");
        Man man = new Man();
        System.out.println("调用子类的带参构造器!");
        Man man1 = new Man("lizhi");
    }
}
  • 运行结果

在这里插入图片描述

  • 注意事项
    • 如果希望指定去调用父类的某个构造器,则显式的调用一下 :super(参数列表)
    • ②super在使用时,需要放在构造器的第一行
    • super()和this()都只能放在构造器第一行,因此两个方法不能存在同一个构造器
    • java所有类都是object的父类,object是所有类的基类;
    • ⑤父类构造器的调用不限于直接父类!将一直往上追溯知道Object类(顶级父类)
    • 子类最多继承一个父类,即java中是单继承方式:如何让A类继承B和C,先让B类继承C,再让A类继承B
    • ⑦不能滥用继承,子类和父类之间必须满足is-a的逻辑关系;

3、继承的本质

  • 范例

(1)新建类GradPa

package com.taobao;

public class GrandPa {
    String name = "爷爷";
    String hobby = "旅游";
}

(2)新建子类Father继承GradPa类

package com.taobao;

public class Father extends GrandPa {
    String name = "大头爸爸";
    int age = 39;
}

(3)新建子类Son继承Father

package com.taobao;

public class Son extends Father{
    String name = "大头儿子";
}

(4)main方法创建子类对象

package com.taobao;

public class hello {
    public static void main(String[] args) {
        Son son = new Son();
        System.out.println("调用Son子类name:"+son.name);
        System.out.println("调用Father父类age:"+son.age);
        System.out.println("调用GrandPa父类hobby:"+son.hobby);
    }
}
  • 运行结果

在这里插入图片描述

  • 属性查找顺序 : 按照查找关系来返回信息
    • ①首先看子类是否有该属性;
    • ②如果子类有这个属性,并且可以访问,则返回信息;
    • ③如果子类没有这个属性,就看父类有没有属性(如果父类有该属性,并且可以访问,就返回信息)
    • ④如果父类没有就按照(3)的规则,继续找上级父类,知道Object
    • ⑤向上找遇上私有属性的则调用get方法;

4、super关键字

  • super:代表父类的引用,用于访问父类的属性,方法,构造器
    • 在子类的构造方法中显式的调用父类构造方法
    • 访问父类的成员方法和变量。

(1)super基本语法
①访问父类的属性,但不能访问父类的private属性;

super.属性

②访问父类的方法,但不能访问父类的private方法;

super.方法名(参数列表)

③访问父类的构造器,但只能放在构造器第一句,和this冲突;

super(参数列表)

(2)super调用父类构造方法

当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会调用父类的无参构造器,
    子类的无参构造器中默认有个  super(),代表调用父类的无参构造器;
	当创建子类对象时,不管使用子类的哪个构造器,默认情况下都会调用父类的无参构造器

(3)super调用父类属性

  • 当父类和子类具有相同的数据成员时,JVM 可能会模糊不清,需要用super指定
  • 范例1 - 不加super就近查找
//1、创建父类
class Person {
    int age = 12;
}

//2、创建子类
class Student extends Person {
    int age = 18;
    void display() {
        System.out.println("学生年龄:" + age);
    }
}

//3、创建测试类
class Test {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.display();
    }
}
  • 运行结果

在这里插入图片描述

  • 范例2 : 加上super则跟随父类
//1、创建父类
public class Person {
    int age = 12;
}

//2、创建子类
public class Student extends Person {
    int age = 18;
    void display() {
        System.out.println("学生年龄:" + super.age);
    }
}

//3、创建测试类
public class Test {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.display();
    }
}
  • 运行结果

在这里插入图片描述

(4)super调用成员方法

  • 父类和子类都具有相同的方法名时,可以使用 super 关键字访问父类的方法;

  • 范例:

//1、创建父类
class Person {
    void message() {
        System.out.println("This is person class");
    }
}

//2、创建子类
class Student extends Person {
    void message() {
        System.out.println("This is student class");
    }
    void display() {
        message();        // 调用当前类的message方法
        super.message();  // 调用父类的message方法
    }
}

//3、main调用子类
class Test {
    public static void main(String args[]) {
        Student s = new Student();
        s.display();
    }
}
  • 运行结果
    • 只调用方法 message( ),是当前的类 message( ) 被调用;
    • 使用 super 关键字时,是父类的 message( ) 被调用。
      在这里插入图片描述

(5)super和this区别

区别点thissuper
1访问属性访问本类中的属性,如果本类中没有此属性则从父类中继续查找直接访问父类中的属性
2调用方法访问本类中的方法,如果本类中没有此方法则从父类继承直接访问父类中的方法
3调用构造器调用本类构造器,必须放在构造器首行**直接调用父类构造器,**必须放在构造器首行
4特殊表示当前对象子类中访问父类对象

5、方法重写(override)

(1)方法重写概述

  • 方法重写:子类中有一个方法,和父类的某个方法名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法;
//1、创建父类
public class Animal {
    public  void cry(){
        System.out.println("动物汪汪叫...");
    }
}

//2、创建子类
public class Dog extends Animal {
    public  void cry(){
        System.out.println("小狗汪汪叫...");
    }
}


//3、main方法调用子类
public class OverrideMain {
    public static void main(String[] args) {
        //演示方法重写
        Dog dog = new Dog();
        dog.cry();
    }
}
  • 运行结果

在这里插入图片描述

(2)方法重写细节

Ⅰ、子类方法的参数,方法名称要和父类方法的参数,方法名称完全一样;

Ⅱ、子类方法的返回类型

  • 父类的方法返回类型一样;

  • 父类的返回类型的子类;

//父类
public object getInfo()

    
//子类
public String getInfo()

Ⅲ、子类方法不能缩小父类方法的访问权限

//父类
void sayOk()

//子类
public void sayOk()

(3)方法重写和方法重载区别

名称发生范围方法名参数列表返回类型修饰符
重载本类必须一样类型、个数、顺序至少一个不同无要求无要求
重写父子类必须一样必须相同一致/父子类子类>父类访问范围
举报

相关推荐

0 条评论