第九天 继承、覆盖和多态

什么是继承,有什么用
  • 定义:继承是从已有的类中扩展出新的类,新的类具有父类的数据属性和方法,并能扩展新的能力,
  • 作用:
    • 基本作用:子类继承父类,代码可以得到复用
    • 主要作用:有了继承关系,才有后期的方法覆盖和多态机制
如何继承
class 类名 extends 父类名 {
    类体;
}
继承的特性
  1. B类继承A类
    • 则称A类:超类、父类、基类
    • 而称B类:子类、派生类、扩展类
    • 实例
package Day09继承;

public class Test01 {
}

class A{}

class B extends A{}
  1. java中继承只支持单继承,不支持多继承(体现简单性)
    • 实例
package Day09继承;

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

class C {}

class D {}

class E extends C{}

class F extends D{}

class G extends D,C{}   //java: 需要'{' 说明D后面应该跟‘{’ 而不是其他的类名
  1. java虽然不支持多继承,但是能有产生间接继承的效果
    • 实例:
package Day09继承;

public class Test03 {
}

class X{}

class Y extends X {}

class Z extends Y {}
//这样Z也同时继承了X和Y,不过是直接继承Y,间接继承X而已
  1. java中规定,子类继承父类,除了构造方法以外,其他的都可以继承
    • 私有属性无法在子类中直接访问,即父类中使用关键字 private 修饰的属性不能在子类中直接访问,但是可以通过间接手段访问
    • 实例
package Day09继承;

public class Test04 {
    private String name = "张三";

    String id = "001";

    public Test04(String name, String id) {
        this.name = name;
        this.id = id;
    }

    public Test04(String id) {
        this.id = id;
    }

    public Test04() {
    }

    public String getName() {
        return name;
    }

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

    public static void main(String[] args) {
        //Student student = new Student("张三");
             //原因: 实际参数列表和形式参数列表长度不同 ———— 父类的构造方法无法继承(无论是否有private修饰)

        //实例化子类对象
        Student student1 = new Student();

        //访问父类中使用private修饰的变量
        //System.out.println(student1.name);
        //java: name 在 Day09继承.Test04 中是 private 访问控制 ———— 使用private修饰的父类变量不能继承

        //访问父类中未使用private修饰的变量
        System.out.println(student1.id);    //001

        //通过getName()方法获取private修饰的变量的值
        System.out.println(student1.getName()); //张三

    }
}

class Student extends Test04{

}
  1. 所有对象都有Object类型的所有特征 —— 默认继承
  • 实例
package Day09继承;

public class Test05 extends Object{
}

//public class Test05{}

//以上两个表达式结果是一样的,因为所有类都会默认继承 Object 类
//Object类 是所有类的超类,类体结构中的根
  1. 缺点:耦合度会非常高 —— 一旦父类的代码发生了改变,子类都会收到牵连
通过子类对象调用继承过来的方法
  • 实例
package Day09继承;

public class Test06 {
    public static void main(String[] args) {
        //创建子类对象
        Cat cat = new Cat();
        //表面看起来是子类对象在调用父类的方法,实际上是子类在调用自己的方法。
        // 因为继承后这个方法就是子类的了
        cat.move();

        //通过子类对象访问name
        System.out.println(cat.name);
    }
}

class Animal{
    String name = "汤圆";

    //提供一个动物移动的方法
    public void move(){
        System.out.println(name + "正在跑");
    }
}

class Cat extends Animal{

}
什么时候可以用继承
  • 满足什么条件的时候可以使用继承
    • 凡是采用”is a“能够描述的,都可以
    • 例如
      • Cat is a Animal
      • Dog is a Animal
    • 若 A类 和 B类有相同的代码,但是没有 ”is a“的关系,不一定能使用继承
package Day09继承;

import Day07封装.Person;

public class Test07 {}

class Product{
    String name;
}

class Customer extends Person {
    String name;
}

// Product类和Customer类,虽然有共同的变量,但是他们之间的关系并没有 “is a” 这样的关系,所以这种继承反而不好
方法覆盖
方法覆盖初体验
package Day09继承_覆盖和多态.覆盖;

/*
方法覆盖初体验
* */
public class Test01 {
    public static void main(String[] args) {
        Chinese chinese = new Chinese();
        chinese.speak();    //人类在说话

        American american = new American();
        american.speak();   //人类在说话
        
        //“人类在说话”显然不符合我们的期望,所以有了方法覆盖
    }
}

class Person{
    public void speak(){
        System.out.println("人类在说话");
    }

    public void soSome(){
        System.out.println("doSome...");
    }
}

//子类继承父类之后,有一些行为(方法)不需要改进,而有一些并不满足子类的需求,所以需要改进

class Chinese extends Person{
    //Chinese类在调用speak()方法的时候,希望能输出的是“中国人正在说汉语”
}

class American extends Person{
    //American类在调用speak()方法的时候,希望能输出的是“美国人正在说英语”
}
什么时候考虑使用方法覆盖
  • 子类继承父类后,继承过来的方法满足不了子类的业务需求的时候
  • 子类是可以对某个方法进行重新编写,即进行“方法覆盖”
满足方法覆盖的条件
  1. 两个类之间必须要有继承关系
  2. 重写的方法和之前的方法具有“三同”
    1. 相同的返回值类型
    2. 相同的方法名
    3. 相同的参数列表(个数、类型、顺序)
  3. 访问条件不能更低,可以更高(见包机制和访问控制权限【暂未更新】
  4. 重写之后的方法不能比之前的方法跑出更多的异常,但是可以更少(见异常篇【暂未更新】

注:

  • 当子类的方法对父类的方法进行覆盖之后,子类对象再调用这个方法的时候,调用的是覆盖之后的方法
  • 在进行方法覆盖的时候,最好是将父类中的办法原封不动的复制粘贴过来 or 使用IDEA工具进行方法的覆盖,不建议手写(因为一旦写错就有点麻烦,还不方便找到)

实例:

package Day09继承_覆盖和多态.覆盖;

import java.io.IOException;

/*
方法覆盖初体验
* */
public class Test02 {
    public static void main(String[] args) {

        American1 american1 = new American1();
        Chinese1 chinese1 = new Chinese1();

        //不相同的参数列表 ———— 导致子类中的dance(int i)方法并没有覆盖父类中的dance()方法      ————— 覆盖方法不满足条件2
        chinese1.dance();
        chinese1.dance(1);


    }
}

class Person1{
    public void speak(){
        System.out.println("说话");
    }

    public void soSome(){
        System.out.println("doSome...");
    }

    public void dance(){
        System.out.println("跳舞");
    }

    public void dress() throws IOException{
        System.out.println("穿着");
    }

    public void drink(){
        System.out.println("喝水");
    }
}

//子类继承父类之后,有一些行为(方法)不需要改进,而有一些并不满足子类的需求,所以需要改进

class Chinese1 extends Person1{
    //Chinese类在调用speak()方法的时候,希望能输出的是“中国人说汉语”

    @Override
    public void speak() {
        System.out.println("中国人说汉语");
    }

    public void dance(int i) {
        System.out.println("有" + i + "个中国人正在跳舞");
    }

    @Override
    //    public void dress() throws Exception{   //Chinese1中的dress()无法覆盖Person1中的dress(),被覆盖的方法未抛出java.lang.Exception  ———— 覆盖方法不满足条件4
    public void dress() {
        System.out.println("中国人穿棉袄");
    }

//    protected void drink() {        //Chinese1中的drink()无法覆盖Person1中的drink(),正在尝试分配更低的访问权限; 以前为public    ———— 覆盖方法不满足条件3
    public void drink(){
        System.out.println("中国人喝山泉水");
    }
}

class American1 extends Person1{
    //American类在调用speak()方法的时候,希望能输出的是“美国人说英语”

    @Override
    public void speak() {
        System.out.println("美国人说英语");
    }

    @Override
    public void dress() {
        System.out.println("美国人穿短袖");
    }

    
}
方法覆盖的注意事项
  1. 方法覆盖只针对于方法,和属性无关
  2. 私有方法不能进行覆盖
  3. 因为构造方法不能继承,不满足方法覆盖条件1,所以构造方法也不能覆盖
  4. 方法覆盖只是针对实例方法,静态方法覆盖没意义
toString()方法的覆盖
  • 关于Object类中的toString()方法
    • 作用:将java对象转换成字符串的形式
    • toString()方法的默认实现是不够用的,所以需要程序员进行方法覆盖
    • 默认实现:
//toString()方法的源代码
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
  • 实例:(读者若想看重写toString()方法前后的区别,只需将代码最下方的toString()方法注释即可)
package Day09继承_覆盖和多态.覆盖;

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

        MyDate myDate = new MyDate();

        //这两种写法是一样的,输出对象的时候,后面隐藏了toString();
        System.out.println(myDate);             //Day09继承_覆盖和多态.覆盖.MyDate@4554617c
        System.out.println(myDate.toString());  //Day09继承_覆盖和多态.覆盖.MyDate@4554617c

        //没有重写toString()方法:Day09继承_覆盖和多态.覆盖.MyDate@4554617c
        //重写toString方法后:1999年8月22日

    }
}

class MyDate{
    private int year;
    private int month;
    private int day;

    public MyDate() {
        this.year = 1999;
        this.month = 8;
        this.day = 22;
    }

    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public void setYear(int year){
        this.year = year;
    }

    public int getYear(){
        return year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    //重写toString()方法

    @Override
    public String toString() {
        return this.year + "年" + this.month + "月" + this.day + "日";
    }
}
覆盖五问
  • 什么时候会用到方法覆盖?
  • 什么条件满足的时候构成方法覆盖?
  • Object类的toString()方法的作用?
  • toString()方法具体如何进行覆盖
  • 方法重载和方法覆盖的区别
多态
转型
向上转型
  • 子 ----> 父
  • 父类型引用指向子类型的对象
  • 与“自动类型转换”有异曲同工之妙
向下转型
  • 父 ----> 子
  • 父类引用可以使用在父类中没有,在子类的“特有”方法
  • 需要加强制转换符(与“强制类型转换”相似)

  • 向上转型、向下转型,不要说成自动类型转换和强制类型转换
  • 自动类型转换和强制类型转换是基本数据类型方面的术语,和转型无关
  • 只是为了方便理解,所以才引用了“自动类型转换”和“强制类型转换”这两个概念
多态定义

父类型引用指向子类型对象

多态的两个阶段
  • 编译阶段:静态绑定的是父类中的方法
  • 运行阶段:动态绑定子类型对象的方法

多种形态:编译和运行的时候形态不一样

实例:

package Day09继承_覆盖和多态.多态;

public class Test01 {
    public static void main(String[] args) {
        //使用多态的方式实例化对象(父类型引用指向子类型对象)
        Person person = new Chinese();
        Person person1 = new American();

        //1、没有继承的两个类之间使用多态
        //Chinese chinese = new American();   //java: 不兼容的类型: American无法转换为Chinese

        //调用继承的方法
        person.dress();     //穿羽绒服
        person1.dress();    //穿短袖

        //2、通过两个阶段分析多态
        /*
        分析person.dress():(因为java程序分别有“编译阶段”和“运行阶段”,所以分别从这两个阶段分析)
            编译阶段:
                编译器看到person.dress()的时候,只知道person(变量)是Person类型(类)
                所以会去Person.class的字节码文件中查找dress()方法
                找到之后,绑定上move()方法,编译通过
                静态绑定成功
                (编译阶段属于静态绑定)

            运行阶段:
                运行阶段在堆内存中的Java对象实际上是Chinese,
                所以当调用dress()方法的时候,
                调用的是Chinese类的dress()方法
                这个过程属于动态绑定
                (运行阶段属于动态绑定)
        * */

        //3、使用多态调用子类中特有的方法
        Person person2 = new Chinese();
        //person2.education();      //java: 找不到符号
        /*
        分析:为什么person2不能调用education()方法
            编译阶段:
             编译器执行到这里的时候只知道person2是Person类
             所以去Person.class寻找education()方法
             但是没有找到,静态绑定失败,所以报错:找不到符号
             就是没有找到education()方法
        * */

        //4、向下转型
        Person person3 = new Chinese();
        Chinese person4 = (Chinese)person3;
        person4.education();    //九年义务教育
        /*
        为什么没有报错?
            因为person4是由person3向下转型得到,
            person4就是Chinese类型,自然而然能调用Chinese类型的专属方法
            且:Person和Chinese具有继承关系(这个是前提)
        * */


        //5、向下转型的风险
        Person person5 = new Chinese();
//        American american = (American)person5;
//        american.gun();     //Exception in thread "main" java.lang.ClassCastException:Chinese cannot be cast to American
        /*
        为什么报错了?
            编译阶段:
                编译器检测到person5是一个Person类型
                Person类型和American类型具有继承关系,所以向下转型没有问题
                所以编译阶段没有问题
            运行阶段:
                堆内存中实际创建的是Chinese对象,
                所以实际操作是要将Chinese对象向下转型成American对象,
                因为Chinese类和American类是没有继承关系的
                所以出现异常:ClassCastException ———— 类型转换异常
        * */

        //如何避免情况5? ———— 使用instanceof关键字进行判断
        if (person5 instanceof American){
            American american1 = (American)person5;
            american1.gun();
        }

        if (person5 instanceof Chinese){
            Chinese chinese = (Chinese)person5;
            chinese.education();
        }
    }
}

class Person{
    public void speak(){
        System.out.println("说话");
    }

    public void dress(){
        System.out.println("穿着");
    }

    public void drink(){
        System.out.println("喝水");
    }
}

class Chinese extends Person{
    @Override
    public void speak() {
        System.out.println("说汉语");
    }

    @Override
    public void dress() {
        System.out.println("穿羽绒服");
    }

    @Override
    public void drink() {
        System.out.println("喝山泉水");
    }

    public void education(){
        System.out.println("九年义务教育");
    }
}

class American extends Person{
    @Override
    public void speak() {
        System.out.println("说英语");
    }

    @Override
    public void dress() {
        System.out.println("穿短袖");
    }

    @Override
    public void drink() {
        System.out.println("喝可乐");
    }

    public void gun(){
        System.out.println("可以合法携带枪支");
    }
}
instanceof运算符
  • 如何避免ClassCastException?
    • instanceof在运行阶段动态判断引用指向对象的类型
  • instanceof的语法:
    • (引用 instanceof 类型)
  • instanceof运算符的结果只会:true/false
  • 在任何时候,进行向下转型操作的时候,一定要用instanceof运算符进行判断,从而避免ClassCastException

实例:

package Day09继承_覆盖和多态.多态;

public class Test02 {
    public static void main(String[] args) {
        Person1 person1 = new Chinese1();
        System.out.println(person1 instanceof Chinese1);    //true
        System.out.println(person1 instanceof American1);   //false
    }
}

class Person1{
}

class Chinese1 extends Person1{
}

class American1 extends Person1{
}
为什么要使用instanceof运算符
  • main方法由程序员A编写,需要调用B类中的test方法,B类是程序员B写的
  • 程序员B只知道test方法传入的参数是一个Person类
  • 但是别人调用test方法的时候,可能传入一个Chinese或者American
  • 如果不使用向下转型,就会报错:java.lang.ClassCastException

实例:
程序员A写的main方法

package Day09继承_覆盖和多态.多态.Instanceof;

public class Test03 {
    public static void main(String[] args) {
        Test04 test04 = new Test04();
        test04.test(new American());
        test04.test(new Chinese());    

    }
}

程序员B写的test()方法

package Day09继承_覆盖和多态.多态.Instanceof;
/*
将未使用向下转型的代码取消注释,并将使用了向下转型的代码注释后,
再执行main方法就可以看出有无instanceof的区别了
* */
public class Test04 {
    public void test(Person p){
        //使用instanceof运算符
        if (p instanceof American){
            American american = (American)p;
            american.gun();
        } else if (p instanceof Chinese){
            Chinese chinese = (Chinese)p;
            chinese.education();
        }

        //直接将传入的参数向下转型(如果传入的是Chinese,就会报错)
        /*American american = (American)p;
        american.gun();*/
    }
}

Person类:

package Day09继承_覆盖和多态.多态.Instanceof;

public class Person {
    public void speak(){
        System.out.println("说话");
    }

    public void dress(){
        System.out.println("穿着");
    }

    public void drink(){
        System.out.println("喝水");
    }
}

Chinese类

package Day09继承_覆盖和多态.多态.Instanceof;

public class Chinese extends Person{
    @Override
    public void speak() {
        System.out.println("说汉语");
    }

    @Override
    public void dress() {
        System.out.println("穿羽绒服");
    }

    @Override
    public void drink() {
        System.out.println("喝山泉水");
    }

    public void education(){
        System.out.println("九年义务教育");
    }
}

American类

package Day09继承_覆盖和多态.多态.Instanceof;

public class American extends Person{
    @Override
    public void speak() {
        System.out.println("说英语");
    }

    @Override
    public void dress() {
        System.out.println("穿短袖");
    }

    @Override
    public void drink() {
        System.out.println("喝可乐");
    }

    public void gun(){
        System.out.println("可以合法携带枪支");
    }
}
回顾多态
  • 向上转型和向下转型

    • 向上转型:子类型转型成父类型
    • 向下转型:父类型转型成子类型
      • 需要添加强制类型转换符
      • 在调用子类对象特有的方法的时候需要向下转型
      • 容易出现ClassCastException(类型转换异常)
      • 使用instanceof运算符,可以动态判断
      • 向下转型之前一定要使用instanceof运算符
    • 注:不管是向上转型还是向下转型,两个类型之间必须要有继承关系
  • 多态

    • 多种形态,多种状态
      • 编译和运行有两种不同的状态
    • 编译的时候叫做静态绑定
    • 运行的时候叫做动态绑定
在实际开发中的作用

实例:

  • 创建Person类
package Day09继承_覆盖和多态.多态.实际开发中的作用;

public class Person {
    public void escape(){
        System.out.println("逃跑");
    }
}
  • 创建Terminator类
package Day09继承_覆盖和多态.多态.实际开发中的作用;

public class Terminator {

    /*
    * 最开始的时候,终结者只追杀美国人
    * */
    public void kill(American american){
        System.out.print("终结者追杀" + american + ",");
        american.escape();
    }

    /*
    * 终结者又想去追杀其他人,就不得不该百年 Terminator 这个类的代码
    * */
    public void kill(Chinese chinese){
        System.out.print("终结者追杀" + chinese + ",");
        chinese.escape();
    }

    /*
    * 有没有一种方法就能让终结者追杀所有人呢? ———— 有,使用多态
    * */
    public void kill(Person person){
        System.out.print("终结者追杀" + person + ",");
        person.escape();
    }

    /*
    * 编译的时候,编译器发现形参是一个Person类,于是就去Person类中找escape()方法,找到了,就通过(静态绑定)
    * 实参的具体的人种是不知道的,只知道一定是人
    * 运行的时候,底层对象是什么类型,就调用该类型的escape()方法
    * */

}
  • 创建Chinese类
package Day09继承_覆盖和多态.多态.实际开发中的作用;

public class Chinese extends Person{
    private String name = "中国人";

    public String getName() {
        return name;
    }

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

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

    public Chinese() {
    }

    @Override
    public void escape() {
        System.out.println(name + "往地堡中逃");
    }

    @Override
    public String toString() {
        return name;
    }
}
  • 创建American类
package Day09继承_覆盖和多态.多态.实际开发中的作用;

public class American extends Person{
    private String name = "美国人";

    public String getName() {
        return name;
    }

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

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

    public American() {
    }

    @Override
    public void escape() {
        System.out.println(name + "往防御工事中逃");
    }

    @Override
    public String toString() {
        return name;
    }
}
  • 创建Japanese类
package Day09继承_覆盖和多态.多态.实际开发中的作用;

public class Japanese extends Person{
    private String name = "日本人";

    public String getName() {
        return name;
    }

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

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

    public Japanese() {
    }

    @Override
    public void escape() {
        System.out.println(name + "往海底逃");
    }

    @Override
    public String toString() {
        return name;
    }
}
  • 测试
package Day09继承_覆盖和多态.多态.实际开发中的作用;

public class Test {
    public static void main(String[] args) {
        //创建终结者对象
        Terminator terminator = new Terminator();
        //创建美国人对象
        American american = new American();
        //创建中国人对象
        Chinese chinese = new Chinese();

        //终结者追杀美国人
        terminator.kill(american);  //终结者追杀美国人,美国人往防御工事中逃
        //终结者追杀中国人
        terminator.kill(chinese);   //终结者追杀中国人,中国人往地堡中逃


        //使用多态创建日本人对象
        Person person = new Japanese();
        terminator.kill(person);    //终结者追杀日本人,日本人往海底逃

        //注:如果直接调用escape()方法,就没有体现出终结者去追杀的效果
        person.escape();
    }
}
多态在开发中的作用
  • 降耦合,升扩展
package Day09继承_覆盖和多态.多态.实际开发中的作用;

public class Terminator {
    public void kill(American american){
        System.out.print("终结者追杀" + american + ",");
        american.escape();
    }
    public void kill(Chinese chinese){
        System.out.print("终结者追杀" + chinese + ",");
        chinese.escape();
    }
//Terminator和American、Chinese的关系很紧密(耦合度高,导致拓展力低)

    public void kill(Person person){
        System.out.print("终结者追杀" + person + ",");
        person.escape();
    }
//Terminator和American、Chinese的关系脱离了,Terminator关注的是Person类
//这样Terminator和American、Chinese的耦合度就降低了,软件的扩展力就提高了


}
遗留问题
  1. 私有方法不能覆盖
  2. 方法覆盖只是针对实例方法,静态方法覆盖没有意义
  3. 在方法覆盖中,关于方法的返回值类型

遗留问题1:

package Day09继承_覆盖和多态.多态;

public class Test03 {
    
    //私有方法
    private void doSome(){
        System.out.println("Test03 ----> doSome...");
    }
    
    
    public static void main(String[] args) {

        Test03 person2 = new Chinese2();
        person2.doSome();
        /*
        * 输出的是Test03 ----> doSome...
        * 说明并没有进行方法覆盖
        * */
    }
}

class Chinese2 extends Test03{
    //并没有重写父类中的doSome()方法,因为访问权限不能更低,但是能更高
    public void doSome(){
        System.out.println("Chinese2 ----> doSome...");
    }
}

遗留问题2:
1、方法覆盖要和多态机制联合起来才有意义
2、静态方法不存在方法覆盖

  • 静态方法的调用并不需要对象,而多态和对象有紧密关系,所以,一般情况下,静态方法是不会进行方法覆盖的
package Day09继承_覆盖和多态.多态;

public class Test04 {
    public static void main(String[] args) {
        //虽然静态方法可以使用“引用.”的方式来调用,但是和对象没有关系
        Animal animal = new Cat();
        animal.doSome();    //这里实际上执行的是:Animal.doSome();

        //静态方法的调用方法还是应该用“类名.”
        Animal.doSome();

        //这个不叫方法覆盖
        Cat.doSome();
    }
}

class Animal{
    //父类的静态方法
    public static void doSome(){
        System.out.println("Animal ----> doSome...");
    }
}

class Cat extends Animal{
    //子类“重写”静态方法doSome()
    public static void doSome() {
        System.out.println("Cat ----> doSome...");
    }
}

遗留问题3:

  • 在学习了多态机制之后,可以知道
    • 对于返回值类型是基本数据类型来讲,必须一致
    • 对于返回值类型是引用数据类型来讲,重写之后的返回值类型可以变得更小
package Day09继承_覆盖和多态.多态;

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

    }
}

class MyClass{
    public double sum(int a, int b){
        return a + b;
    }
}

class OtherClass extends MyClass{

//    public int sum(int a, int b) {
    public double sum(int a, int b){
        /*
        * OtherClass中的sum(int,int)无法覆盖MyClass中的sum(int,int),返回类型int与double不兼容
        * */
        return a + b;
    }

    //所以基本数据类型,子类进方法覆盖的返回值和父类的一定要一样
}

class YourClass{
    public MyClass doSome(){
        return null;
    }
}

class HimClass extends YourClass{
    public OtherClass doSome() {
        return null;
    }
    //重写时,返回值类型变小了,是可以的


    /*public Object doSome(){
        return null;
    //HimClass中的doSome()无法覆盖YourClass中的doSome(),返回类型java.lang.Object与MyClass不兼容
    //重写时,返回值类型变大了,是不可以的
    }*/
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
FlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET) { timeout++; if (timeout > 1000000) return -1; } data[2] = SPI_I2S_ReceiveData(SPIx); SPI继承、封装和多是面向对象程序设计中的三个重要概念。 继承是指一个类x_CS_SET; return ((data[1] << 8) | data[2]) & 0x03FF; } void LCD_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |可以继承另一个类的特性,包括属性和方法,被继承的类称为父类或基类, RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO,继承的类称为子类或派生类。子类可以重写父类的方法,也可以添加自己的 ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed =方法和属性,从而实现代码的复用和扩展。 封装是指将数据和方法封装到一个类 GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); 中,并且对外部隐藏类的实现细节,只暴露必要的接口给外部使用。这样 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_5 | GPIO_Pin_6可以提高代码的安全性和可维护性,同时也方便了代码的使用和调用。 多是 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11; GPIO_InitStructure指同一种行为或方法在不同的对象上具有不同的表现形式,即同一操作作.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure用于不同的对象上面,可以产生不同的执行结果。多可以提高代码的灵活性和); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO可扩展性,也是面向对象编程的重要特性之一。 继承、封装和多是_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 |面向对象编程的基础,它们的实现可以让程序更加高效、简洁、易于维护和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值