面向对象(十三)

面向对象(十三)

封装

简单的说,封装就是使用private将属性私有,然后提供get/set方法获取和设置该属性

在idea中,生成get/set方法快捷键:win(alt+insert), Mac(command+n),然后在列表中选择get/set

封装的作用

  1. 提高代码的安全性,保护数据
  2. 隐藏代码的实现细节
  3. 统一接口
  4. 增加系统的可维护性
package com.oop.demo03;

public class Person {
    private String name;
    private int age;
    private char sex;

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    // 对属性设置增加判断
    public void setAge(int age) {
        if (age>120 || age<0) {
            System.out.println("输入的年龄异常!");
        } else {
            this.age = age;
        }
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }
}
/*
Application:
//一个项目只有一个main方法
public class Application {
    public static void main(String[] args) {

        Person ps1 = new Person();
        ps1.setName("小明");
        String name = ps1.getName();
        System.out.println(name);

        ps1.setAge(150);
        int age = ps1.getAge(); // 输入的年龄异常!
        System.out.println(age); // 0
    }
}
 */

继承

super的使用

super注意点

  1. super调用父类的构造方法,必须在构造方法的第一个
  2. super必须只能出现在子类的方法或构造方法中
  3. super和this不能同时调用构造方法

super和this对比

  1. 代表的对象不同:super代表的是父类对象的引用,this代表本身调用者这个对象
  2. 前提不同:super必须在继承关系下才能使用,this没有继承关系也能使用
  3. 构造方法:this()是本类的构造,super()是父类的构造

重写

idea中重写方法快捷键,Win(Alt+Insert), Mac(command+N) 在选项中选择Override

重写需要有继承关系,是子类对父类方法的重写!

  1. 重写方法的方法名必须与父类的相同
  2. 参数列表必须相同
  3. 修饰符:修饰范围可以扩大但不能缩小:Public > Protected > Default > Private
  4. 抛出的异常:范围可以缩小,但不能放大:ClassNotFoundException(小) --> Exception(大)

重写,子类的方法必须和父类保持一致,但是方法体不同!

方法重写的作用

父类的方法,子类不一定需要,也不一定满足。

示例

下面Student类中调用了父类Person的构造方法,并重写了doWork方法

Application

package com.oop;


import com.oop.demo04.Student;

//一个项目只有一个main方法
public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.test();
        student.name = "小明";
        student.doWork();
    }
}
/*
运行结果:
Person...
Student...
Person: null正在工作。
Student: 小明正在工作。
*/

Student

package com.oop.demo04;

public class Student extends Person{

    public Student() {
        super(); //调用父类的构造方法
        System.out.println("Student...");
    }

    public void test() {
        super.doWork(); //使用super调用父类的方法
    }

    //重写父类的方法
    @Override
    public void doWork() {
        System.out.println("Student: "+this.name+"正在工作。");
    }
}

Person

package com.oop.demo04;

public class Person {

    public Person() {
        System.out.println("Person...");
    }

    public String name;
    public int age;

    protected void doWork() {
        System.out.println("Person: "+this.name+"正在工作。");
    }
}

补充:重写和重载的区别

  1. 重写必须有继承关系,而重载不需要
  2. 重载的参数或返回值需要与原方法不同;重写则需要保持一致

多态

现在有B类继承自A类,并且B中重写了A的test()方法,另外拥有一个父类没有的test2()方法

B

package com.oop.demo05;

public class B extends A{

    @Override
    public void test() {
        System.out.println("BBB");
    }

    public void test2() {
        System.out.println("Only BBB");
    }
}

A

package com.oop.demo05;

public class A {

    public void test() {
        System.out.println("AAA");
    }
}

Application

package com.oop;

import com.oop.demo05.A;
import com.oop.demo05.B;

//一个项目只有一个main方法
public class Application {
    public static void main(String[] args) {
        //对象的示例类型由右边决定
        //对象可以使用那些方法由左边决定,与右边无关
        B b1 = new B();
        b1.test();

        A b2 = new B();
        b2.test();
        //b2.test2(); //无法调用B(子类)中独有方法

        Object b3 = new B();
    }
}
/*
运行结果:
BBB
BBB
AAA
*/

需要注意的点

  1. 一个对象的实际类型是确定的,即new右侧的类型;A a = new A();这里的A()

  2. 但是可以指向的引用类型是不确定的:父类的引用类型可以指向子类 A a = new B();

  3. B类可以调用的方式都是自己的或继承自父类的;而A可以指向子类型(即使用子类中重写的方法test()),但是不能使用子类的独有方法(test2()

对象能执行哪些方法,主要看对象左边的类型,和右边关系不大!

如果子类重写了父类的方法,则父类在引用时回执行子类重写的方法(A a = new B())。

多态使用的条件

从上可以得出,使用多态需要具备一下三个条件:

  1. 具有继承关系
  2. 子类重写父类的方法
  3. 父类引用指向子类对象

instance of方法判断一个对象是否是一个类的实例


2021-2-18更新,看了廖雪峰老师的博客,对多态的使用场景有了个更具体的认识

参考廖雪峰官网Java教程https://www.liaoxuefeng.com/wiki/1252599548343744/1260455778791232

现在有父类Person,定义了吃饭的方法,返回饭量;子类Man和Woman都继承Person类。

Person

package com.oop.demo08;

public class Person {
    public int fan;

    public int getFan() {
        return fan;
    }

    public void setFan(int fan) {
        this.fan = fan;
    }
}

Man 设置饭量为原始Person的三倍

package com.oop.demo08;

public class Man extends Person{

    @Override
    public void setFan(int fan) {
        this.fan = fan*3;
    }

    @Override
    public int getFan() {
        return this.fan;
    }
}

Woman 设置饭量为原始Person的二倍

package com.oop.demo08;

public class Woman extends Person{
    @Override
    public void setFan(int fan) {
        this.fan = 2*fan;
    }

    @Override
    public int getFan() {
        return this.fan;
    }
}

我们在Application中定义一个方法来统计需要准备的总饭量,参数是Person实例的数组

Application

package com.oop;


import com.oop.demo08.Man;
import com.oop.demo08.Person;
import com.oop.demo08.Woman;

//一个项目只有一个main方法
public class Application {
    public static void main(String[] args) {
        Person p1 = new Man();
        p1.setFan(5);
        Person p2 = new Woman();
        p2.setFan(3);

        Person[] ps = {p1, p2};

        int sumEat = eatTotal(ps);
        System.out.println(sumEat);

    }

    public static int eatTotal(Person[] ps) {
        int sum = 0;
        for (Person p: ps) {
            sum+=p.getFan();
        }
        return sum;
    }

}

可以看到,在统计总的饭量的方法中,我们不用去管传入的Person是Man还是Woman,Java在运行时会自动调用对应的实例方法或重写的方法,最后统计出总饭量。这里的精髓在于eatTotal方法的参数,是Person,而Man和Woman都是Person。

posted @ 2021-02-15 22:19  LucaZ  阅读(18)  评论(0编辑  收藏  举报