面向对象第三篇
一、多态
1、多态的概念:
多态是同一行为具有多个不同表现形式或形态的能力,多态就是同一个接口,使用不同的实力而执行不同的操作。
多态、封装、继承是面向对象的三大特性。 如:在生活中跑的动作,小猫、小狗、和大象跑起来不一样。
2、多态的具体实现形式:
父类类型 变量名 = new 子类对象;
举例:
//Test.java文件夹
package Animal_Cat_Dog;
public class Test {
public static void main(String[] args) {
Animal A=new Animal();
A.Eat();//调用父类的Eat方法
System.out.println("-----创建一个Animal类的对象-----");
Animal B=new Cat();
B.Eat();//Cat类创建了自己的Eat方法,所以这里会调用自己的Eat方法
System.out.println("-----创建一个Cat类的对象-----");
Animal C=new Dog();
C.Eat();//Dog类没有创建自己的Eat方法,所以调用的是父类Animal的Eat方法
System.out.println("-----创建一个Dog类的对象-----");
}
}
//Animal.java文件夹
package Animal_Cat_Dog;
public class Animal {
public void Eat(){
System.out.println("动物吃东西。");
}
}
//Cat.java文件夹
package Animal_Cat_Dog;
public class Cat extends Animal {
public void Eat(){
System.out.println("猫吃鱼");
}
}
//Dog.java文件夹
package Animal_Cat_Dog;
public class Dog extends Animal {
}
当使用多态方法调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的重写方法。
使用多态的好处:是程序有良好的扩展,并可以对所有类的对象进行通用处理。实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性与便利。
3、引用类型转换
父类对象和子类对象之间的转换分为了向上转型和向下转型。
(1)向上转型
通过子类(小范围)实例化父类对象(大范围),这种属于自动转换。
意义:当我们需要多个同父的对象调用某个相同的方法时,通过向上转换后,可以确定参数的统一,方便程序设计。
缺点:对象的向上转型是安全的,但是会失去子类新增的属性(变量)或者方法。就是说子类对象被看作为父类的类型,只能访问父类的属性和方法,以及子类的重写。
在Cat子类中创建了一个age属性,在调用过程中使用会报错。这就是向上转型失去了子类新增的属性或者方法的具体体现。
(2)向下转型
通过父类(大范围)示例化子类对象(小范围),这种属于强制转换。
为什么需要向下转型:
当使用多态方式调用时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说不能调用父类没有而子类拥有的方法。为了在多态方式中调用子类特有的方法,需要乡下转型。
instanceof关键字
通过父类强制转换为子类,从而调用子类特有的方法。通过instanceof可以判断某对象是否是某类的实例(该类或该类的父类),如果是则返回true,否则返回false。
if(A instanceof Cat)//如果A是Cat类型,就返回true
{
Cat CatA=(Cat)A;//将A类强转为Cat类
//CatA 可以执行猫类特有的方法
}
//在实际编程中的用法
if(A instanceof Cat){
Cat CatA=(Cat)A;//将A类强转为Cat类
//CatA 可以执行猫类特有的方法
}else if(A instanceof Dog){
Dog DogA=(Dog)A;//将A类强转为Dog类
//DogA 可以执行狗类特有的方法
}
总结
1、看一个对象能够访问哪些属性,看等于号=左边定义的是什么类型
父类类型:只能访问父类的属性。
子类类型:可以访问父类的属性,子类新增,子类重写属性。
2、看一个对象最终能访问那个方法,看=右边是什么类型的对象
父类类型:只能访问父类的方法。
子类类型:父类的方法,及子类新增、重写的方法。
二、Object类
1、Object类概述
所有的类,都是以继承结构存在的。如果没有显示的父类,默认继承Object类。class Person{}
相当于class Person extends Object{}
- Object类是超类、基类,所有类的直接或间接父类,位于继承树的最顶层。
- 任何类,如果没有书写extends显示继承某个类,都默认直接继承Object类,否则为间接继承。
- Object类所定义的方法,是所有对象都具备的方法。
- Object类型可以存储任何对象。
- 作为参数,可以接受任何对象。
- 作为返回值,可以返回任何对象。
2、常用方法
a、getClass();
返回引用中存储的实际对象类型。
通常用于判断两个引用中实际存储对象类型是否一致。
A.getClass()//调用示例
b、hashCode();
返回该对象的十进制的哈希值(十进制地址值)。
可以判断两个对象是不是相同的地址。
A.hashCode();//调用示例
c、toString();
返回该对象的字符串表示。
可以根据程序需求覆盖该方法,如展示对象的各个属性值。IDEA工具提供自动生成。
A.toString();//调用示例
d、equals()
比较两个对象地址是否相同。
可以进行覆盖比较两个对象内容是否相同。
A.equals(B);调用示例
equals 重写步骤
- 比较两个引用是否指向同一个对象。
- 判断object是否为null
- 判断两个引用指向的实际对象类型是否一致
- 强制类型转换
- 依次比较各个属性是否相同
重写equals()示例
@Override
public boolean equals(Object obj) {
if (this==obj){
return true;
}
if(obj==null||this.getClass()!=obj.getClass()){
return false;
}
Animal animal=(Animal)obj;//将Object向下转型为Animal
if(this.name.equals(animal.name)){
return true;
}else {
return false;
}
}
e、finalize()方法:前期简要了解,在学JVM会详细讲解
- 当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列。
- 垃圾对象:没有有效引用指向此对象时,为垃圾对象。
- 垃圾回收:由GC销毁垃圾对象,释放数据存储空间。
- 自动回收机制:JVM内存耗尽,一次性回收所有垃圾对象。
- 手动回收机制:使用System.gc();通知JVM执行垃圾回收。
三、抽象类
将子类的共同特征进行抽取,抽象成一个父类。如果有的功能在父类中定义了,但是没有具体的实现,那么可以定义为抽象的。等待子类实现即可。
作用:
- 可以被子类继承,提供共性属性和方法。
- 可声明为引用,更自然的使用多态。
抽象类:包含抽象方法的类
- 被abstract修饰的类,称为抽象类;
- 抽象类意为不够完整的类、不够具体的类;
public abstract class 类名{
}
抽象方法:没有方法体的方法。抽象的方法一定要定义在抽象类里面。
public abstract 返回值类型 方法名(参数);
代码示例:
@Override
class Cat extends Animal{//抽象类的子类一定要实现抽象方法
System.out.println("猫吃鱼。");
}
abstract class Dog extends Animal{//不实现抽象方法只能将子类也定义为抽象类
}
public abstract class Animal{抽象方法一定要定义在抽象类中
public abstract void eat();//抽象方法
}
注意事项:
- 抽象类不可以直接创建对象,原因:调用抽象方法没有意义。
- 只有覆盖了抽象类中所有的抽象方法后,其子类才可以创建对象。否则该子类还是一个抽象类,需要再被子类继承直到实现所有抽象方法。
- abstract关键字不能和static,private,final等关键字搭配使用。
四、接口
引用数据类型:数组,类,接口
接口是Java语言中一种引用类型,是方法的集合。接口的定义与类的定义方式相似,关键字不同。接口使用interface关键字,但它也会被编译成.class文件。
- 接口中偶尔也定义静态常量。
public static final double PI=3.14;
接口是一种约定、契约,一种规范。
Ⅰ、 接口定义
1、含有抽象方法
抽象方法:使用abstract关键字修饰,可以省略,没有方法体。该方法供子类实现使用。
代码如下:
public interface InterFaceName{
public abstract void method();
}
2、含默认方法和静态方法
默认方法:使用default修饰,不可省略,供子类调用或者子类重写。
静态方法:使用static修饰,供接口直接调用。
代码如下:
Usb.java文件
//创建一个鼠标接口
class Mouse implements Usb{
@Override
public void start() {
System.out.println("鼠标开始工作。");
}
@Override
public void stop() {
System.out.println("鼠标停止工作。");
}
@Override
public void fun1() {
System.out.println("鼠标的默认方法。");
}
}
class Keyboard implements Usb{
@Override
public void start() {
System.out.println("键盘开始工作。");
}
@Override
public void stop() {
System.out.println("键盘停止工作。");
}
}
public interface Usb {
//接口中含有两个抽象方法
public abstract void start();
public abstract void stop();
//默认方法
public default void fun1(){
System.out.println("默认方法。");
}
//静态方法
public static void fun2(){
System.out.println("静态方法。");
}
}
Test.java文件
public class Test {
public static void main(String[] args) {
//错误写法:Usb USB=new Usb();接口不能示例化
Usb mouse=new Mouse();
mouse.start();
mouse.stop();
mouse.fun1();//调用默认方法,用示例对象调用
Usb.fun2();//静态方法用接口名去调用
}
}
3、含默认方法和私有方法
私有方法:使用private修饰,供接口中的默认方法或者静态方法调用。
public interface Usb(){//在默认方法和静态方法中调用
private void method(){
//执行语句
}
}
总结:
- 子类和父类的关系:extends
- 实现类和接口的关系:implements
- 非抽象子类实现接口:必须重写接口中所有抽象方法、继承接口的默认方法,可以重写
- 接口中的静态方法只能使用接口名调用。
Ⅱ、 接口的应用
1、一个类可以实现多个接口
接口中的功能都没有方法体,由子类来明确。
代码示例:
interface Fun1{
void fun1();
}
interface Fun2{
void fun2();
}
public class Zi implements Fun1,Fun2 {//一个类可以实现多个接口
@Override
public void fun1() {
}
@Override
public void fun2() {
}
}
2、一个类继承的同时可以实现接口
当一个类已经继承了一个父类,它又需要拓展额外的功能,这时接口就派上用场了
代码示例:
class Fu{//一个父类
}
public class Zi extends Fu implements Fun1,Fun2 {//一个类可以实现多个接口
@Override
public void fun1() {
}
@Override
public void fun2() {
}
}
3、接口的多继承
两个类之间通过继承产生关系,接口和类之间通过实现产生关系,两个接口的关系?
多个接口之间可以使用extends进行继承。
interface Fun1{//接口一
void fun1();
}
interface Fun2{//接口二
void fun2();
}
interface Children extends Fun1,Fun2{//接口的继承
@Override
void fun1();
@Override
void fun2();
public void children_play();
}
4、接口和抽象类的区别
相同点:
- 二者都存在抽象方法。
- 不能创建对象,不能实例化。
- 可以作为引用类型。
- 具备Object类中所定义的方法。
不同点:
- 接口所有属性都是公开静态常量,个别变量使用public static final修饰
- 接口所有方法都是公开抽象方法,个别方法使用public abstract修饰
- 接口没有构造方法、动态代码块、静态代码块
5、接口的好处
- 接口的出现降低了耦合性
- 设计与实现完全分离,更容易更换具体实现
- 更容易搭建程序框架