带你从零学大数据系列之Java篇---第七章:面向对象三大特性
课程重点:
- 封装的概念
- 单例的实现应用
- 继承的概念
- 继承中的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类被称为是 子类, 两者之间的关系是 子类继承自父类
7.2.2. 父类的抽取
在设计类的时候, 可以根据程序中需要使用到的多个具体的类, 进行共性的提取, 定义为父类。
将多个具体的类中相同的属性和行为提取出来到一个类中。
7.2.3. 继承的特点
- 产生继承关系后, 子类可以使用父类中的属性和方法, 也可以定义子类独有的属性和方法
- Java是单继承! 一个类有且只能有一个父类!
使用Java的好处
- 使用继承,可以提高代码的复用性, 提高代码的拓展性。
7.2.4. 继承的语法
继承, 需要使用关键字 extends。 在定义类的时候, 使用 子类 extends 父类
的方式描述继承。
/**
* @Description 继承的语法
*/
class Dog extends Animal{}
7.2.5. 不可以被继承
- 构造方法
- 构造方法是为了创建当前类的对象的, 不可以继承给子类。
- 私有成员
- 私有成员只能在当前的类中使用, 不可以继承给子类。
- 跨包子类
- 默认权限的属性、方法, 不可以继承给跨包的子类。
7.2.6. 访问权限修饰符
访问权限修饰符, 就是修饰类、属性的访问级别。
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~");
}
}
上一篇: 上海景点排行榜 上海最好玩的旅游景点
下一篇: 虾滑要煮多久?虾滑要煮多久才能吃?