欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

带你从零学大数据系列之Java篇---第七章:面向对象三大特性

程序员文章站 2022-07-04 10:29:57
...

课程重点:

  • 封装的概念
  • 单例的实现应用
  • 继承的概念
  • 继承中的super
  • 继承中的重写
  • 多态的概念
  • 多态的向上转型,向下转型

7.1. 封装

7.1.1. 封装性概念

所谓封装, 其实就是将某些功能私有化。 内部实现的逻辑不必暴露出来, 外界直接使用这个方法即可, 不需要关注这个方法是怎样实现的。

还有属性的封装, 某些属性是不能直接暴露给外界操作的, 因为外界直接访问进行的赋值, 可能会有逻辑上的错误。 因此这些属性需要私有化了, 不让外界直接访问。 但是私有化的同时, 必须同时提供对应的访问的方法。 在这些访问的方法中, 可以实现对某些不符合逻辑的数据进行过滤。

7.1.2. 属性封装的案例

/**
* @Description 属性封装
*/
public class Person {
   private int age;// 将年龄私有化, 外界不能直接访问。
   
   // 属性的 setter 方法, 外界需要使用这个方法设置这个属性的值。
   public void setAge (int age) {
       // 在方法里面, 对值进行过滤
       if( age < 0 || age > 130) {
           return;
      }
       this.age = age;
  }
   
   // 属性的 getter 方法, 外界需要使用这个方法获取这个属性的值。
   public int getAge () {
       return this.age;
  }
}

 

7.1.3. 单例设计模式

设计模式, 是由前人总结出来的, 用来解决特定问题而存在的解题思路。

单例设计模式: 一个类有且只有一个对象。 在程序的任意模块, 获取到这个类的对象, 是相同的对象。

单例设计模式, 分为 饿汉式单例 和 懒汉式单例

 

饿汉式单例

/**
* @Description 饿汉式
*/
public class Boss {
   // 1. 先将无参构造方法私有化,杜绝外界通过 new 的方式实例化对象的可能性。
   private Boss () {
       System.out.println ("实例化了一个BOSS对象");
  }
​
   // 2. 定义一个 private 权限的、静态的、当前类的对象,并实例化
   //   这里,对一个静态属性实例化,发生于类第一次加载到内存中
   //   相当于在静态代码段中进行实例化
   private static Boss instance = newBoss ();
​
   // 3. 设置一个方法,需要能够得到一个当前类的对象
   public static Boss getInstance () {
       // 无论调用多少次这个方法,下方返回的对象应该是同一个对象
       return instance;
  }
}

 

懒汉式单例

/**
* @Description 懒汉式
*/
public class Chairman{
   // 1. 私有化无参构造
   private Chairman () {
       System.out.println ("实例化了一个Chairman对象");
  }
​
   // 2. 声明一个private权限的、静态的、当前类的对象
   //   这个静态的、当前类的对象,暂时不实例化
   private static Chairman instance;
​
   // 3. 提供一个静态的方法,用来获取当前的对象
   public static Chairman getInstance () {
       // 当需要使用到这个对象的时候,再实例化
       if(instance == null) {
           instance = newChairman ();
      }
       return instance;
  }
}

 

7.2. 继承

7.2.1. 程序中的继承

程序中的继承, 是类与类之间的特征和行为的一种赠予或获取。 一个类可以将自己的属性和方法赠予其他的类, 一个类也可以从其他的类中获取他们的属性和方法。

两个类之间的继承, 必须满足 is a 的关系。

两个类之间, A类将属性和特征赠予B类。 此时 A类被称为是父类, B类被称为是 子类, 两者之间的关系是 子类继承自父类

 

带你从零学大数据系列之Java篇---第七章:面向对象三大特性

 

7.2.2. 父类的抽取

在设计类的时候, 可以根据程序中需要使用到的多个具体的类, 进行共性的提取, 定义为父类。

将多个具体的类中相同的属性和行为提取出来到一个类中。

 

带你从零学大数据系列之Java篇---第七章:面向对象三大特性

 

 

7.2.3. 继承的特点

  • 产生继承关系后, 子类可以使用父类中的属性和方法, 也可以定义子类独有的属性和方法
  • Java是单继承! 一个类有且只能有一个父类!

使用Java的好处

  • 使用继承,可以提高代码的复用性, 提高代码的拓展性。

 

7.2.4. 继承的语法

继承, 需要使用关键字 extends。 在定义类的时候, 使用 子类 extends 父类 的方式描述继承。

/**
* @Description 继承的语法
*/
class Dog extends Animal{}

 

7.2.5. 不可以被继承

  • 构造方法
    • 构造方法是为了创建当前类的对象的, 不可以继承给子类。

 

  • 私有成员
    • 私有成员只能在当前的类中使用, 不可以继承给子类。

 

  • 跨包子类
    • 默认权限的属性、方法, 不可以继承给跨包的子类。

 

 

7.2.6. 访问权限修饰符

访问权限修饰符, 就是修饰类、属性的访问级别。

带你从零学大数据系列之Java篇---第七章:面向对象三大特性

7.2.7. 方法重写

子类可以继承到父类中的属性和方法, 但是有些方法, 子类的实现与父类的方法可能实现的不同。

当父类提供的方法已经不能满足子类的需求时, 子类中可以定义与父类相同的方法。

此时, 子类方法完成对父类方法的覆盖, 又叫重写(Override)。

 

/**
* @Description 方法的重写
*/
class Animal{
   protected void bark () {
       System.out.println ("Animal Bark~");
  }
}
class Dog extends Animal{
   @Override
   public void bark () {
       System.out.println ("Dog Bark~");
  }
}

 

7.2.7.1. @Override

一个注解, 进行重写前的校验。 校验这个方法是否是一个重写的方法。 如果不是重写的方法, 会直接报错。

7.2.7.2. 重写的注意事项

  • 方法名字必须和父类方法名字相同
  • 参数列表必须和父类一致
  • 方法的访问权限需要大于等于父类方法的访问权限
  • 方法的返回值类型需要小于等于父类方法的返回值类型

 

7.2.7.3. super关键字

有时候, 子类重写父类方法的时候, 并不是要对父类的实现全盘推翻, 而是对父类方法进行拓展。

父类方法中的实现仍然需要, 但是还需要在父类方法的基础上进行拓展的实现, 此时就需要使用super关键字调用父类的方法。

/**
* @Description super
*/
class Student {
   public void work () {
       System.out.println ("学生在学习");
  }
}
class Monitor extends Student {
   @Override
   public void work () {
       super.work ();// 调用父类的实现
       System.out.println ("班长收作业");
  }
}

 

7.2.8. 继承中的构造方法

子类对象在实例化的时候, 需要先实例化从父类继承到的部分。 此时默认调用父类中的无参构造方法。

/**
* @Description 继承中的构造方法
*/
class Animal {
   public Animal () {
       System.out.println ("父类中的构造方法执行");
  }
}
class Dog extends Animal {
   publicDog () {
       System.out.println ("子类中的构造方法执行");
  }
}

 

因此, 如果父类中没有无参构造方法, 对所有的子类对象实例化都会造成影响, 导致子类对象无法实例化!

解决这个问题, 有两种方案:

  • 给父类添加无参构造方法。
  • 在子类的构造方法中, 使用 super() 调用父类中的有参构造方法。
/**
* @Description super
*/
class Animal {
   String name;
   int age;
   public Animal (String name, int age) {
       this.name = name;
       this.age = age;
  }
}
class Dog extends Animal {
   public Dog (String name, int age) {
       super(name, age);// 调用父类中存在的构造方法,实例化父类部分
  }
}

 

7.3. 多态

7.3.1. 程序中的多态

生活中的多态, 是指的客观的事物在人脑中的主观体现。 例如, 在路上看到一只哈士奇, 你可以看做是哈士奇, 可以看做是狗, 也可以看做是动物。

主观意识上的类别, 与客观存在的事物, 存在 is a 的关系的时候, 即形成了多态。

 

在程序中, 一个类的引用指向另外一个类的对象, 从而产生多种形态。 当二者存在直接或者间接的继承关系时, 父类引用指向子类的对象, 即形成多态。

 

7.3.2. 对象转型

向上转型

对象由子类类型, 转型为父类类型, 即是向上转型。

  • 向上转型是一个隐式转换, 一定会转型成功。
  • 向上转型后的对象, 只能访问父类中定义的成员。
/**
* @Description 向上转型
*/
classTest{
   public static void main (String[] args) {
       // 1. 实例化一个子类对象
       Dog dog = new Dog();
       // 2. 转成父类类型
       Animal animal = dog;
       // 此时, 这个animal引用只能访问父类中的成员
       animal.name="animal";
       animal.age=10;
       animal.furColor="white";// 这里是有问题的, 访问不到
  }
}
class Animal {
   String name;
   int age;
}
class Dog extends Animal {
   String furColor;
}

 

向下转型

对象由父类类型, 转型为子类类型, 即是向下转型。

  • 向下转型是一个显式转换, 有可能转型失败, 需要强制转换。
  • 向下转型后的对象, 将可以访问子类中独有的成员。
/**
* @Description 向下转型
*/
class Test {
   public static void main (String[] args) {
       // 1. 实例化一个子类对象
       Dog dog = new Dog();
       // 2. 转成父类类型
       Animal animal = dog;
       // 3. 转成子类类型
       Dog sub = (Dog)animal;
  }
}
class Animal {
   String name;
   int age;
}
class Dog extends Animal {
   String furColor;
}

 

7.3.3. instanceof关键字

向下转型, 存在失败的可能性。 如果引用实际指向的对象, 不是要转型的类型, 此时强制转换, 会出现 ClassCastException 异常。

所以, 在向下转型之前, 最好使用 instanceof 关键字进行类型检查。

/**
* @Description instanceof关键字
*/
classTest{
   public static void main (String[] args) {
       // 1. 实例化一个子类对象
       Dog dog = new Dog();
       // 2. 转成父类类型
       Animal animal = dog;
       // 3. 转成子类类型
  if(animal instanceof Dog) {
          Dog sub = (Dog)animal;
      }
  }
}
class Animal {
   String name;
   int age;
}
class Dog extends Animal{
   String furColor;
}

 

7.3.4. 多态中的方法重写

当向上转型后的对象, 调用父类中的方法。 如果这个方法已经被子类重写了, 此时调用的就是子类的重写实现!

/**
* @Description 多态中的方法重写
*/
class Test{
   public static void main (String[] args) {
       // 1. 实例化一个子类对象, 并向上转型
       Animal animal = newDog ();
       // 2. 调用父类方法
       animal.bark ();// 因为在子类中已经重写过这个方法了, 此时的输出结果是 Won~
  }
}
class Animal{
   public void bark () {
       System.out.println ("Animal Bark~");
  }
}
class Dog extends Animal{
   @Override
   public void bark () {
       System.out.println ("Won~");
  }
}
相关标签: 个人技术分享