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)

大家都在看

  • 摸鱼系列之idea摸鱼插件推荐

    前言 作为一枚程序员,上班时候正撸着代码呢,撸不出代码了,没灵感了,看需求念头不通达了,脑瓜里蹦不出一丁点火花了,这时候怎么办?程序在运行,还要好几分钟,等待时间里,白白浪费了,玩…

    数据库 2023年6月16日
    0135
  • 没有 Cgroups,就没有 Docker

    Cgroups 是什么? Cgroups 是 control groups 的缩写,是 Linux 内核提供的一种可以 限制、 记录、 隔离进程组(progress groups)…

    数据库 2023年6月6日
    0117
  • 将侧边栏制成inclusion_tag

    在开发过程中,像侧边栏这种功能的版块,我们在很多页面都需要使用到的时候,我们则需要在视图函数中书写重复的代码,这样很繁琐,我们可以将侧边栏制成inclusion_tag,后面我们需…

    数据库 2023年6月14日
    083
  • 解决 IDEA 2021.2.3 新建maven项目只有两个archetype项目模板的问题

    最近把我的 IDEA 版本更新到 2021.2.3 了,发生了一个比较有意思的问题,做个小小的记录 思路分析 在新的 IDEA 中配置完Maven之后,想要创建Maven项目的时候…

    数据库 2023年6月11日
    084
  • 基于Redis&MySQL接口幂等性设计

    基于Redis&MySQL接口幂等性设计 欲把相思说似谁,浅情人不知。 幂等性即多次调用接口或方法不会改变业务状态,可以保证重复调用的结果和单次调用的结果一致。 前端重复提…

    数据库 2023年6月14日
    091
  • ATM系统开发(Java版)

    ATM系统Java模拟开发总结 ATM系统开发 技术点分析 1.面向对象编程 每个用户的账户都是一个对象,所以需要设计账户类Accent用于创建账户对象封装账户信息。 2.使用集合…

    数据库 2023年6月16日
    076
  • Java面试题(四)–RabbitMQ

    1、MQ有哪些使用场景?(高频) 异步处理:用户注册后,发送注册邮件和注册短信。用户注册完成后,提交任务到 MQ,发送模块并行获取 MQ 中的任务。 系统解耦:比如用注册完成,再加…

    数据库 2023年6月16日
    087
  • mysql绿色版在windows系统中的启动

    Original: https://www.cnblogs.com/java265/p/15597871.htmlAuthor: java265Title: mysql绿色版在wi…

    数据库 2023年5月24日
    094
  • springboot~手动加载thymeleaf模版

    thymeleaf在spring-mvc时代很是盛行,与freemaker组成了两大模版引擎,而进行springboot之后,很多项目都采用前后分离的模式,这使得模板引擎关注度少了…

    数据库 2023年6月6日
    0122
  • day04-1群聊功能

    多用户即时通讯系统04 4.编码实现03 4.5功能实现-群聊功能实现 4.5.1思路分析 群聊的实现思路和私聊的实现非常类似。 不同的是:私聊时,服务端接收到消息后,只需要找出接…

    数据库 2023年6月11日
    090
  • Java学习-第一部分-第二阶段-第一节:面向对象编程(高级)

    面向对象编程(高级) 笔记目录:(https://www.cnblogs.com/wenjie2000/p/16378441.html) 类变量和类方法(static) 类变量 类…

    数据库 2023年6月11日
    0107
  • day03-2无异常退出

    多用户即时通讯系统03 4.编码实现02 4.3功能实现-无异常退出系统 4.3.1思路分析 上述代码运行时,在客户端选择退出系统的时候,可以发现程序并没有停止运行,原因是: 退出…

    数据库 2023年6月11日
    092
  • mysql5.7初始化密码报错 ERROR 1820 (HY000): You must reset your password using ALTER USER statement before

    mysql初始化密码常见报错问题1,mysql5.6是密码为空直接进入数据库的,但是mysql5.7就需要初始密码 cat /var/log/mysqld.log | grep p…

    数据库 2023年6月16日
    067
  • DASCTF 冰墩墩

    SimpleFlow 一下子就能发现传了一个含有flag.txt的压缩包,需要密码,字典简单跑一下就发现是 <span class=”ne-text”>PaSsZiPW…

    数据库 2023年6月11日
    080
  • COM组件 学习笔记

    COM组件是 以Win32动态链接库dll或可执行文件exe的形式发布的可执行代码组成的; COM组件是动态链接的,COM使用dll将组件动态链接起来; COM组件是语言无关的; …

    数据库 2023年6月14日
    076
  • 基于Spring实现策略模式

    背景: 看过很多策略模式,总结下来实现原理大体都差不多,在这里主要是讲解下自己基于Spring更优雅的实现方案;这个方案主要是看了一些开源rpc和Spring相关源码后的一些思路,…

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