【JavaSE】继承和多态

目录

前言

1. static

1.1 static修饰成员变量

1.2 类变量的使用场景

1.3 static修饰成员方法

2. 代码块

3. 继承

3.1 为什么会有继承

3.2 继承的语法

3.3 继承后成员的访问

super关键字

3.4 子类的构造器

super和this的联系

继承中的代码块

4. 多态

4.1 多态的定义

4.2 多态实现的条件

方法重写

4.3 多态的好处

4.4 多态的缺陷

5. final

结语


前言

继承和多态就是面向对象的三大特征之二,今天我们就一起来学习怎么使用继承和多态。此外,我还会补充一些其他知识,如static、代码块、final使用等相关知识点。文章很长,耐心观看一定有所获的

1. static

static叫做静态,可以修饰成员变量,成员方法

1.1 static修饰成员变量

成员变量按照有无static修饰,可以分为两种:

  • 类变量:也称为静态成员变量,有static修饰,属于类的,不属于某个具体的对象,是所有对象所共享的
  • 实例变量:就是普通的成员变量,无static修饰,属于某个具体的对象

我们既可以通过对象来访问(对象.类变量),也可以通过类名来访问(类名.类变量),不过更推荐使用类名来访问

1.2 类变量的使用场景

在开发中,如果某个数据只需要一份,而且希望它能被共享(访问、修改),我们就可以用使用类变量来记住它

例子:要求记录用户创建了多少个对象

1.3 static 修饰成员方法

成员方法按照有无static修饰,可以分为两种:

  • 类方法:也称为静态成员方法,有static修饰,属于类的。静态成员一般是通过静态方法来访问的
  • 实例方法:就是普通的成员方法,无static修饰,属于某个具体的对象

我们既可以通过对象来访问(对象.类方法),也可以通过类名来访问(类名.类方法),不过更推荐使用类名来访问

注意事项:

  • 类方法可以直接访问类成员(变量和方法),但不可以直接访问实例成员(变量和方法)
  • 实例方法既可以直接访问类成员,也可以直接访问实例成员
  • 实例方法中可以出现this关键字,类方法中不可以出现this关键字

关于最后一点,仔细想想,因为类方法它是属于类的方法,this是要拿到当前对象的,而类是不依赖对象的,所以类方法中不可以出现this关键字

2. 代码块

代码块是类的五大成分之一(成员变量、构造方法、方法、代码块、内部类),使用{ }定义的一段代码就是代码块。我们通常会把代码块分为四种:

  • 普通代码块
  • 构造块
  • 静态块
  • 同步代码块(博主也不会,后面学到会再讲的)
(一)普通代码块:用{ }直接定义在 方法里的代码块
    public static void main(String[] args) {
        //普通代码块:直接用{}来定义,比较少见
        {
            int a = 10;
            System.out.println(a);
        }
        int b = 20;
        System.out.println(b);
    }

(二)构造块:也叫做实例代码块。它是用{ }定义在中的代码块不加修饰符

特点:每次创建对象时,都会执行构造块,而且它会在构造器前执行

作用:和构造器一样,都是用来完成对象的初始化的

我们能发现,每次创建对象时,构造块都会跟着执行一次,而且会先于构造器执行 

(三)静态代码块:定义在类中使用static修饰的代码块。

特点:在类加载时执行一次,与对象无关,无论产生多少对象,静态代码块只在类加载时执行一次。

作用:对类进行初始化

通过打印结果我们能发现: 静态代码块只执行了一次,它是在类被加载后就执行了,而且它比构造块更早执行

3. 继承

继承,在生活中我们可能会这样使用这个词:某人继承了ta父母的遗产;而在Java中,继承的意思也大体相同

3.1 为什么会有继承

在Java中,我们会对现实世界中复杂的事物抽象成类,并定义它们的属性和功能;但即使是再复杂的事物,它们之间也可能存在共性:狗和猫都是动物,它们能跑能跳,能进食会逗人笑(skr~

我们来看看下面这个代码

我们定义了两个类:Student类和Teacher类,他们的成员变量一模一样的,也有一个完全相同的成员方法。对于这些共性,我们可以设计一个People类,把相同的成员放在里面,再使用继承让三者建立父子关系,实现代码的复用

在上图中,Student类和Teacher类都继承了People类。那么People类就是父类,Student类和Teacher类就是People类的子类,继承之后,子类就可以使用父类中非私有的成员。继承主要解决的问题是:共性的抽取,实现代码的复用

3.2 继承的语法

我们可以使用extends关键字,让一个类和另一个类建立起父子关系

继承的特征

  • 子类会将父类中的非私有成员继承到子类中来
  • 子类在继承后必须要添加新的、有别于父类的成员,这样继承才有意义

Java是单继承的,Java中的类不支持多继承,但是它支持多层继承

即使可以多层继承,一般我们不希望超出三层继承关系,如果继承太多层,那应该对代码进行重构了。如果我们想限制一个类被继承,那么可以在它前面添加final关键字(下面会讲到)

3.3 继承后成员的访问

子类访问父类成员,遵循就近原则

在子类方法中或者通过子类对象访问父类成员变量时

  • 如果访问的成员变量子类中有,优先访问自己的成员变量。
  • 如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
  • 如果访问的成员变量与父类中成员变量同名,则优先访问自己的。
  • 总结:子类自己有优先自己的,如果没有则向父类中找

在子类方法中或者通过子类对象访问父类成员方法时

  • 通过子类对象访问父类与子类中不同名方法时,优先访问自己的成员方法,如果没找到,就访问父类的成员方法,还是没找到就会报错。
  • 通过子类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同 重载) ,根据调用 方法适传递的参数选择合适的方法访问,如果没有则报错;
如果我们想摆脱就近原则,想要访问跟子类同名的父类成员变量,那么就得使用super关键字 

super关键字

Java提供了super关键字,它可以让我们在子类方法中访问父类的成员

要注意的是,super只能在非静态方法中使用,在static修饰的方法中,使用static会报错;

super用来在子类方法中,访问父类成员

3.4 子类的构造器

我们还是用上面的代码来演示,并在父类和子类中加入无参构造器,再生成一个子类对象,看看会发生什么

通过打印结果我们可以得到子类构造器的特点:子类的全部构造器,都会先调用父类的构造器,接着再执行自己的构造器

注意:

  • 在默认情况下,子类全部构造器的第一行代码都是super( )(就算不写也默认有),它会调用父类的无参构造器
  • 如果父类没有无参构造器,即我们在父类中定义了有参构造器,那么我们必须在子类构造器的第一行手写上super(……),指定去调用父类的有参构造器,否则会报错
  • super(……)只能在子类构造器中出现一次,而且不能和this( )同时出现

super和this的联系

我们需要对this补充一个知识点:在任意类的构造器中,是可以通过this(……)去调用该类的其他构造器的,用法如下:

相同点:

  1. 都只能在类的非静态方法中使用,用来访问非静态成员
  2. 在构造器中调用时,必须在第一条语句,而且不能同时出现

不同点:

  1. this是对象的引用;super则相当于子类中父类继承下来的引用
  2. 在构造器中:this(……)用于调用其他构造器;super(……)用于调用父类构造器,而且它们俩不能同时在构造器中出现
  3. 构造器中一定会存在super(……),但是this(……)我们自己不写则没有

继承中的代码块

我们在父类和子类中分别定义静态代码块,构造块,构造器,再创建两个对象,我们来观察一下代码执行顺序

运行结果如下

通过打印结果我们可以得到下面结论:

  1. 实例化对象时,父类的静态代码块最先执行,紧接着是子类的静态代码块
  2. 然后就是父类的构造块和构造器,最后是子类的构造块和构造器
  3. 第二次实例化对象时,父类和子类的静态代码块不会再执行了

4. 多态

4.1 多态的定义

多态是继承情况下的一种现象,表现为:对象多态、行为多态。通俗来讲,就是去完成某个行为时,不同对象去完成时会产生不同的状态

对象多态:比如一个人有多种身份,ta可以是学生,也可以是孩子、公民……

行为多态:比如考试,有的人考的成绩很好,有的人稍差……

4.2 多态实现的条件

  1. 必须在继承体系下
  2. 子类要对父类中的方法进行重写
  3. 存在父类引用子类对象

方法重写

重写(override),也叫做覆盖、覆写。重写是子类对父类中非静态、非private、非final、非构造器等的重新编写。方法名、返回值和形参都不能变,只重写内部代码实现

重写的规则

  1. 子类重写父类方法时,一般必须跟父类方法的“外壳”一致:方法名、返回值类型、参数列表
  2. 被重写的方法返回值类型可以不一样,但是必须是具有父子关系(也称协变类型)
  3. 访问修饰符的权限必须比父类被重写的方法权限更高,这样才能正常重写
  4. 我们可以在重写方法上面标注上@Override,这样编译器可以帮我们矫正一些重写小错误

在认识重写后,我们就可以来写出多态:1.继承;2.子类要对父类中的方法进行重写;3.父类引用子类对象

People s = new Student();

这个就是父类引用子类对象,我们可以这样来理解:学生是属于人,而且人的范围更大,学生的范围比较小;这种现象也有一个称呼:向上转型,即用父类引用来创建一个子类对象

格式一:父类类型 对象名 = new 子类类型()

识别技巧:编译看左边,运行看右边。意思是,我们在用对象去使用方法时,得看父类里有没有定义该方法,而到真正运行时,就会走到子类里重写的方法

格式二:方法传参——public void test(父类类型){ },调用该方法时用子类类型的对象作为参数

格式三:方法返回——public 父类类型 test( ){ return new 子类类型;}

格式二:
public void test1(People p) {

}

格式三:
public People test2() {

    return new Student();
}

要注意的是:多态是对象、行为的多态,在Java中,成员变量是不谈多态的。当父类和子类都有同名成员变量时,通过父类引用,就只能引用父类自己的成员变量

4.3 多态的好处

  1. 可拓展性更强(右边的对象是解耦合的),如果想要更换对象类型,可以直接更换,不需要更改下面的大量代码。——解耦合,类似可拆卸玩具车,我们可以任意更换零件,让玩具车跑得更快,此时该玩具车就是解耦合的
  2. 定义方法时,使用父类类型作为形参,可以接收一切子类对象,扩展性更强、更便利

4.4 多态的缺陷

当然,多态也存在一定的缺陷:多态下不能调用子类独有的功能(因为在编译阶段只有父类里存在该方法才能通过编译,否则会报错)

要想解决这个问题,就得使用强制类型转换,俗称向下转型

但是向下转型我们用得比较少,而且不安全,万一转换失败,运行时就会报错

所以Java中提供了instanceof关键字,如果该表达式为true,则可以安全转换

5. final

final是Java中的一个关键字,表示最终的意思,我们可以用它来修饰变量、方法、类

  • 修饰变量,表示常量(该变量只能被赋值一次)
  • 修饰方法,表示该方法不能被重写
  • 修饰类,表示此类不能被继承
//final用法的演示
public class Test {
    //1.final修饰变量,则变为常量,有且仅能赋值一次
    /* 变量:
       一:局部变量
       二:成员变量
         1.静态成员变量
         2.实例成员变量
    */    
    final int a = 1;
    a = 2; //报错,第二次赋值
    
    //常量:public static final修饰的成员变量,名称要全部大写,多个单词用下划线链接
    public static final String STUDENT_NAME = "flmz";
    
    //2.final修饰方法,方法不能被重写
    class C {
        public final void test() {

        }
    }
    class D extends C {
        //报错
        @Override
        public void test() {

        }
    }

    //3.final修饰类,类就不能被继承了
    final class A {}
    class B extends A{} //报错
}

final修饰变量的时候要注意:

  1. final修饰基本类型的变量时,变量储存的数据不能被改变
  2. final修饰引用类型的变量时,变量储存的地址不能被改变,但是地址所指向对象的内容是可以被改变的
public class Test {
    final int a = 10;
    a = 20; //报错,不能改数据

    final int[] array = {10, 20};
    array = null;  //报错,不能改地址
    array[0] = 20; //改地址指向的内容,可以
}

结语

本篇博客为大家讲解了继承和多态的相关知识,还对static、代码块、super、方法重写、final进行了解释,内容很多,知识点连贯性很强。希望大家能喜欢这篇文章,有总结不到位的地方还请多多谅解,若有出现纰漏,希望大佬们看到错误之后能够在私信或评论区指正,博主会及时改正,共同进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值