• 【JAVASE系列】06_继承,多态与final


    一、继承

    1、继承是面向对象的三大特征之一(封装,继承,多态)。

    2、继承基本作用:代码复用。但是继承最重要的作用是:有了继承之后的“方法覆盖”和“多态机制”。

    3、java当中的继承只支持单继承,一个类不能同时继承很多类,只能继承一个类。C++当中支持多继承。

    4、继承语法格式:

    [修饰符列表] class 类名 extends 父类名{
    		类体=属性+方法;
    }
    
    • 1
    • 2
    • 3

    5、关于继承当中的一些术语:

    • B类继承A类:
      • A类称为父类,基类,超类,superclass
      • B类称为:子类,派生类,subclass

    6、在java当中子类继承父类继承了哪些数据?

    • 私有的不支持和继承
    • 构造方法不支持继承
    • 其他数据都可以被继承

    7、虽然java当中只支持单继承,但是一个类也可以间接继承其他类,例如:

    • 下述代码当中:C直接继承B类,但是C类间接继承T,A类
    C extends B{
    }
    
    B extends A{
    }
    
    A extends T{
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    8、java中假设一个类没有显示的继承任何类,则该类默认继承JAVASE当中提供的java.lang.Object

    查找类的快捷键:CTRL+N

    在这里插入图片描述
    9、java中任何一个类中都有Object类的特征

    public class Test04 extends Object{
        public static void main(String[] args) {
            Test04 tt=new Test04();
            tt.toString();
            //这里编译通过了,说明可以调用toString方法
            //即Test04当中有toString方法,是从其父类Object当中继承过来的
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    二、方法覆盖

    回顾方法重载:

    • 方法重载又称为Overload

    • 方法重载的使用时间:当在一个类当中,方法完成的功能类似时,建议方法名相同,这样方便程序员编程

    • 满足方法重载的条件:

      • 在一个类当中
      • 方法名相同
      • 参数列表不同:类型,顺序,个数
    • 方法重载和以下无瓜:

      • 和方法的返回值无关
      • 和方法的修饰符列表无关

    重写
    1、方法覆盖又被称为方法重写(Override)

    2、 什么时候使用方法重写?

    • 当父类当中的方法已经无法满足子类的需求,则此时子类有必要将父类继承过来的方法进行重写,这个重写的过程叫做方法的重写/方法覆盖。

    3、什么条件满足之后方法发生重写?

    • 方法重写发生在具有继承关系的父子类之间
    • 方法重写的时候:方法名相同,返回值类型相同,形参列表相同
    • 方法重写的时候:访问权限不能更低,可以更高
    • 方法重写的时候: 抛出异常不能更多,可以更少

    4、注意

    • 私有方法不能继承,所以不能覆盖
    • 构造方法不能继承,所以不能覆盖
    • 静态方法不存在覆盖
    • 覆盖只针对方法,不谈属性
    public class Animal {
        public void move(){
            System.out.println("动物在移动");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    public class Cat extends Animal{
        public void move(){
            System.out.println("猫在走猫步");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    public class Bird extends Animal{
        public void move(){
            System.out.println("鸟在飞翔");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    三、多态

    关于java当中的多态语法机制:

    • 1、Animal和Cat,Bird三个类之间的关系:
      • Cat继承了Animal
      • Bird继承了Animal
      • Cat和Bird之间没有继承关系
    • 2、面向对象之间三大特征:封装,继承,多态
    • 3、关于多态当中涉及到的几个概念:
    • 向上转型(子类转成父类——自动类型转换)upcasting
    • 向下转型(父类转成子类——强制类型转换)downcasting
    • 注意:无论是向下转型还是向上转型,都需要有继承关系。如果没有继承关系,则程序是无法编译通过的。

    1、向上转型

            Animal a=new Cat();
    
    • 1

    上面的代码分析如下:表示猫是一个动物(等号的右边先执行)

    • 1、Cat is a Animal
    • 2、new Cat():创建的对象的类型是Cat,a这个引用的数据类型是Animal,可见其进行了类型转换
    • 子类转换成了父类,因此称为向上转型
    • 3、java当中允许这种语法:即父类型引用指向子类型对象
    a1.move();
    
    • 1

    在这里插入图片描述

    上面的代码分析如下:

    • 1、程序可以编译通过。先分析编译阶段,再分析运行阶段,
      如果编译无法通过,则根本就无法运行。
    • 2、编译阶段编译器先检查a1这个引用的数据类型是Animal,由于Animal.class字节码当中有move()方法,所以编译通过。这个过程我们称为静态绑定,编译阶段绑定。
    • 3、只有静态绑定成功之后,才有后续的运行。
    • 4、在程序运行阶段,JVM堆内存当中真实创建的对象是Cat对象,则程序在运行阶段一定会调用Cat对象的move方法,此时发生了程序的动态绑定。
    • 5、如果此时将Cat类当中的move方法删除,则显示的结果是Animal当中move方法的结果,但是仍然是使用Cat当中的方法,因为方法有继承。
    • 6、无论Cat类有没有重写move方法,运行阶段一定调用的是Cat对象的move方法,因为底层真实的对象就是Cat对象。
    • 7、父类型引用指向子类型对象这种机制导致程序在编译阶段绑定和运行阶段绑定两种不同的形态/状态,这种机制称为多态语法机制。
    a1.catchMouse()
    
    • 1

    上面的代码无法运行,原因如下:

    • 因为编译阶段编译器检查到a1的类型是Animal类型,从Animal.class的字节码文件当中查找该方法没有找到。导致静态绑定失败,没有绑定成功,即编译失败。

    2、向下转型

    什么时候需要使用向下转型?

    当调用的方法是子类型当中特有的,在父类型当中不存在,则必须进行向下转型。

    a1.catchMouse()
    
    • 1

    如果想让上面的代码可以运行的话,就需要使用向下转型:

    将a1强制类型转换成为Cat类型,a1的类型是Animal类型,转换成为Cat类型,被称为强制类型转换。

     Cat a2=(Cat)a1;
     a2.catchMouse();
    
    • 1
    • 2

    分析:

    以上程序编译是没有问题的,因为编译器检查到a2的数据类型是Animal,而Animal和Cat之间存在继承关系,并且Animal是父类型,Cat是子类型,父类型转换成子类型叫做向下转型,语法合格。

     Animal a3=new Bird();
     Cat a4=(Cat)a3;
    
    • 1
    • 2

    在这里插入图片描述
    分析:以上程序虽然在编译期通关了,但是程序在运行阶段会出现异常,因为JVM堆内存当中真实存在的类型是Bird类型,Bird对象无法转换成Cat对象,因为两种类型之间不存在任何继承关系,此时出现了异常:java.lang.ClassCastException

    • java.lang.ClassCastException:这种异常总是在向下转型的时候发生
    • 以上异常只有在强制类型转换的时候会发生,也就是说向下转型存在安全隐患(编译过了,但是运行错了)
    • 而向上转型只要编译通过,则运行一定不会出问题

    如何避免出现向下转型异常?

    • 使用instanceof运算符可以避免出现以上的异常

    四、instanceof运算符

    在进行强制类型转换之前,建议采用instanceof运算符进行判断,避免异常的发生。

    语法格式:

    引用 instanceof 数据类型
    
    • 1

    以上运算符的执行结果是布尔类型,结果可能是true或者false

    a instanceof Animal
    
    • 1

    关于运算结果:

    • true表示:a这个引用指向的对象是一个Animal类型
    • false表示:a这个引用指向的对象不是一个Animal类型

    例子:

    测试类:

    public class Test05 {
        public static void main(String[] args) {
            Master m=new Master();
            LittleCat c=new LittleCat();
            m.feed(c);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    master主人类:

    public class Master {
        public void feed(LittleCat c){
            c.eat();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    小猫类:

    public class LittleCat {
        public void eat(){
            System.out.println("小猫正在吃鱼!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    以上代码扩展力太差,因为如果要写一个小狗类的话就需要重新建立一个Dog类。

    下面是使用多态之后重新写的代码:

    分析:让每一个动物类都继承Pet类,这样就使用了多态。

    public class Test05 {
        public static void main(String[] args) {
            Master m=new Master();
            LittleCat c=new LittleCat();
            m.feed(c);
            Snake s0=new Snake();
            m.feed(s0);
            Dog d=new Dog();
            m.feed(d);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述
    多态的作用:

    • 降低程序的耦合度,提高程序的扩展能力
    • 能使用多态尽量使用多态
    • 父类引用指向子类对象

    五、final关键字

    1、final定义

    1、final是一个关键字,表示最终的,不可变的。

    2、final修饰的类无法被继承。

    3、final修饰的方法无法被覆盖。

    4、final修饰的变量一旦赋值之后,不可重新赋值。

    5、final修饰的局部变量一旦赋值之后,不可重新赋值【二次赋值】

    6、java语言规定实例变量使用final修饰之后,必须手动赋值,不能采用系统默认值

    public class Final {
        final int age=10;
    //    final int b;//报错,这里必须赋值
        
        public static void main(String[] args) {
            final int m;
            m=10;
    //      m=20;//报错
            final int k=10;
    //      k=20;//报错
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    7、final修饰的引用一旦指向某个对象之后,就不能再指向其他对象,被指向的对象无法被垃圾回收器回收

        public static void main(String[] args) {
            //创建新用户对象
            User u=new User(100);
            //又创建一个新的用户对象,执行到此处的时候以上对象已经变成垃圾数据,等待垃圾回收器的回收
            u=new User(20);
            //创建用户对象
            final User user=new User(30);
    //      user=new User(40);这里报错,因为final修饰的引用一旦指向某个对象之后,就不能再指向其他对象
            user.id=50;//不会报错,final修饰的引用虽然指向某个对象之后不能指向其他对象,但是所指向的对象内部的内存是可以被修改的
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    8、final修饰的引用虽然指向某个对象之后不能指向其他对象,但是所指向的对象内部的内存是可以被修改的

    2、常量

    • final修饰的实例变量是不可变的,这种变量一般和static一起联用,被称为常量
    • java要求所有的常量的名字全部大写,每个单词之间使用下划线分开。

    常量的语法格式:

    public static final 类型 常量名=
    • 1

    例子:

    public class Test01 {
        public static void main(String[] args) {
            System.out.println(Chinese.GUO_JI);
            System.out.println(Math.PI);
        }
    }
    
    class Math{
        public static final double PI=3.1415926;
    }
    
    //中国人
    class Chinese{
        //需求:每一个中国人的国籍都是中国人,而且国籍不会发生改变,为了防止国籍被修改,建议加上final
        //final修饰的实例变量是不可变的,这种变量一般和static一起联用,被称为常量
        //
        public static final String GUO_JI="中国";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    六、package和import

    1、package

    关于java当中的包机制:

    • 1、包又称为package,java中引入package这种语法机制主要是为了方便程序的管理。不同功能的类被分门别类的放到不同的软件包当中,查找比较方便,易于维护。

    • 2、如果定义package语句?

      • 在java源程序的第一行上面编写package语句。
      • package只能编写一个语句。

    语法结构:

    package 包名;
    
    • 1
    • 3、包名的规范:
      • 公司域名倒序+项目名+模块名+功能名

    例如:

    org.apache.tomcat.core;
    com.bjpowernode.oa.user.service;
    
    • 1
    • 2
    • 4、包名要求全部小写,包名也是标识符,必须遵守标识符的命名规则
    • 5、一个包对应的是一个目录,目录之间使用.隔开
    package com.bjpowernode.oa.user.service;
    public class Test01 {
    
    }
    
    • 1
    • 2
    • 3
    • 4

    方法:建包

    • 使用package之后,类名就不在是Test01了,而相应的变成com.bjpowernode.oa.user.service.Test01,当然,相应的文件目录也是如此的
    • 编译:javac java源文件路径(在硬盘上生成一个class文件:Test01.class)
    • 手动方式创建目录,将Test01.class字节码文件放到指定目录下
    • 运行:java com.bjpowernode.oa.user.service.Test01;

    2、import

    • import语句用来完成导入其他类,在同一个包下的类不需要导入。
    • import的语法格式:
    import 类名;
    import 包名.*;
    
    • 1
    • 2
    • import 语句需要编写在package语句之下,class语句之上。
    • java.lang*;不需要手动引入,系统自动引入。lang表示java语言的核心类,不需要手动引入。
    public class Test01 {
        public static void main(String[] args) {
            //`java.lang*;`不需要手动引入,系统自动引入。lang表示java语言的核心类,不需要手动引入。
            //其中String就在lang包当中
            String s="abc";
            System.out.println(s);
            
            //直接编写以下程序错误,因为Date类没有被自动导入,需要我们手动导入
    //      Date d=new Date();
            
            //在类名之前写上包名
            java.util.Date d=new java.util.Date();
            
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    导入以下两个包,就可以直接使用Date类了:

    import java.util.*;
    import java.util.Date;
    
    • 1
    • 2

    最终结论,什么时候需要引入import:

    • 不是java.lang包下,并且不在同一个包下的时候,需要使用import进行引入

    七、访问控制权限修饰符

    1、访问控制权限修饰符来控制元素的访问范围。

    2、访问控制权限修饰符包括:

    • public:表示公开的,在任何位置都可以访问
    • procteced:同一个包下和子类当中可以访问
    • 缺省:只能同一个包下访问
    • private:私有的,只能在本类当中进行访问

    3、访问控制权限修饰符可以修饰类变量,方法。

    4、当某个数据只希望子类使用,则使用protected进行修饰。

    5、修饰符的范围:private < 缺省 < protected < public

    6、类只能使用public和缺省的修饰符进行修饰。(内部类除外)

  • 相关阅读:
    执行mysql-community-libs-8.1.0-1.el8.x86_64.rpm报错依赖检测失败
    如何从一门编程语言过渡到另一门编程语言?
    7.5 - 防火墙 7.6 - 安全协议
    IntelliJ IDEA 2023.2正式发布,新UI和Profiler转正
    Tomcat线程池与Fork/Join使用
    【老生谈算法】matlab实现巴特沃斯IIR滤波器程序设计源码
    Java学生管理系统升级版
    STC 51单片机54——气压水压计HX710B 串口显示均值滤波+滑窗滤波
    软件设计模式(二):工厂、门面、调停者和装饰器模式
    Java-数据结构-矩阵专题
  • 原文地址:https://blog.csdn.net/wxfighting/article/details/125523286