文章目录

  • 三大特征
  • 面向对象编程-封装
    • 封装介绍
    • 封装的理解和好处
    • 封装的实现步骤(三步)
    • 封装的简单案例
    • 封装与构造器
    • 封装的练习
  • 面向对象编程-继承
    • 为什么需要继承
    • 继承基本介绍和示意图
    • 继承的基本语法
    • 入门案例(修改上述代码)
    • 继承带来的便利
    • 继承的深入讨论/细节问题
      • 1.子类继承了所有的属性和方法,但是私有属性和方法不能在子类直接访问,可以间接访问,但要通过公共的方法去访问
      • 2.子类必须调用父类的构造器,完成父类的初始化
      • 3.当创建子类对象是,不管使用子类的哪一个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过。
      • 4.如果希望子类指定去调用父类的某个构造器,则在子类构造器中显式的调用一下:
      • 5.super在使用时,需要放在构造器第一行(super只能在构造器中使用)
      • 6.super()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
      • 7.java所有类都是Object类的子类
      • 8.父类构造器的调用不限于直接父类 将一直往上追溯直到Object类(顶级父类)
      • 9.子类最多只能继承一个父类(指直接继承),即java中是单继承机制
      • 10.不能滥用继承,子类和父类之间必须满足is-a(是一个XXX)的逻辑关系
    • 继承的本质分析(重要)
      • 子类创建的内存布局
      • 按照查找关系来返回信息
  • super关键字
    • 基本介绍
    • 基本语法
    • super细节
      • 1.调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化)
      • 2.当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、直接访问是一样的效果
      • 3.super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类中都有同名的成员,使用super访问遵循就近原则。
    • super和this的比较
  • 方法重写/覆盖(override)
    • 基本介绍
    • 注意事项和使用细节
    • 方法重装和方法重写比较
  • 面向对象编程-多态(非常重要)
    • 多【多种】态【状态】基本介绍
    • 多态的具体体现
      • 1.方法的多态(重写和重载就体现出多态)
      • 2.对象的多态(核心,困难,重点)
      • 3.多态的使用案例
      • 4.多态注意事项和细节讨论
        • 多态的前提是:两个对象(类)存在继承关系
        • 多态的向上转型
        • 多态的向下转型
      • 5.属性没有重写的说法,属性的值看编译类型
      • 6.instanceOf比较操作符
    • 多态的应用
      • 多态数组
        • 多态数组(案例升级)
      • 多态参数

三大特征

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

面向对象编程-封装

封装介绍

封装(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.多态的使用案例

主人给动物喂食程序

父类:Animalpackage 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;}
}
父类:Foodpackage 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();//helloanimal.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);//  10Sub 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);// trueSystem.out.println(bb instanceof AA);// trueAA aa = new BB();System.out.println(aa instanceof AA);// trueSystem.out.println(aa instanceof BB);// trueObject obj = new Object();System.out.println(obj instanceof AA);//falseString 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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() + "正在工作");}@Overridepublic 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() + "正在管理");}@Overridepublic double getAnnual() {return super.getAnnual() + bonus;}
}

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

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

  1. Day55-每日一道Java面试题-Java 面向对象编程三大特性: 封装 继承 多态

    Java 面向对象编程三大特性: 封装 继承 多态 封装 封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问.但是如果一个类没有 ...

  2. python多态的三种表现形式_python小结----面向对象的三大特征(封装,继承,多态)

    面向对象的三大特征: 封装,继承,多态 面向对象的编程思想核心:高类聚,低耦合–程序的设计模式范畴 封装 什么是封装: 在面向对象编程的思想中,对代码进行高度封装,封装又叫包装 封装就是指将数据或者函 ...

  3. Python学习笔记④——类、面向对象的三大特征 [封装+继承+多态]

    ✅ Blogger Learns Python is for learning the "Deep Learning". 文章目录 一.面向对象编程的简介 二.类与对象 -- 基础 ...

  4. OC面向对象的三大特征(封装 继承 多态)习题2 复合

    复合:一个类中有一个成员变量是另外一个类的对象. 比如我现在要制作一台电脑,电脑需要CPU,显示器,鼠标和键盘等.这些东西的研发都是很复杂的过程.如果现在有成型的CPU等组件,就可以直接用这些组件攒一 ...

  5. java的知识点11——面向对象的三大特征之一继承、instanceof 运算符、方法的重写override、Object类基本特性、toString方法

    面向对象的三大特征:继承.封装.多态 继承的实现 继承让我们更加容易实现类的扩展.子类是父类的扩展 使用extends实现继承 package cn.sxt;public class Test {pu ...

  6. Java笔记013-IDEA、包、访问修饰符、封装、继承、多态、Super、方法重写/覆盖(override)、java的动态绑定机制

    目录 面向对象编程(中级部分) IDE(集成开发环境)-IDEA IDEA介绍 IDE(集成开发环境)-Eclipse Eclipse介绍 IDEA的安装 IDEA的基本介绍和使用 创建一个java项 ...

  7. 三大特征 封装 继承 多态

    ''' 1.面向对象与面向过程 面向过程:核心过程二字,过程即解决问题的步骤,就是先干什么后干什么 基于该思想写程序就好比在这是一条流水线,是一种机械式的思维方式 优点:复杂的过程流程化 缺点:扩展性 ...

  8. 面向对象编程三大特征之一 继承

    文章目录 继承 概述 语句定义格式 继承的特点 注意事项 继承与成员变量之间的关系 this关键字与super关键字的使用区别 继承与构造方法的关系 继承与成员方法的关系 重写与重载的区别 方法重写的 ...

  9. 面向对象的四大特征 封装 继承 多态 抽象

    1.封装 广义: 类 方法 包 的定义本身就是一种封装 狭义: 在设计一个类的时候 将所有的属性设置为私有的 并对各个私有的属性设计相应的 存/取方法 来完成对属性的使用 私有化只能代表封装的特性 可 ...

最新文章

  1. 004_strace工具
  2. 观百工堰竹筏竞技比赛有感
  3. jQuery 阻止冒泡和默认事件
  4. Android弹出Dialog使用举例
  5. hdu2457 Trie图+dp
  6. powerbi视觉对象_玩转Power BI的图片可视化
  7. poj3179 Corral the Cows(二分, 前缀和, 离散化, 双指针)
  8. JavaScript面向对象之Function类型
  9. qt 工具栏分隔符_带有分隔线和上下文工具栏的RecyclerView Android
  10. web集群之 Keepalived
  11. SQL-Server2008数据库异常报错
  12. MyBatis 拦截器执行顺序
  13. ubuntu的使用--系统目录篇(文末附Desktop目录位置)
  14. QQ游戏连连看自动化脚本(仅限学习交流)
  15. 如何带移动技术团队?
  16. Office excel2010如何用两个文件分别打开两个窗口
  17. 关于ssl证书:pem转成crt文件的最简单方法:直接改后缀名!
  18. 【惊了】迅雷下载速度竟然比不上虚拟机中的下载速度
  19. 配置免密登录报错:ssh: Could not resolve hostname note1: Name or service not known
  20. android pmem内存,android内存管理-ION/PMEM【转】

热门文章

  1. APP-细说APP网络深度优化与网络安全
  2. python代码实现论文〖文献引用顺序〗修改校对
  3. pxcook使用(量尺寸)+盒子模型+残缺新浪导航栏
  4. iis服务器运行失败解决方法
  5. neutron网络服务部署
  6. VBS基础篇 - 对象(4) - Drive对象
  7. C++ 字符串字符转为16进制
  8. Python 线性分类器
  9. Java 图片 基础操作
  10. 网页大面积用ajax好嘛,如何使Ajax发挥最佳效用