Java基础(八)——面向对象基础(四)

一、抽象类

猫狗举例子,猫狗都是动物类,猫狗可以有具体的行为,但动物不行,因为动物是一个大类,不够具体。比如猫吃猫粮,狗就吃狗粮,但这两个吃的东西不一样,Animal类就不能定义具体吃什么;但是可以定义一个吃的方法,不写方法体,但不写方法体会报错;且Animal类不够具体,理应不能实例化,所以,这里引入一个抽象类的概念。

1、abstract——抽象

public abstract  class Animal{		// 抽象类
}

被 abstract 修饰的类称为抽象类。

抽象类中的方法有方法体会报错,因此,抽象类中的方法没有方法体:

判断 java 对象的属性有值 java对象类型判断_接口

判断 java 对象的属性有值 java对象类型判断_判断 java 对象的属性有值_02

接着子类继承抽象的父类:

判断 java 对象的属性有值 java对象类型判断_接口_03

会报错,因为继承抽象父类的子类,必须要重写抽象父类的抽象方法,不然就会报错,这是一种约束行为,你继承了我这个类,就必须重写抽象方法,这时的抽象父类有一种模板的意味:

判断 java 对象的属性有值 java对象类型判断_判断 java 对象的属性有值_04


抽象类可以有构造方法:

判断 java 对象的属性有值 java对象类型判断_接口_05


但是不能实例化:

判断 java 对象的属性有值 java对象类型判断_面向对象_06

抽象类可以有属性,访问修饰符也有,跟普通类一样,看需求:

判断 java 对象的属性有值 java对象类型判断_多态_07

2、抽象类举例子

假设定义一个门的抽象类,定义开门这个方法,各种门开的方式不同。再定义木门和感应门,都继承门这个抽象类,所以必须重写开门这个方法。木门就是普通的开门即可,感应门人靠近就自动开门。这就是一个简单的抽象类例子。

3、总结

  1. abstract——修饰的类为抽象类,修饰的方法为抽象方法,抽象的方法没有方法体,这只能存在于抽象类中。
  2. 普通子类继承抽象类,必须重写抽象方法(约束效果)。
  3. 抽象类可以有普通方法。
  4. 抽象类有构造方法,但是不能实例化对象。

二、接口

1、接口介绍

继续引用上面的例子。除了普通开门的方式,还能有密码开门的方式。但是密码开门的方式不适合写在模板里,因为木门和感应门没有这种开门方式,是密码门才有的方式。所以单独给密码门即可,但是想要约束效果的话,就要给到抽象类里面,但是另外两个门没有这种方式,不适合。所以这里引入一个接口的概念:额外的提升类的功能,意思是功能的扩展。

2、interface——接口

interface 修饰的类为接口,是特殊的抽象类:

判断 java 对象的属性有值 java对象类型判断_多态_08


这里为这个类额外提供一个密码开门的功能。可以发现前面的 public 和 abstract 是灰色的,其实是这里不写也行,因为接口类中,默认方法时公开抽象的。接口方法只需要写返回值和参数列表就够了。

3、implements——接入接口

普通类怎么接入接口呢?通过关键字 implements 接入:

判断 java 对象的属性有值 java对象类型判断_判断 java 对象的属性有值_09


接入之后可以发现报错,这是因为跟抽象类一样,也要重写抽象方法:

判断 java 对象的属性有值 java对象类型判断_接口_10

可以看到,普通子类既可以继承抽象类,也可以实现接口类:

判断 java 对象的属性有值 java对象类型判断_多态_11

4、接口的特点

1、接口中同样不允许有方法体,更不允许有普通方法。

2、默认为公开的静态常量:

判断 java 对象的属性有值 java对象类型判断_面向对象_12

其他修饰符会报错:

判断 java 对象的属性有值 java对象类型判断_java_13

3、接口没有构造方法,因为方法默认都是抽象的,抽象方法没有方法体。更不能实例化。

4、类可以实现多个接口。就是一个类可以接入多个接口,实现多种功能。

5、接口可以多继承接口(多继承概念),可以实现三合一功能,比如一个接口继承三个接口类,那么这个接口就有三个功能,再来个普通子类接入这一个接口,那么这个子类也能有三个功能:

判断 java 对象的属性有值 java对象类型判断_接口_14


可以看到这个接口什么都不用写都行。

多继承这个概念只存在接口与接口!

6、JDK8以后接口允许存在 static 或者 default 修饰的方法(新特性):

判断 java 对象的属性有值 java对象类型判断_面向对象_15

5、总结

再稍微总结一下:

  1. 通过 implements 实现接口,类只能实现接口,不能继承接口。
  2. 接口中同样不允许有方法体,更不允许有普通方法。
  3. 接口没有构造方法,因为方法默认都是抽象的,抽象方法没有方法体。更不能实例化。
  4. 类可以实现多个接口(多实现概念)。就是一个类可以接入多个接口,实现多种功能。
  5. 接口可以多继承接口(多继承概念),比如三合一功能。
  6. JDK8以后接口允许存在 static 或者 default 修饰的方法(新特性

三、多态

1、多态的概念引入

继续拿猫狗举例子。创建猫狗类,以及一个医生类。:

判断 java 对象的属性有值 java对象类型判断_判断 java 对象的属性有值_16

猫类一样,但输出的不是狗,是猫,然后是医生类,并创建一个打针的方法:

判断 java 对象的属性有值 java对象类型判断_面向对象_17


看上述代码,打针方法接收的是猫类以及猫对象,如果传的是狗,则不能接收,不能给狗打针。不同类型不能随意接收。接着实例化:

判断 java 对象的属性有值 java对象类型判断_多态_18


运行结果:

判断 java 对象的属性有值 java对象类型判断_接口_19

接着看运行流程:

判断 java 对象的属性有值 java对象类型判断_判断 java 对象的属性有值_20


这时如果把医生打针这个当做一个技能,来尝试能否给狗打针:

判断 java 对象的属性有值 java对象类型判断_java_21

很明显报错了,因为接收的是Cat类型,但是这里传的是Dog类型。当然我们可以给医生类再增加一个接收Dog类型的方法,但这样一来,如果有上百种不同的动物,就要有上百种方法。

所以这里开始引入多态的概念。Java中可以引入它自己,以及本身的父类。意思就是,猫是猫,是动物的子类;狗也是动物的子类。是什么动物不要紧,只要它是动物这个类的子类就行。医生给动物打针,给什么动物不重要,重要的是,它是动物就行,或者说是动物这个类的子类就行,这样,就只需要一个方法就能给不同动物打针。

2、多态

接着,医生打针这个方法,接收动物类就行:

判断 java 对象的属性有值 java对象类型判断_多态_22


然后无论是接收猫类或者狗类,都不报错了:

判断 java 对象的属性有值 java对象类型判断_多态_23


然后运行效果,跟之前的一模一样,还能给不同动物打针:

判断 java 对象的属性有值 java对象类型判断_接口_24

3、父类对象指向(引用)子类对象 (接口同理)

为什么传入Cat或者Dog都可以呢?

判断 java 对象的属性有值 java对象类型判断_判断 java 对象的属性有值_25

// 父类对象引用子类对象。这里的 = 是引用的意思。
Animal animal = new Cat();
Animal animal = new Dog();

接口同理,接口也能实现一样的效果,接口对象引用实现类对象。

4、约束对象只能调用父类继承或重写的方法

现在取消抽象:

判断 java 对象的属性有值 java对象类型判断_多态_26

判断 java 对象的属性有值 java对象类型判断_面向对象_27

这时候使用多态方式创建对象:

判断 java 对象的属性有值 java对象类型判断_面向对象_28


问:调用的是什么方法?打印的是谁的名字?

答案:

判断 java 对象的属性有值 java对象类型判断_判断 java 对象的属性有值_29

使用多态创建对象,调用方法为子类对象的方法,但是调用的属性是父类的属性。

这时候猫类创建自己独有的方法:

判断 java 对象的属性有值 java对象类型判断_接口_30


这时会发现父类不能调用子类独有的方法:

判断 java 对象的属性有值 java对象类型判断_java_31

这里是因为:约束了对象只能调用从父类继承或者重写的方法。

5、强制转换

在数据类型中,强制转换,存在大转小和小转大:

判断 java 对象的属性有值 java对象类型判断_java_32


在这里的对象(引用数据类型)中,也存在大转小和小转大:

判断 java 对象的属性有值 java对象类型判断_面向对象_33


判断 java 对象的属性有值 java对象类型判断_多态_34

看上方代码,当animal是猫时,猫变猫没有问题,但如果是狗时,猫变成狗就要出大问题,但是这里的IDEA并不会给你标红,但是编译运行的时候就会报错,显示类型转换异常。

6、instanceof——判断对象是否为某类型

那么这里可以写一个方法,通过这个方法来判断是否在可转范围,如果不在此范围内就不允许强转。但是需要判断原本是什么类型,这里引入一个关键词 instanseof ,左边写对象,右边写类型,意为判断左边是否是右边这种类型,如果是的话返回 true 。

(对象 instanceof 类型)

判断 java 对象的属性有值 java对象类型判断_面向对象_35


这样一来,转换类型就不会出错了,是猫就转猫,是狗就转狗。

四、题外话——面向对象设计原则

简写:开口合里最单依

开:开闭原则
口:接口原则
合:聚合原则
里:替换原则
最:最少原则
单:单一原则
依:依赖原则

开闭原则:
(1)open :对外部代码持放开状态。(上面举的猫狗医生例子中,只要是Animal的子类统统都能接收,不像原本只能接收一种,持开放状态)
(2)close:对内部代码持关闭状态(上面举的猫狗医生例子中,内部只需要一个方法即可,不再需要添加其他方法。内部就可关闭了)