08-面向对象三大特征

引言

前面的章节咱们掌握了,面向对象的基本使用,除此以外,面向对象思想还具备三大典型特征,分别是封装 继承多态,面向对象的三大特征,就是面向对象思想的核心,使用这三特征,可以设计更为安全,简洁,灵活的程序。

一. 封装

1.1 封装概念

封装的意思,广义的封装,指的是把物体装起来,例如CPU的封装技术,在编程语言中的封装,往往指的是,把数据有效保护起来,对其访问设定限制,达到保护数据,使数据不被破坏,达到数据安全的目的。
image.png

1.2 实现封装

Java中实现封装是通过 private 关键字实现, private 意为私有的意思,指的是如果一个属性 或者 方法被其修饰,那么这个属性和方法就只能在其声明的类中使用。

语法:

class Foo{
   private int age;
    
   public void aa(){
   
   }

}

class TestFoo{
 
    public static void main(String[] args){
    
        Foo foo = new Foo();
        foo.age=100; //报错,此时age是无法被访问的。 
    }
}

1.3 访问被私有化属性

一个属性被私有化以后,出了本类的其他地方,都无法访问,这是,如果外界有需要对其访问,咱们可以提供 数据访问的方法,如果要取值提供get方法,如果要赋值提供set方法,如果都需要,则都提供。

class Foo{
   private int age;
   public int getAge(){       // 取值方法
      return this.age;
   } 
   public int setAge(int age){// 赋值方法
      this.age = age;
   } 
}

这里的取值 设值 方法都是有行规的 set+属性(首字母大写) get+属性名(首字母大写) , 事实上这个规范称为 JavaBean 规范。

设计模式:23个

二. 继承

继承,来源于生活,生活中继承,是指后代获得父辈的资产,通过继承,后代可以获得这些资源而无需重复创造,得利得是后代。这种思想,在编程中也成立,在编程中,后代获得的是父辈定义的属性和行为,可以理解是代码的继承。
image.png

2.1 父类建立

继承是两个类的事情,要使用继承特性,首先需要分析出父子类,父类的抽取是关键,父类于子类通常存在一种关系,就是 is-a ** 的关系,描述为是一种的关系,比如 狗是一种动物, 汽车是一种交通工具,等等 ,当然,这里对父类的抽取也需要把握度,也往上越抽象, 父类的作用就是定义子类需要的属性和行为,也叫共性 ,**差异部分,需要子类自己定义。
image.png

2.2 继承语法

继承的语法关键字为 extends , 子类名 extends 父类名。

class Animal{

}

class Dog extends Animal{
   
}

一个类如果没有显示继承任何父类,那么默认继承Object

2.3 继承特点

避免 多继承 c++ 类都了可能会出现 环形集成
Java中的继承为单继承,也就是一个类最多只有一个直接父类,但可以多级继承,同样可以为子类扩充更多的属性和方法。
image.png

2.4 不可继承

子类继承父类,并不是所有父类的东西都可继承。

  1. **构造器不可继承 **(构造器名字必须和类名一致)
  2. 私有化的属性不可继承(只有本类使用)private
  3. 默认属性 跨包不可继承(default 为同包访问级别)

继承练习

/**
 *
 *  动物:Animal
 *    [  属性 ]  颜色  年龄
 *    [  方法 ]  eat()吃  睡 sleep()
 *
 *
 *  狗 Dog
 *    [属性]   名字
 *    [方法]   lookDoor()
 *
 *
 *  猴  Monkey
 *    [属性]   无新增
 *    [方法]   play()
 *
 *  猪 Pig
 *    [属性]   体重
 *    [方法]   cross()
 *
 *
 *
 *  实例化动物调用方法。
 *
 *
 */

image.png

2.5 访问修饰符

image.png

从宽到严 public protected default private

总结: 子类的属性和方法,有自己特有的 叠加上 从父类继承来。

选择修饰符的经验: 属性在没有明确要求的情况下 ** private 方法在没有说明的情况下使用 public 务必要子类继承到的属性和方法使用 protected**

定义属性 用private 所有类 和 方法 public

思考:类 可以用 private? 类不能用private

2.6 方法重写[多态灵活性的基础]

面向对象的编程语言中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类继承来的方法并不适用,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。

image.png
1.发生方法重写的两个方法返回值、方法名、参数列表必须完全一致(子类重写父类的方法)。
2.子类抛出的异常下不能超过父类相应方法抛出的异常(子类异常不能大于父类异常)。
3.子类方法的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别)。

@Override 它是一个注解,用来检验方法是否重写正确。它不是必要的,建议加上防止重写错误。

public class Animal {
      protected String name;
      protected int age;
      protected String sex;

    public Animal(){

    }
    public Animal(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public  void eat(){
        System.out.println("吃");
    }
    public  void sleep(){
        System.out.println("睡");
    }
}

public class Dog extends  Animal{

    //共性属性和方法无需定义了,继承就可以了

    //子类特有的属性和行为
    String color;

    public void lookDoor(){
        System.out.println("看门");
    }

    //重新继承的方法
    @Override
    public void eat() {
        System.out.println("吃骨头");
    }

    @Override
    public void sleep() {
        System.out.println("躺着睡");
    }
}

2.7 对象创建过程

如果引入继承后,子类的创建过程会导致相关父类初始化而触发相关父类的构造器执行。具体过程是,先分配子类对象所需实例空间,然后依次递归调用父级的方法初始化属性。

方法的作用是初始化对象的方法。一般通过new 创建对象 则会触发。

  1. 分配子类所需的空间(自己实例属性空间和 父类继承实例空间)
  2. 递归调用父级的方法( 属性的赋值+构造器的执行 )
  3. 递归返回,完成自己的初始化方法( 属性的赋值+构造器的执行 )
class Super{
    String sex = "男";  //1
    public Super(){
        System.out.println("Super()");//2
    }
}
class Father extends Super{

    String name="admin";//3

    public Father(){
        System.out.println("Father()");//4
    }
}
class Son extends Father{

    int age=19;//5

    public Son(){
        System.out.println("Son()");//6
    }

}
public class ObjectCreateDemo {

    public static void main(String[] args) {

        Son son = new Son();
    }
}

2.8 Super关键字

  1. super 可以访问到父类中声明的属性和方法。
/**
 * 理解Super的作用
 */
public class SuperDemo {

    public static void main(String[] args) {
        Son son = new Son();
        son.happy();
    }

}
class Father{
    String  name="张飞";
    int age;
    public void happy(){
        System.out.println("打麻将.....");
    }

}

class Son extends Father{
    String hobby;
    String name="刘备";
    @Override
    public void happy() {
        super.happy();
        System.out.println("蹦迪......"+super.name);
    }
}

如果子类 存在方法重写 和 属性遮蔽 , 可以通过 super.xxx 来强制区分。

  1. super 可以调用父类的构造器。
class Father{
    String  name;
    int age;

    public Father(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void happy(){
        System.out.println("打麻将.....");
    }

}
class Son extends Father {

    String hobby;
    public Son(String hobby,String name, int age){
        super(name,age);// 调用父类构造器
        this.hobby=hobby;
    }

    @Override
    public void happy() {
        System.out.println("蹦迪......");
    }
}

三. 多态

指的的是 一个对象的多种状态,不同状态下,具有不同的行为。从语法角度讲,就是 父类的引用可以指向任意子类对象。

3.1什么是多态

从语法上讲,就是 通过_父类类型的引用保存子类对象_,通过不同父类调用不同的行为。通过父类只能调用父类中声明的属性和方法,无法调用子类特有的属性和方法
image.png
这里 lookdoor()就是子类特有的方法。

//动物:父类
public class Animal {

    public void eat(){
        System.out.println("eat()");
    }
    public void sleep(){
        System.out.println("sleep()");
    }
    public void shit(){
        System.out.println("shit()");
    }
}

//Dog 子类
public class Dog extends Animal {

    @Override
    public void eat() {
        System.out.println("啃着吃....");
    }

    @Override
    public void sleep() {
        System.out.println("躺着睡....");
    }

    @Override
    public void shit() {
        System.out.println("找个电线杆尿....");
    }
    
    
    //特有方法
    public void  lookDoor(){
        System.out.println("看门.....");
    }

}



// Cat 子类
public class Cat extends Animal {

    public void eat(){
        System.out.println("吃鱼");
    }
    public void sleep(){
        System.out.println("上树睡觉");
    }
    public void shit(){
        System.out.println("猫砂盆里尿");
    }

    //特有方法
    public void catchMouse(){
        System.out.println("捉老鼠");
    }

}

public class Test {
    public static void main(String[] args) {
        Animal obj = new Dog(); // 这里为多态
        obj.eat();
        obj.shit();
        obj.sleep();
        //obj.lookDoor();
        //obj.catchMouse();
    }
}

3.2多态中的重写

多态语法中,通过父类的引用去调用方法,分情况讨论,如果这个方法被子类重写过,那么调用子类重写的方法,如果子类没有重写,调用父类中的方法。多态语法可以记一个口诀: 编译看左边(能调用什么东西),运行看右边(实际运行的是谁)。

public class Test {
    public static void main(String[] args) {
        Animal obj = new Cat();
        obj.eat();
        obj.shit();
        obj.sleep();
        //obj.lookDoor();  报错
        //obj.catchMouse(); 报错
        //解释: 这里 obj 是Animal 类型的引用只能调用 Animal 声明的方法, 而注释掉的方法属于子类的特有方法。
    }
}

3.3 类型转换

// 自动类型提升 : 安全 自动完成
Animal an = new Cat();
// 向下转型 : 不安全 手动完成
Dog dd  = (Dog)an; //java.lang.ClassCastException: case6.Cat cannot be cast to case6.Dog
dd.lookDoor(); 

3.4 instanceof 关键字

作用是判断一个引用是否为指定的类型 语法为 引用 instanceof 类型 如果该表达式成立返回 true ,否则返回false

 public static void main(String[] args) {
        System.out.println("--------转型-----------");
        // 自动类型提升 : 安全 自动完成
        Animal an = new Dog();
        // 向下转型 : 不安全 手动完成
        //Dog dd  = (Dog)an; //java.lang.ClassCastException: case6.Cat cannot be cast to case6.Dog
        //dd.lookDoor();
        // 转型前判断一下
         an.Animal中声明的方法

             
        if( an instanceof Cat  ){
             Cat xx= (Cat)an;
             xx.catchMouse();
        }
     
     
        if( an instanceof  Dog ){
            Dog yy = (Dog)an;
            yy.lookDoor();
        }
     
 }

3.5 多态应用场景

  1. 父类类型做参数
//主人
public class Master {
    /* 这两个方法重载,可以使用多态优化为一个方法
    //接收一个 Dog 类型的参数
    public void  feed( Dog obj  ){
        obj.eat();
    }
    //接收一个 Cat 类型的参数
    public void  feed( Cat obj  ){
        obj.eat();
    }
    */
    //接收一个 Animal 类型的参数
    public void  feed( Animal obj  ){ //Animal obj = cat = new Cat();
        obj.eat();
    }
    public static void main(String[] args) {
        Dog dog = new Dog();
        Cat cat = new Cat();
        Master master = new Master();
        master.feed(  cat  ); // 这里可以传  cat 和  dog对象 均可。
    }

}
  1. 父类型做返回值
//主人
public class Master {
    //接收一个 Animal 类型的参数
    public void  feed( Animal obj  ){
        obj.eat();
    }

    //返回值为父类类型
    public  Animal  kill(){
        Random random = new Random();
        int num = random.nextInt(2);
        if( num == 0 ){ //杀个狗
            Dog dog = new Dog();
            return dog;
        }else{ //杀个猫
            Cat cat = new Cat();
            return cat;
        }
    }
  
}

3.父类型定义数组,可以保存各种子类对象

    public static void main(String[] args) {
        Animal[] arr = new Animal[4];
        arr[0] = new Cat();
        arr[1] = new Dog();
        arr[2] = new Cat();
        arr[3] = new Dog();
        for( Animal an : arr){
            an.eat();
        }
    }

4. 类与类的关系

4.1 什么是依赖

比如A类使用B类,就是说明A是依赖于B的,通常依赖存在一下集中情况。

4.2 聚合

一个类A的属性是另一个B类型,B类型的这个属性就是聚合属性。
私家车案例

public class Car  {

    private String brand;

    public Car() {
    }

    public Car(String brand) {
        this.brand = brand;
    }

    public void run(){
        System.out.println(brand+"行驶....");
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }
}

public class Person {
    private String name;
    //存在一个属性
    private Car myCar;

    public Person() {

    }

    public Person(String name, Car myCar) {
        this.name = name;
        this.myCar = myCar;
    }

    //开车方法
    public void drive(){
        //无需外接提供汽车,自己都有
        this.myCar.run();
    }

    public String getName() {
       
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Car getMyCar() {
        
        return myCar;
    }

    public void setMyCar(Car myCar) {
        this.myCar = myCar;
    }
}

4.3 参数依赖

一个方法的参数是另一个B类型,这样就是方法依赖某个类型。
代驾案例

 
public class Person {
    
    private String name;

    public Person() {

    }
    public Person(String name) {
        this.name = name;

    }
    //开车方法
    public void drive( Car car ){
        //需要外部传入一个汽车对象
        car.run();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

4.4 继承

继承在本章节中,已经重点讨论过了,如果一个类需要使用其他类的功能,继承也是一种方案,通过继承其他类,来获得其他类的行为,但是这种情况,通常是自己和继承的其他类是同一种事物。这种耦合对是非常高的,一般不继承,就不要轻易继承,继承是一种侵入式的编程方式。
汽车人案例

public class Car {

    private String brand;

    public Car() {
    }

    public Car(String brand) {
        this.brand = brand;
    }

    public void run(){
        System.out.println(brand+"行驶....");
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }
}

public class Person extends Car {
    private String name;

    public Person() {

    }
    public Person(String name) {
        this.name = name;

    }
    //开车方法
    public void drive(   ){
        //无需外接提供汽车,自己从父类继承了行驶方法
        this.run();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

软件设计遵循的一个原则高内聚 低耦合
关于耦合度高低: 参数耦合 < 属性聚合 < 继承。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值