【JAVA语言-第7话】面向对象的封装性、继承性、多态性,构造方法,this和super关键字(下)

面向对象的特性(下) 

1.1 继承性

1.1.1 概述

        继承是多态的前提,如果没有继承,就没有多态,主要解决问题“共性抽取”。从面向对象的角度来说,其实就是一种“is a”的关系,即子类是父类的扩展。子类可以通过继承(extends)获得父类原有的字段和方法,也可以增加父类所没有的字段和方法,更可以覆写父类中的允许被子类覆盖的字段和方法。类之间的继承关系只允许单继承,即一个类只能有一个直接父类,但是多重继承是被允许的

1.1.2 继承的优点

  • 子类可以拥有父类的“内容”(包含属性和方法)。
  • 子类还可以拥有自己专有的内容。
  • 有效解决了代码的重用问题,使代码扩展更加灵活,以适应不同的业务需求
  • 通过继承关系,可以完整的体现出一个应用体系,逻辑更加清晰。

1.1.3 格式

定义父类的格式:

        public class 父类名称{

        }

public class Animal {
}

定义子类的格式:

        public class 子类名称 extends 父类名称{

        }  

public class Cat extends Animal{
}

1.1.4 访问特点

成员变量的访问特点:

1.在父子类的继承关系中,如果成员变量名重名,则创建子类对象时,访问有两种方式:

  • 直接通过子类对象访问成员变量:等号左边是谁,就优先用谁,没有则向上找。
  • 间接通过成员方法访问成员变量:该方法属于谁,就优先用谁,没有则向上找。

        

2.访问子类方法中重名的三种变量名

  • 局部变量:直接写局部变量名。
  • 本类的成员变量:this.成员变量名。
  • 父类的成员变量:super.成员变量名。

        

成员方法的访问特点:

1.在父子类的继承关系中,如果成员方法重名,则访问规则为:

  • 创建的对象是谁(=右边的类型决定),就优先使用谁,没有则向上找父类。

        

注意事项

  • 无论是成员变量还是成员方法,如果没有都是向上找父类,绝对不会向下找子类的

1.1.5 子类可以继承父类的哪些成员

可以继承的情况

  1. 父类和子类处于不同包时:子类可以继承父类中使用protected、public修饰的成员和方法。
  2. 父类和子类处于相同包时:子类可以继承父类中使用(缺省)、protected、public修饰的成员和方法。

        

不可继承的情况:

  1. 父类中使用private修饰的成员和方法子类不可继承。
  2. 父类的构造器(构造方法),子类不能继承。每个类的构造器都必须和类名相同。

1.1.6 方法重写 

在子类中重写父类的方法,重写原则(一同两小一大)

一同

        方法签名必须相同。方法签名 = 方法名 + 方法的参数列表(参数类型、参数个数、参数顺序)。

        

两小

        子类方法的返回值类型必须和父类的返回类型相同或者更具体。

        子类方法声明抛出的异常类型(后续会详细讲异常,这里记住即可)必须小于或者等于父类方法声明抛出异常类型,子类方法可以同时声明抛出多个属于父类方法声明抛出异常的子类。

        

一大:子类方法的访问权限与父类方法访问权限相同或者更大。

注:@Override注解:修饰子类重写,如果重写语法错误,就会编译报错,能确保重写的正确性。

1.1.7 super关键字的用法

  • 在子类的成员方法中,访问父类的成员变量:super.成员变量名;
  • 在子类的成员方法中,访问父类的成员方法:super.成员方法名();
  • 在子类的构造方法中,访问父类的构造方法:super();
    public Cat(String breed) {
        super(breed); //调用父类的构造方法,必须写在第一行
        super.breed = breed; //访问父类的成员变量
        super.eat(); //访问父类的成员方法
    }

1.2 多态性

1.2.1 概述 

        一个对象拥有多种形态,就是对象的多态性。例如:小明是一个对象,但小明既有学生形态,也有人类形态。多态实现 = 子类继承父类,并重写父类的方法

1.2.2 多态的格式和使用

格式:父类的引用指向子类的对象

        父类名称 对象名 = new 子类名称();

        接口名称 对象名 = new 实现类名称();

        

多态中成员变量的使用特点:

        直接通过对象名称访问:看等号左边是谁,优先用谁,没有则向上找。

        间接通过成员方法访问:看该方法属于谁,优先用谁,没有则向上找。

        

多态中成员方法的使用特点:

        看new的是谁,就优先用谁,没有则向上找。

        对比一个成员变量和成员方法的熟记口诀:

                成员变量:编译看左边,运行还看左边。

                成员方法:编译看左边,运行看右边。

1.2.3 多态的好处

  1. 无论右边new的时候换成哪个子类对象,等号左边调用方法都不会变化。
  2. 提高代码的可维护性:多态使得代码更加灵活,能够应对未来的需求变化,减少重构代码的工作量。
  3. 增加代码的可复用性:多态让代码可以更好地复用,一个方法在不同的对象上表现出不同的行为,不需要编写大量相似的代码。
  4. 提高代码的可扩展性:多态可以让新的子类添加到已有的代码中,而不需要对原有代码进行修改。
  5. 降低代码的耦合度:多态可以在抽象层面上定义和使用对象,而不需要关心底层的实现细节,从而降低代码之间的依赖关系。
  6. 提高代码的可读性和可理解性:多态可以让代码更加抽象和直观,有助于程序员更快地理解代码的含义和功能。

1.2.4 多态对象的转型

1.2.4.1  对象的向上转型

 其实就是多态的写法

格式:

        父类名称 对象名 = new 子类名称();

        //父类引用指向子类对象
        Animal a = new Cat();
        Animal b = new Dog();

说明:

        右侧创建一个子类对象,把它当做父类来看待使用。

        

注意事项

        1.向上转型一定是安全的,从小范围转向了大范围。

        2.但是一旦向上转型为父类,就无法调用子类原本特有的方法,只能调用子类和父类公共方法,单独存在于子类中的方法无法调用。

1.2.4.2 对象的向下转型

其实就是一个[还原]的动作

格式:

        子类名称 对象名 = (子类名称)父类对象名;

        Animal a = new Cat(); //向上转型,子类转父类
        Cat cat = (Cat)a; //向下转型,父类转子类

含义:

        将父类对象,【还原】成为本来的子类对象。

        

注意事项:

        1.必须保证对象本来创建的时候,就是Cat,才能向下转型还原回去。

        2.如果对象创建的时候本来不是Cat,强行向下转型为Cat,就会出现类转换异常(java.lang.ClassCastException)。

        3.因为父类存在多个子类,所以向下转型不一定是安全,可能会出现问题2,为了保证转型安全,需要用到关键字instanceof。

1.2.5 instanceof关键字的使用

格式:

        对象 instanceof 类名称

        Animal a = new Cat();
        if(a instanceof Cat){
            Cat cat = (Cat)a;
        }

含义:

        用于判断前面的对象能不能当做后面类型的实例,返回结果是一个boolean值

1.3 综合案例:

步骤一:定义一个Animal.java类,包含属性:breed,color;包含方法:eat(),sleep()。

/**
 * 定义一个Animal类
 *  包含属性:品种,颜色
 *  包含方法:吃,睡
 */
public class Animal {
    /**
     * 品种
     */
    String breed;
    /**
     * 颜色
     */
    String color;

    /**
     * 无参构造方法
     */
    public Animal() {
    }

    /**
     * 有参构造方法,重载
     * @param breed
     */
    public Animal(String breed) {
        this.breed = breed;
    }

    /**
     * 构造方法重载
     * @param breed
     * @param color
     */
    public Animal(String breed, String color) {
        this(breed); //调用一个参数的构造方法,必须写在第一行
        this.color = color; //访问本类的成员变量
        this.eat(); //访问本类的成员方法
    }

    /**
     * 吃饭
     */
    public void eat(){
        System.out.println(breed + "吃饭!");
    }

    /**
     * 睡觉
     */
    public void sleep(){
        System.out.println("睡觉!");
    }
}

步骤二:定义一个Cat.java类,继承Animal类,并重写eat()方法,新增子类特有的方法play()。

/**
 * 定义一个Cat类,继承Animal类
 */
public class Cat extends Animal{

    public Cat(){
        super();//调用父类的无参构造方法
    }

    /**
     * 重写父类的eat方法
     */
    @Override
    public void eat() {
        //breed属性是继承自父类的,可以直接使用
        System.out.println(breed + "吃猫粮!");
    }

    /**
     * 子类特有的方法
     */
    public void play(){
        System.out.println(breed + "在玩耍!");
    }
}

步骤三:定义一个Dog.java类,继承Animal类,并重写eat()方法,新增子类特有的方法wagTail()。

/**
 * 定义一个Dog类,继承Animal类
 */
public class Dog extends Animal{
    /**
     * 重写父类的eat方法
     */
    @Override
    public void eat() {
        //breed属性是继承自父类的,可以直接使用
        System.out.println(breed + "吃狗粮!");
    }

    /**
     * 子类特有的方法
     */
    public void wagTail(){
        System.out.println(breed + "在摇尾巴!");
    }
}

步骤四:定义一个TestAnimal.java类,测试同一个引用指向不同子类,调用相同方法发生的变化。

/**
 * 测试类
 */
public class TestAnimal {
    public static void main(String[] args) {
        System.out.println("单独调用父类方法:");
        //创建父类对象,给属性赋值,调用方法
        Animal animal = new Animal();
        animal.breed = "动物";
        animal.eat();
        System.out.println("=====================================");

        System.out.println("单独调用子类方法:");
        Cat cat = new Cat();
        cat.breed = "猫";
        cat.eat();
        cat.play();

        Dog dog = new Dog();
        dog.breed = "狗";
        dog.eat();
        dog.wagTail();
        System.out.println("=====================================");

        System.out.println("使用多态形式调用子类方法,向上转型:");
        Animal a = new Cat();
        a.breed = "猫";
        a.eat();

        a = new Dog();
        a.breed = "狗";
        a.eat();
        System.out.println("=====================================");

        //向上转型后,父类引用是无法调用子类特有的方法,如果要调用,只能在转回去
        System.out.println("使用向下转型,调用子类特有的方法:");
        if(a instanceof Cat){
            Cat cat1 = (Cat) a;
            cat1.play();
        }else if(a instanceof Dog){
            Dog dog1 = (Dog) a;
            dog1.wagTail();
        }
    }
}

输出结果:

 【JAVA语言-第7话】面向对象的封装性、继承性、多态性,构造方法,this和super关键字(下)_第1张图片

         

题外话:

        如果文章中存在错误的地方,欢迎大家指正出来,共同学习进步,后续会陆续就JAVA这门课程展开进行分享。

你可能感兴趣的:(JAVA语言,java,开发语言)