Java面向对象程序设计(2)封装,继承和多态

面向对象的三大特征是:封装,继承和多态

访问修饰符

java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围) :

访问级别 访问控制修饰符 同类 同包 子类 不同包 公开 public √ √ √ √ 受保护 protected √ √ √ × 默认 无需修饰符 √ √ × × 私有 private √ × × ×

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

封装实现的步骤:

当我们使用构造器进行初始化时,属性的赋值有一定要求(要求在set方法中体现),为了减少冗余的的代码,可以使用set方法在构造器内部初始化对象

当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来声明继承父类即可。 继承可以解决代码复用的问题。

class 子类 extends 父类{
}

  • 子类会自动获得父类的属性和方法
  • 父类又叫基类,超类
  • 子类又叫派生类

使用super可以访问父类的属性,方法和构造器

super.属性名,super.方法名(参数列表),super不能访问父类的私有属性和私有方法, 当子类和父类的属性和方法重名时,如果想要访问父类的成员,必须使用super关键字,没有重名时,使用super,this和直接访问的作用是一样的。

使用 super调用父类的构造器能给编程带来便利:父类的属性调用父类构造器进行初始化,而子类的属性交给子类构造器初始化。

区别点 this super 访问属性和方法 从本类开始向上查找 从父类开始向上查找 调用构造器 调用本类的构造器 调用父类的构造器,子类都会隐式的调用super 意义 表示当前对象 表示父类对象

当我们要实现子类的一个方法,它与父类的某个方法有类似的作用,我们让这个方法与父类的方法具有相同的函数名,返回类型和参数列表,于是子类的这个方法覆盖了父类的方法,或者说我们在子类中重写了父类的这个复方

注意:

  • 子类的形参列表和方法名称必须和父类完全一样,返回类型可以一样,也可以是父类返回类型的子类
  • 子类方法不能缩小父类方法的访问权限

多态是指方法和对象具有多种状态,多态建立在继承和封装的基础上

方法重载和方法覆盖体现了方法的多态,对于方法重载,同一个方法名,我们传入不同的参数,它调用不同的方法。对于方法重写,同一个方法名,当对象是父类对象时调用父类方法,子类会调用子类的方法

对象的多态体现一个父类对象变量既可以引用父类对象也可以引用子类对象,所以多态的前提是存在继承关系,深入理解对象的多态要先理解以下几句话。


* 对象的编译类型和运行类型可以不一致
* 编译类型是指编译器在编译.java文件为.class文件时(javac命令),认定对象的的状态,运行类型是指在运行java文件时(java命令),对象实际的状态

* **用new操作符和构造器初始化对象时,右边的是编译类型,左边的是运行类型,编译类型不可变,但运行类型是可以改变的,这体现了多态
*

Animal animal = new Cat();//编译类型为animal,运行类型Cat
animal = new Dog()//运行类型发生变化,为Dog

当父类的引用指向了子类的对象就发生了向上转型,使用向上转型可以减少冗余的代码。当多个类具有相同的方法,可以在父类中写一个方法,参数设置为父类对象,当调用这个方法时可以使用向上转型,那么它在运行时实际还是把这个对象看出子类对象。
语法:父类类型 对象名 = new 子类类型()

public class Test {
    public static void main(String[] args) {
        Car car1 = new Benz()
        show(car1);
        Car car2 = new BMW()
        show(car2);
    }
}

class Car {
    public void run() {
        System.out.println("这是父类run()方法");
    }

    public void speed() {
        System.out.println("speed:0");
    }

    public void show(Car car) {//父类实例作为参数
        car.run();
        car.speed();
    }
}

class BMW extends Car {
    public void run() {
        System.out.println("这是BMW的run()方法");
    }

    public void speed() {
        System.out.println("speed:80");
    }
}

class Benz extends Car {
    public void run() {
        System.out.println("这是Benz的run()方法");
    }

    public void speed() {
        System.out.println("speed:100");
    }
    public void price() {
        System.out.println("prict:18w");
    }
}

如上面的示例,如果没有使用向上转型,那么如果想要输出每个子类的信息就需要在每个子类中写对应的show()方法。但同时向上转型存在一个问题: 不能调用子类的特有方法,这是在编译过程中,这个对象被看作父类对象,而父类对象没有这个方法,当调用父类和子类共同的方法时,看对象的运行类型。

如前面向上转型提到的问题:不能调用子类特有方法,于是出现了向下转型,向下转型是强制类型转换,子类对象引用了父类类型。进行向下转型 只改变了这个对象的引用而没有改变对象父类的引用必须指向当前目标类型的对象,进行向下转型后就可以使用子类的全部成员
语法:子类类型 引用名 = (子类类型) 父类引用

//接上面的java类
public class Test {
    public static void main(String[] args) {
        Car car1 = new Benz();
        show(car1);
        Benz benz = (Benz) car1;
        benz.price()//向下转型调用子类特有方法
        // BMW benz = (BMW) car1; 这一句会报错,因为当前这个对象指向的Benz类型的对象
    }
}

Java的动态绑定机制可以由以下两句话总结

看一个例子

public class DynamicBinding {
    public static void main(String[] args) {
    //a 的编译类型 A, 运行类型 B
    A a = new B();//向上转型

    System.out.println(a.sum());//输出30
    System.out.println(a.sum1());//输出20
    }
}
class A {//父类
    public int i = 10;
    //动态绑定机制:绑定B类的getI()方法
    public int sum() {
        return getI() + 10;//20 + 10
}
    public int sum1() {
        return i + 10;//使用A类的 i = 10,10 + 10
}
    public int getI() {
        return i;
}
}
class B extends A {//子类
    public int i = 20;

    public int getI() {//子类 getI()
        return i;//使用B类的 i = 20
    }
}

多态的应用由多态数组和多态参数,它们能够很好的解决代码复用的问题

语法:对象变量 instanceof 对象类型
instanceof 关键字可以用来判断某个对象的运行类型是否是目标类型,使用 instanceof关键字向下转型还可以方便的调用子类的特有方法。

数组定义为父类,但是里面的元素可以是父类对象也可以是子类对象,这样可以方便的遍历数组,对不同的对象做相似的处理。
类定义:

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String say(){
        return name + "\t" + age;
    }

    public String getName() {
        return name;
    }
}
class Student extends Person{
    private int score;

    public Student(String name, int age, int score) {
        super(name, age);
        this.score = score;
    }
    @Override
    public String say(){
        return super.say() + "成绩是:" + score;
    }
    //特有方法
    public void examine(){
        System.out.println(super.getName() + "正在考试ing~~~");
    }
}
class Teacher extends Person{
    private String major;

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

    @Override
    public String say() {
        return super.say() + "教授学科是:" + major;
    }
    //特有方法
    public void teach() {
        System.out.println(super.getName() + "正在上课ing~~~");
    }

测试类:

public class PersonTest {
    public static void main(String[] args) {
        Person[] person = new Person[3];
        person[0] = new Person("jack",23);
        person[1] = new Student("Tom",23,80);
        person[2] = new Teacher("Milan",23,"Math");
        //遍历数组调用say方法,并调用特有方法
        for (int i = 0; i < person.length; i++) {
            System.out.println(person[i].say());
            if(person[i] instanceof Student){//判断运行类型
                ((Student) person[i]).examine();//向下转型
            }else if(person[i] instanceof Teacher){
                ((Teacher) person[i]).teach();
            }
        }
    }
}

方法定义的形参类型是父类类型,实参可以是子类类型,在前面向上转型中其实可以直接把子类实参(BMW对象,Benz对象)传给形参(Car对象)。多态参数的使用非常广泛(在jdk的源码中),它能够大大的提高代码的复用性

Object类

对于基本数据类型,我们可以用 == 运算符来判断值是否相等,但是对于引用类型即对象, == 运算符只能用来判断对象变量是否指向了同一个对象,而如果要判断对象本身即属性的值是否相等就需要用到 equals() 方法。 如果类中没有重写 equals() 方法,调用的就是Object类中的方法,它只能判断是否指向同一个引用

@Override
public boolean equals(Object o) {
    if (this == o)//指向同一个对象则一定相等
        return true;
    if (o == null || getClass() != o.getClass())//对象为空或者不是同一个类,则一定不相等
        return false;
    Employee employee = (Employee) o;//向下转型
    return salary == employee.salary && age == employee.age && name.equals(employee.name);
}

返回该对象的哈希码值,由object类定义的hashcode()能根据不同的对象返回不同的整数值,这是通过对象的内部地址经过转换成一个整数实现的重写该方法能够提高哈希表的性能。在学习集合部分后再对该方法作补充。

默认返回:全类名+@+哈希值的十六进制。
子类往往重写 toString 方法,用于返回对象的属性信息

public String toString()
{
    return "Employee[name=" + name
    +", salary=" + salary
    +", age=" + age
    +"]"
}

Original: https://www.cnblogs.com/yjh1024/p/16534028.html
Author: Nights_Watch
Title: Java面向对象程序设计(2)封装,继承和多态

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/620468/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 一条SQL查询语句是如何执行的?

    MySQL是典型的 C/S&#x67B6;&#x6784;(客户端/服务器架构),客户端进程向服务端进程发送一段文本(MySQL指令),服务器进程进行语句处理然后返…

    数据库 2023年5月24日
    073
  • 515. 在每个树行中找最大值

    515. 在每个树行中找最大值 给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。 示例1: 输入: root = [1,3,2,5,3,null,9]输出: […

    数据库 2023年6月16日
    089
  • sql查询结果的排序问题

    在sql语句中的查询语句,不同的写入顺序会导致查询的结果不一样 比如我要查询一个联合表中的同学,如果查询的顺序不一样的话,那么结果就会不同 上图为数据的关系图 下面我们要查询张三老…

    数据库 2023年6月11日
    079
  • spring内嵌cglib包,这里藏着一个大坑

    问题发现 2022-01-21 早上 9 点,订单系统出现大面积的”系统未知错误”报错,导致部分用户无法正常下单。查询后台日志,可以看到大量的 duplic…

    数据库 2023年6月6日
    0100
  • AI+医疗:使用神经网络进行医学影像识别分析 ⛵

    💡 作者:韩信子@ShowMeAI📘 计算机视觉实战系列:https://www.showmeai.tech/tutorials/46📘 行业名企应用系列:https://www….

    数据库 2023年6月14日
    099
  • LeetCode 35. 搜索插入位置

    给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 …

    数据库 2023年6月11日
    061
  • Python实现XMind测试用例快速转Excel用例

    转载请注明出处❤️ 作者:测试蔡坨坨 原文链接:caituotuo.top/c2d10f21.html 你好,我是测试蔡坨坨。 今天分享一个Python编写的小工具,实现XMind…

    数据库 2023年6月11日
    075
  • 数据库的常用命令

    1. 数据操作类语句: SELECT:&#x4ECE;&#x6570;&#x636E;&#x5E93;&#x8868;&#x4E2D…

    数据库 2023年5月24日
    099
  • 205. 同构字符串

    给定两个字符串 s 和 t ,判断它们是否是同构的。 如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的。 每个出现的字符都应当映射到另一个字符,同时不改…

    数据库 2023年6月16日
    077
  • 23种设计模式之迭代器模式

    文章目录 概述 迭代器模式的优缺点 迭代器模式的结构和实现 * 模式结构 模式实现 总结 ; 概述 迭代器模式就是顺序访问聚集中的对象,一般来说,集合中非常常见,如果对集合类比较熟…

    数据库 2023年6月6日
    059
  • Windows10 下使用 telnet 命令

    正常情况下 windows 是使用不了 telnet 命令的: 打开控制面板-》程序和功能-》启用或关闭 Windows 功能 勾选 “Telnet客户端”…

    数据库 2023年6月14日
    072
  • 老板:把系统从单体架构升级到集群架构!

    首发于公众号:BiggerBoy 如题,本文针对工作中实际经验,整理了把一个单体架构的系统升级成集群架构需要做的准备工作,以及为集群架构的升级做指导方针。 本文首先分析了单体架构存…

    数据库 2023年6月11日
    070
  • Python 学习笔记(五)

    我们经常需要从文件中读取数据或向其中写入数据,但要做到这一点,我们需要检查文件是否存在。 SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上…

    数据库 2023年6月16日
    075
  • 小试牛刀:Go 反射帮我把 Excel 转成 Struct

    背景 起因于最近的一项工作:我们会定义一些关键指标来衡量当前系统的健康状态,然后配置对应的报警规则来进行监控报警。但是当前的报警规则会产生大量的误报,需要进行优化。我所负责的是将一…

    数据库 2023年6月6日
    084
  • 新建vue项目

    1、CMD中输入命令行 vue ui 打开一个创建项目的窗口 2、安装插件element ui 3、Idea 打开这个项目即可 4、Idea 运行vue项目 npm run ser…

    数据库 2023年6月9日
    092
  • 百度我为你伤心

    9月9日 我写了一篇文章,原名:事务方块,后改名:事务的本质和死锁的原理 9月10日23点 我突然发现,这个原创文章被转载盗贴,可气的是都没有记录原创地址 早上我查了一下搜索引擎排…

    数据库 2023年6月9日
    081
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球