Java面向对象三大特征

一曲冷凌霜 提交于 2020-04-04 17:52:22

封装

  • 封装的好处
    1、封装之后,复杂的事物被“包起来”了。复杂性封装,对外提供简单的操作入口。比如照相机,照相机内部结构、实现原理都很复杂,然而对于使用者就很简单。
    2、封装之后才会形成真正的“对象”,真正的“独立体”。
    3、封装意味着以后的程序可以重复使用,并且这个事物应该适应性比较强,在任何场合都适用。
    4、封装之后,对于事物本身,提高了安全性【安全级别高】。
  • 封装的步骤
    1、所有属性私有化,使用private关键字进行修饰,private表示私有的,修饰的所有数据只能在本类中访问。(例子:private int age,age属性私有化,在外部程序不能直接访问)
    2、对外提供简单的操作入口,也就是说以后外部程序要想访问age属性,必须通过这些简单的入口进行访问。(属性的访问形式:读取属性的值(get);修改属性的值(set)。)
    3、对外提供两个公开的方法,分别是set方法和get方法:想修改属性,调用set方法;想读取属性,调用get方法。
    4、set方法的命名规范:
    public void set+属性名首字母大写(形参){
    安全控制;
    Java代码;
    }
    例子:
public void setAge(int a){
    if(a<0 || a>150){
      return;
    }
    age = a;
}

get方法的命名规范:
public 参数类型 get+属性名首字母大写(){
安全控制;
Java代码;
}
例子:

public int getAge(){
    if(a<0 || a>150){
      return;
    }
    return age;
}

5、setter和getter方法没有static关键字;有static关键字修饰的方法怎么调用:类名.方法名(实参);没有static关键字修饰的方法怎么调用:引用.方法名(实参)。

继承

  • 作用
    基本作用:代码复用。
    重要作用是:有了继承才有以后“方法的覆盖”和“多态机制”。
  • 继承的语法格式:
    [修饰符列表] class 类名 extends 父类名{
    类体 = 属性 + 方法
    }
  • 单继承
    Java中只支持单继承,一个类不能同时继承很多类,只能继承一个类。在C++中支持多继承
    但是一个类也可以间接继承其他类,例如:
C extends B{
}
B extends A{
}
A extends T{
}

C类直接继承B类,但是C类间接继承了A、T类

  • 关于继承中的一些术语
    B类继承A类:
    A类称为:父类、基类、超类、superclass
    B类称为:子类、派生类、subclass
  • 子类继承父类继承那些数据呢?
    私有的不支持继承
    构造方法不支持继承
    其他数据都可以被继承
  • 默认继承
    Java中假设一个类没有显示继承任何类,该类默认继承JavaSE库中提供的java.lang.Object类。
    //快捷键:查找类型[Open Type]:ctrl + shift + T;
    查找资源:[Open resource]:ctrl + shift + R
继承中的方法覆盖
  • 方法覆盖
    1、方法覆盖又被称为方法重写(override)/(overwrite)
    2、什么时候使用方法重写?
    当父类中的方法已经无法满足当前子类的业务需求;
    子类有必要将父类中继承过来的方法进行重新编写;
  • 代码需要满足什么条件才能构成方法覆盖?
    1、方法重写发生在具有继承关系的父子类之间;
    2、方法重写的时候:方法名相同、返回值类型相同、形参列表相同;
    3、方法重写的时候:访问权限不能更低,可以更高;
    4、方法重写的时候:抛出异常不能更多,可以更少;
    5、建议方法重写的时候尽量复制粘贴!(因为容易出错,导致没有产生覆盖)
  • 重写标注
    1、为了避免错误,可以使用一个特殊的Java语法,称为重写标注,在子类的方法前面放一个@Override。
    2、该标注表示被标注的方法必须重写父类的一个方法。如果具有该标注的方法没有重写父类的方法,编译器将报告一个错误。例如,如果toString被错误地输入为tostring,将报一个编译错误。如果没有使用重写标注,编译器不会报告错误。使用标注可以避免错误。
  • 代码例子:
    在这里插入图片描述
    在这里插入图片描述
    访问权限不能更低:
    在这里插入图片描述
  • 注意
    私有方法不能继承,所以不能覆盖;
    构造方法不能继承,所以不能覆盖;
    静态方法不存在覆盖。
    覆盖只针对方法,不谈属性。

多态

  • 关于Java中的多态语法机制
    1、Animal、Cat、Bird三个类之间的关系:
    Cat继承Animal
    Bird继承Animal
    Cat和Bird之间没有任何继承关系
  • 关于多态涉及到的几个概念:
    1、向上转型(upcasting):
    子类型 转换为 父类型
    又被称为自动类型转换
    2、向下转型(downcasting):
    父类型 转换为 子类型
    又被称为强制类型转换【需要加强制类型转换符】
    3、注意:向上转型和向下转型的前提是具有继承关系!(没有继承关系,程序是无法编译通过的)
    4、代码、例子及内存图
//动物类
public class Animal {
    public void move(){
        System.out.println("动物在移动");
    }
}
//猫类
public class Cat extends Animal{
    //重写父类
    public void move(){
        System.out.println("猫在悄无声息地跑");
    }

    //子类对象特有
    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}
//鸟儿类
public class Bird extends Animal{
    //重写父类
    public void move(){
        System.out.println("鸟儿在飞翔");
    }
    
    //子类特有
    public void fly(){
        System.out.println("bird is flying!");
    }
}
        //使用多态语法机制
        Animal a2 = new Cat();
        /*1、Java程序分为编译阶段和运行阶段*/
        /*2、先分析编译阶段,在分析运行阶段;
        编译无法通过,根本是无法运行的。*/
        /*3、编译阶段编译器检查a2这个引用的
        数据类型为Animal,由于Animal.class字
        节码当中有move()方法,所以编译通过了。
        这个过程我们成为静态绑定,编译阶段绑定。
        只有静态绑定成功之后才有后续的运行。*/
        /*4、在程序运行阶段, JVM堆内存当中
        真实创建的对象是cat对象,那么以下程
        序在运行阶段定会调用cat对象的move()方法,
        此时发生了程序的动态绑定,运行阶段绑定。*/
        /*5、调用的一定是Cat()方法,与重写不
        重写无关,无论是Cat类有没有重写move方
        法,运行阶段一定调用的是Cat对象的move
        方法,因为底层真实对象就是cat对象。*/
        a2.move();
        /*6、cat对象里除了move()方法还有
        catchMouse()方法,但是不能使用
        catchMouse()方法,因为程序编译的
        时候a2引用的数据类型Animal里面没有
        catchMouse()方法,所以编译不通过。*/
        /*7、父类型引用指向子类型对象这种机制
        导致程序存在编译阶段绑定和运行阶段绑定
        两种不同的形态/状态,这种机制可以称为一
        种多态语法机制。*/

Animal和Cat之间存在继承关系,Animal是父类,Cat是子类。
new Cat()创建的对象的类型是Cat,a2这个引用的数据类型是Animal,可见它们之间进行了类型转换。子类型转换成父类型,称为向上转型(upcasting)或者自动类型转换。
Java中允许这种语法:父类型引用指向子类型对象。
在这里插入图片描述

  • 怎么让以上的对象执行catchMouse()方法?
    1、a2是无法调用的,因为a2的数据类型是Animal,Animal中没有catchMouse()方法。
    所以要将a2强制类型转换为Cat类型。(属于子类转父类,所以其为强制类型转换)
    2、什么时候需要向下转型?
    当调用的方法是子类型中特有的,在父类中不存在的,必须进行向下转型。
    3、代码
        /*long x = 100L;
          int y = (int)x;*/
        Cat c2 = (Cat)a2;/*a2在上面的代码中
        被自动转换成了Animal类型,所以需要强转为Cat类型*/
        c2.catchMouse();
        //或者
        ((Cat) a2).catchMouse();
        
        
        //著名的异常:java.lang.classCastException
        Animal a3 = new Bird();
        /*1、以下程序编译是没有问题的,因为编译
        器检查到a3的数据类型是Animal,Animal和
        cat之间存在继承关系,并且Animal是父类型,
        cat是子类型,父类型转换成子类型叫做向下
        转型,语法合格。*/
        /*2、程序虽然编译通过了,但是程序在运行
        阶段会出现异常,因为JVM堆内存当中真实存在
        的对象是Bird类型, Bird对象无法转换成
        cat对象,因为两种类型之间不存在任何继承
        关系,此时出现了著名的异常:
        java.lang.classCastException.类型转换
        异常,这种异常总是在"向下转型的时候"会发生。*/
        Cat c3 = (Cat)a3;
  • “向下转型"存在隐患
    1、以上异常只有在强制类型转换的时候会发生,也就是说“向下转型"存在隐患(编译过了,但是运行错了!)
    2、向上转型只要编译通过,运行一定不会出问题: Animal a = new cat()
    3、向下转型编译通过,运行可能错误: Animal a3 = new Bird(); cat c3 = (Cat) a3;
    4、怎么避免向下转型出现的ClassCastException呢?
    使用instanceof运算符可以避免出现以上的异常。
  • instanceof运算符
    1、语法格式:(引用 instanceof 数据类型名)
    2、以上运算符的执行结果类型是布尔类型,结果可能是true/false
    3、关于运算结果true/false:
    假设: (a instanceof Animal)
    true表示:a这个引用指向的对象是一个Animal类型。
    false表示:a这个引用指向的对象不是一个Animal类型。
    4、代码
        Animal a3 = new Bird();
        if (a3 instanceof Cat){//a3是一个Cat类型的对象
            Cat c3 = (Cat) a3;
            c3.catchMouse();
        } else if(a3 instanceof Bird) {//a3是一个Bird类型的对象
            Bird b2 = (Bird) a3;
            b2.fly();
        }

5、Java规范中要求:在进行强制类型之前采用instanceof运算符进行判断,避免ClassCastException异常的发生,这是一种编程的好习惯。

  • 低耦合,高扩展
    1、现有Master、Dog、Cat三个类:
    Master和Cat, Dog这两个类型的关联程度很强,耦合度很高,扩展力差。
    2、所以要降低程序的耦合度【解耦合】,提高程序的扩展力【软件开发的一个很重要的目标】
    3、创建一个Pet类,使Cat, Dog继承Pet
    这时Master主人类面向的是一个抽象的Pet,不再面向具体的宠物
    4、提倡:面向抽象编程,不要面向具体编程
    面向抽象编程的好处是,耦合度低,扩展力强。
  • 多态的作用是什么?
    降低程序的耦合度,提高程序的扩展力。
    能使用多态尽量使用多态。
    父类型引用指向子类型对象。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!