Java---面向对象编程三大特征【封装、继承、多态】及super关键字、方法重写/覆盖(不定期更新补充)---B站韩顺平老师视频总结

文章目录

三大特征

面向对象编程有三大特征:封装,继承和多态。

面向对象编程-封装

封装介绍

封装(encapsulation)就是把抽象出的数据【属性】和堆数据的操作【方法】封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作【方法】,才能对数据进行操作。

封装的理解和好处

1.隐藏实现细节
2.可以对数据进行验证,保证安全合理

封装的实现步骤(三步)

1.将属性进行私有化private【不能直接修改属性】
2.提供一个公共的(public)set方法,用于对属性判断并赋值

public void setXxx(类型 参数名){//Xxx表示某个属性
	//加入数据验证的业务逻辑
	属性 = 参数名;
}

3.提供一个公共的get方法,用于获取属性的值

public XX getXxx(){//权限判断,Xxx表示某个属性
	return xx;
}

封装的简单案例

写一个程序,不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认。年龄必须在1-120,年龄,工资不能直接查看,name的长度在2-6个字之间

import java.util.Scanner;

public class Encap {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Person person = new Person();
        person.setName("jackfafasfasf");
        person.setAge(20);
        person.setSalary(1000);

//        System.out.println(person.info());
        System.out.println(person.getSalary());
        System.out.println(person.getName());
    }
}

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

    //自己写set和get太慢了,可以使用快捷键(Alt + Insert),然后根据要求完善代码

    public String getName() {
        return name;
    }

    public void setName(String name) {
        if (name.length() >= 2 && name.length() <= 6) {
            this.name = name;
        }else{
            System.out.println("名字长度不在范围内,按默认处理");
            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() {
        System.out.print("请输入密码:");
        Scanner scanner = new Scanner(System.in);
        int num = scanner.nextInt();
        if (num == 123456) {
            return salary;
        } else {
            System.out.println("密码错误");
            return null;
        }
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

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

封装与构造器

import java.util.Scanner;

public class Encap {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Person person = new Person();
        person.setName("jackfafasfasf");
        person.setAge(20);
        person.setSalary(1000);

//        System.out.println(person.info());
        System.out.println(person.getSalary());
        System.out.println(person.getName());


        Person person1 = new Person("小白",18,1000);
        System.out.println(person1.info());
    }
}

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

    public Person() {
    }

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

        setAge(age);//等价于this.setAge(age);
        setSalary(salary);
        setName(name);
    }

    //自己写set和get太慢了,可以使用快捷键(Alt + Insert),然后根据要求完善代码

    public String getName() {
        return name;
    }

    public void setName(String name) {
        if (name.length() >= 2 && name.length() <= 6) {
            this.name = name;
        }else{
            System.out.println("名字长度不在范围内,按默认处理");
            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() {
        System.out.print("请输入密码:");
        Scanner scanner = new Scanner(System.in);
        int num = scanner.nextInt();
        if (num == 123456) {
            return salary;
        } else {
            System.out.println("密码错误");
            return null;
        }
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

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

封装的练习

创建程序,在其中定义两个类:Account和AccountTest类体会Java的封装性。
1.Account类要求具有属性:姓名(长度为2位3位或4位)、余额(必须>20)、密码(必须是6位),如果不满足,则给出提示信息,并给默认值。
2.通过setXxx的方法给Account的属性赋值。
3.在AccountText中测试

package com.fspdu.encap;

public class Account {
    private String name;
    private double banlance;
    private String pwd;

    public Account() {
    }

    public Account(String name, double banlance, String pwd) {
        this.setName(name);
        this.setBanlance(banlance);
        this.setPwd(pwd);
    }

    public String getName() {
        return name;
    }

    public String setName(String name) {
        if(name.length() >= 2 && name.length() <= 6) {
            this.name = name;
            return name;
        }else{
            System.out.println("名字不规范,按默认处理");
            this.name = "无名者";
            return name;
        }
    }

    public double getBanlance() {
        return banlance;
    }

    public void setBanlance(double banlance) {
        if(banlance > 20) {
            this.banlance = banlance;
        }else{
            System.out.println("余额必须大于20,在此按默认0处理");
        }
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        if(pwd.length() == 6) {
            this.pwd = pwd;
        }else{
            System.out.println("密码必须是6位");
        }
    }

    public void info(){
        System.out.println("name:" + name + "banlance:" + banlance + "pwd:" + pwd);
    }
}
package com.fspdu.encap;

public class AccounText {
    public static void main(String[] args) {
        Account account = new Account("小",1,"12345");
        account.info();

    }
}

面向对象编程-继承

为什么需要继承

看一个问题,我们编写了两个类,一个是Pupil类(小学生),一个是Graduate(大学毕业生)。

//小学生->模拟小学生考试情况
public class Pupic {
    public  String name;
    public int age;
    private double score;

    public void setScore(double score) {
        this.score = score;
    }
    public void testing(){
        System.out.println("小学生" + name + "正在考小学数学");
    }
    public void showInfo(){
        System.out.println("学生名字:" + name + "年龄:" + age + "分数:" + score);
    }

}
//模拟大学生考试情况
public class Graduate {
    public  String name;
    public int age;
    private double score;

    public void setScore(double score) {
        this.score = score;
    }
    public void testing(){
        System.out.println("大学生" + name + "正在考高等数学");
    }
    public void showInfo(){
        System.out.println("学生名字:" + name + "年龄:" + age + "分数:" + score);
    }
}
public class Extends01 {
    public static void main(String[] args) {
        Pupic pupic = new Pupic();
        pupic.name = "小白";
        pupic.age = 15;
        pupic.testing();
        pupic.setScore(100);
        pupic.showInfo();
        System.out.println("======================");
        Graduate graduate = new Graduate();
        graduate.name = "大白";
        graduate.age = 18;
        graduate.testing();
        graduate.setScore(150);
        graduate.showInfo();

    }
}

测试结果:
小学生小白正在考小学数学
学生名字:小白 年龄:15 分数:100.0
======================
大学生大白正在考高等数学
学生名字:大白 年龄:18 分数:150.0

我们发现两个类的属性和方法有很多是相同的,怎么办?这就用到了继承(代码复用性)。

继承基本介绍和示意图

继承可以解决代码复用,让我们的编程更加靠近人类思维。当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继续父类即可。
在这里插入图片描述

继承的基本语法

class 子类 extends 父类{
}

1.子类就会自动拥有父类定义的属性和方法
2.父类又叫超类,基类
3.子类又叫派生类

入门案例(修改上述代码)

父类

package com.fspdu.extend.improve;
//父类,是Pupil和Graduate的父类
public class Student {
    //共有属性
    public  String name;
    public int age;
    private double score;

    //共有方法
    public void setScore(double score) {
        this.score = score;
    }
    public void showInfo(){
        System.out.println("学生名字:" + name + " " + "年龄:" + age + " " + "分数:" + score);
    }
}

两个子类

package com.fspdu.extend.improve;

public class Pupil extends Student{

    public void testing()
    {
        System.out.println("小学生" + name + "正在考小学数学");
    }
}
package com.fspdu.extend.improve;

public class Graduate extends Student{
    public void testing(){
        System.out.println("大学生" + name + "正在考高等数学");
    }
}

测试

package com.fspdu.extend.improve;

public class Extends01 {
    public static void main(String[] args) {
        Pupil pupil = new Pupil();
        pupil.name = "小白";
        pupil.age = 10;
        pupil.testing();
        pupil.setScore(100);
        pupil.showInfo();

        Graduate graduate = new Graduate();
        graduate.name = "小黑";
        graduate.age = 18;
        graduate.testing();
        graduate.setScore(150);
        graduate.showInfo();
    }
}

测试结果:
小学生小白正在考小学数学
学生名字:小白 年龄:10 分数:100.0
大学生小黑正在考高等数学
学生名字:小黑 年龄:18 分数:150.0

继承带来的便利

1.代码复用性提高
2.代码的扩展性和维护性提高

继承的深入讨论/细节问题

1.子类继承了所有的属性和方法,但是私有属性和方法不能在子类直接访问,可以间接访问,但要通过公共的方法去访问

父类

package com.fspdu.extend;

public class Base {//父类
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;

    public int getN4(){
        return n4;
    }

    public Base(){
        System.out.println("父类无参构造器运行");
    }
    public void test100(){
        System.out.println("test100");
    }
    protected void test200(){
        System.out.println("test200");
    }
    void test300(){
        System.out.println("test300");
    }
    private void test400(){
        System.out.println("test400");
    }
    public void test4(){
        test400();
    }
}

子类

package com.fspdu.extend;

public class Sub extends Base{//子类

    public Sub(){
        System.out.println("子类无参构造器运行");
    }
    public void sayOK(){
        System.out.println(n1 + " " + n2 + " " + n3 + " " + getN4());
        test100();
        test200();
        test300();
        test4();
    }
}

测试

package com.fspdu.extend;

public class ExtendsDetail {
    public static void main(String[] args) {
        Sub sub = new Sub();
        sub.sayOK();
    }
}

测试结果:
父类无参构造器运行
子类无参构造器运行
100 200 300 400
test100
test200
test300
test400

2.子类必须调用父类的构造器,完成父类的初始化

观察上述测试结果:父类无参构造器在子类无参构造器被调用之前先被调用,原因是Sub类里面隐藏了一句话(编译器默认),默认调用父类的无参构造器。

public Sub(){
        super();//默认调用父类的无参构造器
        System.out.println("子类无参构造器运行");
    }

3.当创建子类对象是,不管使用子类的哪一个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过。

父类

package com.fspdu.extend;

public class Base {//父类
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;

    public int getN4(){
        return n4;
    }

    public Base() {
        System.out.println("父类无参构造器运行");
    }

    public void test100() {
        System.out.println("test100");
    }
    protected void test200(){
        System.out.println("test200");
    }
    void test300(){
        System.out.println("test300");
    }
    private void test400(){
        System.out.println("test400");
    }
    public void test4(){
        test400();
    }
}

子类

package com.fspdu.extend;

public class Sub extends Base{//子类

    public Sub(){
        super();//默认调用父类的无参构造器
        System.out.println("子类无参构造器运行");
    }
    public Sub(String cchar){
        System.out.println("子类有参构造器运行");
    }
    public void sayOK(){
        System.out.println(n1 + " " + n2 + " " + n3 + " " + getN4());
        test100();
        test200();
        test300();
        test4();
    }
    public void exce(){
        System.out.println("===========");
    }
}


测试

package com.fspdu.extend;

public class ExtendsDetail {
    public static void main(String[] args) {
        Sub sub = new Sub();
        sub.sayOK();
        Sub sub1 = new Sub("aaa");
        sub1.exce();
    }
}

测试结果:
父类无参构造器运行
子类无参构造器运行
100 200 300 400
test100
test200
test300
test400
父类无参构造器运行
子类有参构造器运行
===========

父类

package com.fspdu.extend;

public class Base {//父类
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;

    public int getN4(){
        return n4;
    }

//    public Base() {
//        System.out.println("父类无参构造器运行");
//    }

    public Base(String name){
        System.out.println("父类有参构造器运行");
    }
    public void test100() {
        System.out.println("test100");
    }
    protected void test200(){
        System.out.println("test200");
    }
    void test300(){
        System.out.println("test300");
    }
    private void test400(){
        System.out.println("test400");
    }
    public void test4(){
        test400();
    }
}

子类

package com.fspdu.extend;

public class Sub extends Base{//子类

    public Sub(){
        super("fsp");//(父类没有无参构造器,用super指定父类构造器完成对父类的初始化)
        System.out.println("子类无参构造器运行");
    }
    public Sub(String cchar){
        super("fsp");
        System.out.println("子类有参构造器运行");
    }
    public void sayOK(){
        System.out.println(n1 + " " + n2 + " " + n3 + " " + getN4());
        test100();
        test200();
        test300();
        test4();
    }
    public void exce(){
        System.out.println("===========");
    }
}

测试

package com.fspdu.extend;

public class ExtendsDetail {
    public static void main(String[] args) {
        Sub sub = new Sub();
        sub.sayOK();
        Sub sub1 = new Sub("aaa");
        sub1.exce();
    }
}

测试结果:
父类有参构造器运行
子类无参构造器运行
100 200 300 400
test100
test200
test300
test400
父类有参构造器运行
子类有参构造器运行
===========

4.如果希望子类指定去调用父类的某个构造器,则在子类构造器中显式的调用一下:

public Xxx(....,....) {
		super(....);
        System.out.println(".....");
    }

5.super在使用时,需要放在构造器第一行(super只能在构造器中使用)

6.super()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器

7.java所有类都是Object类的子类

在这里插入图片描述

8.父类构造器的调用不限于直接父类 将一直往上追溯直到Object类(顶级父类)

9.子类最多只能继承一个父类(指直接继承),即java中是单继承机制

思考:如何让A类继承B类和C类?【A继承B,然后B继承C】

10.不能滥用继承,子类和父类之间必须满足is-a(是一个XXX)的逻辑关系

Music extends Person //不合理
Cat extends Animal //合理

继承的本质分析(重要)

子类创建的内存布局

在这里插入图片描述

按照查找关系来返回信息

在这里插入图片描述

super关键字

基本介绍

super代表父类的引用,用于访问父类的属性、方法、构造器

基本语法

1.访问父类的属性,但不能访问父类的private属性:super.属性名;
2.访问父类的方法,不能访问父类的private方法:super.方法名(参数列表);
3.访问父类的构造器:super(参数列表);只能放在构造器的第一句,只能出现一句

父类

package com.fspdu.super_;

public class A {
    public  int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;

    public void test100(){

    }
    protected void test200(){

    }
    void test300(){

    }
    private void test400(){

    }
}

子类

package com.fspdu.super_;

public class B extends A{

    public void hi(){
        System.out.println(super.n1 + " " + super.n2 + " " + super.n3);
    }

    public void ok(){
        super.test100();
        super.test200();
        super.test300();
    }

    public B(){
        super();
    }
}

super细节

1.调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化)

2.当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、直接访问是一样的效果

this等价于直接访问:先找本类,如果有,则调用;如果没有,则找父类(父类有就调用);如果父类没有,则找父类的父类,直到Object类(提示:如果查找方法或者属性的过程中,找到了但是不能访问,则报错;如果查找过程中没有找到,则提示方法不存在)
super:跳过本类(子类)直接查找父类,后续规则一样

3.super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类中都有同名的成员,使用super访问遵循就近原则。

super和this的比较

在这里插入图片描述

方法重写/覆盖(override)

基本介绍

简单的说:方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名字、返回类型、参数一样,那么我们就说子类的这个方法覆盖(重写)了父类的那个方法

注意事项和使用细节

方法重写也叫方法覆盖,需要满足下面的条件
1.子类的方法的参数,方法名称,要和父类方法的参数,方法名称完全一样
2.子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类
(比如父类返回类型是Object,子类方法返回类型是String)

父类---public Object getInfo(){}
子类---public String getInfo(){}

3,子类方法不能缩小父类方法的访问权限,允许扩大**
public > protected > 默认 > private

父类---void sayOk(){}
子类---public void sayOk(){}

方法重装和方法重写比较

在这里插入图片描述

面向对象编程-多态(非常重要)

提高代码的复用性,有利于代码维护

多【多种】态【状态】基本介绍

方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的

多态的具体体现

1.方法的多态(重写和重载就体现出多态)

package com.fspdu.poly_;

public class PolyMethod {
    public static void main(String[] args) {
        //方法重载体现多态
        A a = new A();
        //我们通过不同的参数个数去调用sum方法,就会去调用不同的方法
        //因此对sum方法来说,就是多种状态的体现
        System.out.println(a.sum(11,22));
        System.out.println(a.sum(11,22,33));

        //方法重写体现多态
        B b = new B();
        a.say();
        b.say();

    }
}

class B{
    public void say(){
        System.out.println("B say()方法被调用");
    }
}
class A extends B{
    public int sum(int n1,int n2){
        return n1 + n2;
    }
    public int sum(int n1,int n2,int n3){
        return n1 + n2 + n3;
    }
    public void say(){
        System.out.println("A say()方法被调用");
    }
}

33
66
A say()方法被调用
B say()方法被调用

2.对象的多态(核心,困难,重点)

重要的几句话:
(1)一个对象的编译类型和运行类型可以不一致
(2)编译类型在定义对象时,就确定了,不能改变
(3)运行类型是可以变化的
(4)编译类型看定义时 = 号的左边,运行类型看 = 号的右边
例:
Animal animal = new Dog();【animal编译类型是Animal,运行类型Dog】
animal = new Cat();【animal的运行类型变成了Cat,编译类型仍然是Animal】

父类

package com.fspdu.poly_.objpoly_;

public class Animal {
    
    public void cry(){
        System.out.println("动物在叫");
    }
}

子类

package com.fspdu.poly_.objpoly_;

public class Dog extends Animal{

    public void cry() {
        System.out.println("dog.cry---小狗汪汪");
    }
}

package com.fspdu.poly_.objpoly_;

public class Cat extends Animal{

    public void cry(){
        System.out.println("cat.cry---小猫喵喵");
    }
}

测试

package com.fspdu.poly_.objpoly_;

public class PolyObject {
    public static void main(String[] args) {
        //对象多态的特点

        //animal 编译类型是Animal
        //运行类型 Dog
        //结果以运行类型为主
        Animal animal = new Dog();
        animal.cry();

        animal = new Cat();
        animal.cry();
    }
}

结果:
dog.cry—小狗汪汪
cat.cry—小猫喵喵

3.多态的使用案例

主人给动物喂食程序

父类:Animal

package com.fspdu.poly_;

public class Animal {
    private String name;

    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
父类:Food

package com.fspdu.poly_;

public class Food {
    private String name;

    public Food(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
子类:Fish
package com.fspdu.poly_;

public class Fish extends Food{
    public Fish(String name) {
        super(name);
    }
}
子类:Bone
package com.fspdu.poly_;

public class Bone extends Food{
    public Bone(String name) {
        super(name);
    }
}
子类:Cat
package com.fspdu.poly_;

public class Cat extends Animal{
    public Cat(String name) {
        super(name);
    }
}
子类:Dog
package com.fspdu.poly_;

public class Dog extends Animal{
    public Dog(String name) {
        super(name);
    }
}
主人类:Master
package com.fspdu.poly_;

public class Master {
    private String name;

    public Master(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public void feed(Animal animal,Food food){
        System.out.println(name + "给" + animal.getName() + "吃" + food.getName());
    }
}
main测试
package com.fspdu.poly_;

public class Poly01 {
    public static void main(String[] args) {
        Master tom = new Master("Tom");
        Dog dog = new Dog("小黑");
        Bone bone = new Bone("牛骨");
        tom.feed(dog,bone);

        Cat cat1 = new Cat("小白");
        Bone fish = new Bone("鱼骨");
        tom.feed(cat1,fish);

    }
}

测试结果:
Tom给小黑吃牛骨
Tom给小白吃鱼骨

4.多态注意事项和细节讨论

多态的前提是:两个对象(类)存在继承关系
多态的向上转型

1)本质:父类的引用指向了子类的对象
2)语法:父类类型 引用名 = new 子类类型();
3)特点:

编译类型看左边,运行类型看右边。
可以调用父类中的所有成员(需遵守访问权限),
不能调用子类中特有成员;
最终运行效果看子类的具体实现。

4)案例

父类
package com.fspdu.poly_.detail_;

public class Animal {
    String name = "动物";
    int age = 10;
    public void sleep(){
        System.out.println("睡");
    }
    public void run(){
        System.out.println("跑");
    }
    public void eat(){
        System.out.println("吃");
    }
    public void show(){
        System.out.println("hello");
    }
}

子类
package com.fspdu.poly_.detail_;

public class Cat extends Animal{
    public void eat(){
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}

测试
package com.fspdu.poly_.detail_;

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

        //(向上转型):父类的引用指向了子类的对象
        //语法:父类类型引用名 = new 子类类型();
        Animal animal = new Cat();
        Object obj = new Cat();//可以吗?可以,因为object也是Cat的父类

        //向上转型调用方法的规则如下:
        //(1)可以调用父类中的所有成员(需要遵守访问权限)
        //(2)但是不能调用子类的特有的成员
        //(3)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
        //animal.catchMouse();  错误

        //(4)最终运行效果看子类的具体实现,即调用方法时,按照从子类开始查找方法,然后调用
        //(5)规则和前面进的方法调用规则一致
        animal.eat();//猫吃鱼
        animal.run();//跑
        animal.show();//hello
        animal.sleep();//睡
    }

}
多态的向下转型

1)语法: 子类类型 引用名 = (子类类型) 父类引用;
2)只能强转父类的引用,不能强转父类的对象
3)要求父类的引用必须指向的是当前目标类型的对象
4)可以调用子类类型种所有的成员

案例:

父类与子类和向上转型一样
package com.fspdu.poly_.detail_;

public class PolyDetail {
    public static void main(String[] args) {
        Animal animal = new Cat();

        //向下转型
        Cat cat = (Cat) animal;
        cat.catchMouse();//猫抓老鼠

    }

}

5.属性没有重写的说法,属性的值看编译类型

package com.fspdu.poly_.detail_;

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

        Base base = new Sub();//向上转型
        System.out.println(base.count);//  10
		
		Sub sub = new Sub();
        System.out.println(sub.count);//   20
    }
}

class Base{
    int count = 10;
}

class Sub extends Base{
    int count = 20;
}

6.instanceOf比较操作符

用于判断对象的运行类型是否为XX类型或是XX类型的子类型

package com.fspdu.poly_.detail_;

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

        BB bb = new BB();
        System.out.println(bb instanceof BB);// true
        System.out.println(bb instanceof AA);// true

        AA aa = new BB();
        System.out.println(aa instanceof AA);// true
        System.out.println(aa instanceof BB);// true

        Object obj = new Object();
        System.out.println(obj instanceof AA);//false

        String str = "hello";
        System.out.println(str instanceof Object);//true

    }
}
class AA{}
class BB extends AA{}

多态的应用

多态数组

数组的定义类型Wie父类类型,里面保存的实际元素类型为子类类型
应用实例:现有一个继承结构如下:要求创建1个Person对象、2个Student对象和2个Teacher对象,统一放在数组中,并调用say方法。
在这里插入图片描述

public class PloyArray {
    public static void main(String[] args) {
        Person[] person = new Person[5];
        person[0] = new Person("Jack",20);
        person[1] = new Student("Jack",18,100);
        person[2] = new Student("Toom",19,120);
        person[3] = new Teacher("King",40,18000);
        person[4] = new Teacher("Qing",50,20000);

        for (int i = 0; i < person.length; i++) {
            System.out.println(person[i].say());//动态绑定机制
        }
    }
}

class Person{   //父类
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = 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 String say(){
        return name + "\t" + age;
    }
}

class Student extends Person{

    private double score;
    public Student(String name, int age,double score) {
        super(name, age);
        this.score = score;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    @Override
    public String say() {
        return super.say() + " score=" + score;
    }
}

class Teacher extends Person{
    private double salary;

    public Teacher(String name, int age, double salary){
        super(name, age);
        this.salary = salary;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    @Override
    public String say() {
        return super.say() + " salary=" + salary;
    }
}

Jack 20
Jack 18 score=100.0
Toom 19 score=120.0
King 40 salary=18000.0
Qing 50 salary=20000.0

多态数组(案例升级)

如何调用子类特有的方法,比如Teacher有一个teach,Student有一个study怎么调用?

public class PloyArray {
    public static void main(String[] args) {
        Person[] person = new Person[5];
        person[0] = new Person("Jack",20);
        person[1] = new Student("Jack",18,100);
        person[2] = new Student("Toom",19,120);
        person[3] = new Teacher("King",40,18000);
        person[4] = new Teacher("Qing",50,20000);

        for (int i = 0; i < person.length; i++) {
            System.out.println(person[i].say());//动态绑定机制
            if(person[i] instanceof Student){
//                Student student = (Student)person[i];
//                student.study();
                ((Student)person[i]).study();//向下转型简写
            } else if (person[i] instanceof Teacher) {
                ((Teacher)person[i]).teach();//向下转型简写
            }else if(person[i] instanceof Person){
                
            }
        }
    }
}

class Person{   //父类
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = 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 String say(){
        return name + "\t" + age;
    }
}

class Student extends Person{

    private double score;
    public Student(String name, int age,double score) {
        super(name, age);
        this.score = score;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    @Override
    public String say() {
        return super.say() + " score=" + score;
    }

    public void study(){
        System.out.println("学生 " + getName() + "正在学习");
    }
}

class Teacher extends Person{
    private double salary;

    public Teacher(String name, int age, double salary){
        super(name, age);
        this.salary = salary;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    @Override
    public String say() {
        return super.say() + " salary=" + salary;
    }

    //特有方法
    public void teach(){
        System.out.println("老师 " + getName() + "正在授课");
    }
}

Jack 20
Jack 18 score=100.0
学生 Jack正在学习
Toom 19 score=120.0
学生 Toom正在学习
King 40 salary=18000.0
老师 King正在授课
Qing 50 salary=20000.0
老师 Qing正在授课

多态参数

方法定义的形参类型为父类类型,实参类型允许为子类类型
应用实例1:前面的主人给动物喂食
应用实例2:
定义员工类Employee,包含姓名和月工资[private],以及计算年工资getAnnual的方法。普通员工和经理继承了员工,经理类多了奖金bonus属性和管理manage方法,普通员工类多了work方法,普通员工和经理类要求分别重写getAnnual方法

测试类中添加一个方法showEmpAnnal(Employee e),实现获取任何员工对象的年工资,并在main方法中调用该方法[e.getAnnual()]

测试类中添加一个方法,testWork,如果是普通员工,则调用work方法,如果是经理,则调用manage方法

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

        Worker tom = new Worker("tom",2500);
        Manager akl = new Manager("akl", 5000, 200000);
        PolyParameter polyParameter = new PolyParameter();
        polyParameter.showEmpAnnual(tom);
        polyParameter.showEmpAnnual(akl);

        polyParameter.testWork(tom);
        polyParameter.testWork(akl);
    }
    public void showEmpAnnual(Employee e){
        System.out.println(e.getAnnual());
    }

    public void testWork(Employee e){
        if(e instanceof Worker){
            ((Worker) e).work();
        }else if(e instanceof Manager){
            ((Manager) e).manage();
        }else {
            System.out.println("不做处理");
        }
    }
}

class Employee{     //员工类
    private String name;
    private double saraly;

    public Employee(String name, double saraly) {
        this.name = name;
        this.saraly = saraly;
    }

    public String getName() {
        return name;
    }

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

    public double getSaraly() {
        return saraly;
    }

    public void setSaraly(double saraly) {
        this.saraly = saraly;
    }

    //得到年工资的方法
    public double getAnnual(){
        return 12 * saraly;
    }
}
class Worker extends Employee{       //普通员工子类

    public Worker(String name, double saraly) {
        super(name, saraly);
    }
    public void work(){
        System.out.println("普通员工 " + getName() + "正在工作");
    }

    @Override
    public double getAnnual() {
        return super.getAnnual();
    }
}

class Manager extends Employee{      //经理子类

    private double bonus;
    public Manager(String name, double saraly,double bonus) {
        super(name, saraly);
        this.bonus = bonus;
    }

    public double getBonus() {
        return bonus;
    }

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }

    public void manage(){
        System.out.println("经理 " + getName() + "正在管理");
    }

    @Override
    public double getAnnual() {
        return super.getAnnual() + bonus;
    }
}

30000.0
260000.0
普通员工 tom正在工作
经理 akl正在管理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值