Java面向对象三大特性:多态

1. 多态思想

1.1. 接口(了解)

接口是一种约定规范,是多个抽象方法的集合。仅仅只是定义了应该有哪些功能,本身不实现功能,至于每个功能具体怎么实现,就交给实现类完成。

接口中的方法是抽象方法,并不提供功能实现,体现了规范和实现相分离的思想,也体现了组件之间低耦合的思想。

所谓耦合度,表示组件之间的依赖关系。依赖关系越多,耦合性越强,同时表明组件的独立性越差,在开发中往往提倡降低耦合性,可提高其组件独立性,举一个低耦合的例子。

电脑的显卡分为集成显卡和独立显卡:

  • 集成显卡:显卡和主板焊死在一起,显卡坏了,只能换主板

  • 独立显卡:显卡和主板相分离,显卡插到主板上即可,显卡坏了,只换显卡,不用换主板

接口也体现的是这种低耦合思想,接口仅仅提供方法的定义,却不提供方法的代码实现。那么得专门提供类并去实现接口,再覆盖接口中的方法,最后实现方法的功能,在多态案例中再说明。

1.1.1. 接口定义和多继承性(重点掌握)

接口可以认为是一种特殊的类,但是定义类的时候使用class关键字,定义接口使用interface关键字。

public  interface  接口名{

    抽象方法1();

    抽象方法2();

    抽象方法2();

}

接口表示具有某些功能的事物,接口名使用名词,有人也习惯以I打头如IWalkable.java。

接口定义代码:

public interface IWalkable {

    void walk();

}

接口中的方法都是公共的抽象方法,等价于:

public interface IWalkable {

    public abstract void walk();

}

类可以继承类,但是只能单继承的,接口也可以继承接口,但是却可以继承多个接口,也就是说一个接口可以同时继承多个接口,如两栖动物可以行走也可以拥有。

可行走规范:

public interface IWalkable {

    void walk();

}

可游泳规范:

public interface ISwimable {

    void swim();

}

两栖动物规范,即可以游泳,又可以行走。

public interface IAmphibiable  extends IWalkable,ISwimable{

}

此时子接口能继承所有父接口的方法。

1.1.2. 接口实现类(重点掌握)

和抽象类一样,接口是不能创建对象的,此时必须定义一个类去实现接口,并覆盖接口中的方法,这个类称之为实现类,类和接口之间的关系称之为实现关系(implements)。

public class 类名 implements 接口名{

    覆盖接口中抽象方法

}

在类实现接口后,覆盖接口中的抽象方法,完成功能代码,此时接口和实现类之间的关系:

  • 接口:定义多个抽象方法,仅仅定义有哪些功能,却不提供实现。

  • 实现类:实现接口,覆盖接口中抽象方法,完成功能具体的实现。

如果实现类没有全部实现接口中的方法,要么报错,要么把实现类设置为抽象类(下图)。

image.png

需求:定一个猫类(Cat)实现IWalkable接口,并创建对象调用方法。

public class Cat implements IWalkable{

    public void walk() {

        System.out.println("走猫步...");

    }

}

根据方法覆盖原则:子类方法的访问修饰符必须大于等于父类方法的访问修饰符,接口中的方法都是public修饰的,所以实现类中的方法只能使用public修饰。

如果是创建实现类对象,此时要面向接口编程,语法如下:

接口 变量 = new 实现类();

测试类:

public class CatDemo {

    public static void main(String[] args) {

        IWalkable cat = new Cat();

        cat.walk();

    }

}

实现类可以继承父类,也可以同时实现多个接口,定义一个青蛙类(Frog)继承于动物类(Animal),同时实现于会走路(IWalkable),会游泳(ISwimable)的接口,语法如下(记住定义语法即可):

public class Frog extends Animal implements ISwimable,IWalkable{

    public void walk() {

        System.out.println("跳啊跳...");

    }

    public void swim() {

        System.out.println("游啊游..");

    }

}  

1.2. 多态(掌握)

多态时面向对象三大特征:封装、继承、多态。

在继承关系,是一种”is A”的关系,也就说子类是父类的一种特殊情况,有如下代码:

public class Animal{}

public class Dog extends Animal{}

public class Cat extends Animal{}

那么我们可以认为狗和猫都是一种特殊的动物,那么可以使用动物类型类来表示狗或猫。

Dog d = new Dog();    //创建一只狗对象,赋给子类类型变量

Animal  a    =  new Cat();      //创建一只猫对象,赋给父类类型变量

此时对象(a)具有两种类型:

  • 编译类型:声明对象变量的类型——>Animal

  • 运行类型:对象的真实类型 ——>Dog

当编译类型和运行类型不一致的时候,此时多态就产生了:

注意:编译类型必须是运行类型的父类或接口。

所谓多态,表示一个对象具有多种形态。

Animal  a = null;

a   =  new    Dog();  //  a此时表示Dog类型的形态

a   =  new    Cat();  //  a此时表示Cat类型的形态

多态的前提,可以是继承关系(类和类),也可以是实现关系(接口和实现类),在开发中,一般都指接口和实现类之间的关系,什么是多态?

一言以蔽之:父类引用变量指向于子类对象,调用方法时实际调用的是子类的方法。

我家有一种动物,你猜它的叫声是怎么样的,猜不到,因为这个动物有多种形态。

  • 如果该动物是狗,叫声是:旺旺旺...

  • 如果该动物是猫,叫声是:妙妙妙...

多态操作有两种定义格式和操作语法

  • 操作继承关系(开发中不是很多):
父类 变量名 = new 子类();

变量名.方法();
  • 操作实现关系(开发中最频繁):
接口 变量名 = new 实现类();

变量名.方法();

1.2.1. 操作继承关系(掌握)

接口 变量名 = new 实现类();

变量名.方法();

Animal类:

public class Animal {

    public void shout() {

        System.out.println("Animal...shout...");

    }

}

Cat类:

public class Cat extends Animal{

    public void shout() {

        System.out.println("妙妙妙...");

    }

}

Dog类:

public class Dog extends Animal{

    public void shout() {

        System.out.println("旺旺旺...");

    }

}

测试类:

public class AnimalDemo {

    public static void main(String[] args) {

        // 创建Cat对象

        Animal a = new Cat();

        a.shout();

        // 创建Dog对象

        a = new Dog();

        a.shout();

    }

}

运行结果:

妙妙妙...

旺旺旺...

验证结论:父类引用变量指向于子类对象,调用方法时实际调用的是子类的方法。

1.2.2. 操作实现关系(重点掌握)

接口 变量名 = new 实现类();

变量名.方法();

ISwimable 接口:

public interface ISwimable {

    void swim();

}

Fish类:

public class Fish implements ISwimable{

    public void swim() {

        System.out.println("游啊游...");

    }

}

测试类:

public class FishDemo {

    public static void main(String[] args) {

        // 创建Fish对象

        ISwimable fish = new Fish();

        fish.swim();

    }

}

运行结果:

游啊游...

1.2.3. 多态时方法调用问题(重点掌握)

把子类对象赋给父类变量,此时调用方法:

Animal a = new Cat();

a.shout();

那么a对象调用的shout方法,是来自于Animal中还是Cat中?判断规则如下:

一张图,看懂到底调用的是哪一个类中的方法!

image.png

文字解释,先判断shout方法是否在父类Animal类中:

  • 找不到:编译报错

  • 找 到:再看shout方法是否在子类Cat类中:

  • 找不到:运行父类方法

  • 找 到:运行子类方法(这个才是真正的多态方法调用)

1.2.4. 类型转换和instanceof运算符(了解)

自动类型转换:把子类对象赋给父类变量(多态)

Animal a = new Dog();

Object  obj = new Dog();  //Object是所有类的根类:

强制类型转换:把父类类型对象赋给子类类型变量(前提:该对象的真实类型应该是子类类型)

Animal a = new Dog();

Dog  d = (Dog) a;  //正确

Cat c = (Cat) a;  //错误

instanceof 运算符:判断该对象是否是某一个类的实例,在开发中运用不是很多

语法格式:boolean b = 对象A instanceof 类B; //判断 A对象是否是 B类的实例?如果是,返回true

代码如下:

Animal a = new Dog();

System.out.println(a instanceof Animal);  //true

System.out.println(a instanceof Dog);  //true

System.out.println(a instanceof Cat);  //false

1.2.5. 多态的好处-USB案例(掌握)

需求:模拟在主板上安装鼠标、键盘等,比较没有规范和有规范的区别。

没有统一规范

鼠标类:

public class Mouse {

    //鼠标工作的方法

    public void **work1**() {

        System.out.println("鼠标在移动");

    }

}

键盘类:

public class Keyboard {

    //键盘工作的方法

    public void work2() {

        System.out.println("鼠标在移动");

    }

}

主板类:

public class MotherBoard {

    //在主板上安装鼠标对象

    public void plugin(**Mouse** m) {

        m.work1();  //调用鼠标工作的方法

    }

    //在主板上安装键盘对象

    public void plugin(**Keyboard** k) {

        k.work2();  //调用键盘工作的方法

    }

}

上述代码是没有统一规范的,我们能发现其中的问题:

  • 不同设备中工作的方法名称是不一致的

  • 每次需要安装中设备,都需要在主板类上新增一个方法 (这个问题严重)

没有统一规范

USB规范接口:

//定义一种规范,用来约束所有的USB设备应该具有的功能

public interface IUSB {

    //USB设备工作的方法

    void swapData();

}

在Mouse和Keyboard类遵循于USB规范——工作的方法名称也就相同了。

public class Mouse implements IUSB{

    public void swapData() {

        System.out.println("鼠标在移动");

    }

}

public class Keyboard **implements IUSB**{

    public void **swapData**() {

        System.out.println("鼠标在移动");

    }

}

主板类,在安装方法plugin上也体现出了多态的特征:

public class MotherBoard {

    //IUSB类型可以接受实现类对象

    public void plugin(IUSB usb) {

        usb.swapData();

    }

}

面向接口编程,体现的就是多态,其好处:把实现类对象赋给接口类型变量,屏蔽了不同实现类之间的实现差异,从而可以做到通用编程。

测试类,无论是否使用多态,测试代码相同:

public class USBDemo {

    public static void main(String[] args) {

        // 创建主板对象

        MotherBoard board = new MotherBoard();

        // 创建鼠标对象

        Mouse m = new Mouse();

        // 创建键盘对象

        Keyboard k = new Keyboard();

        //在主板上安装鼠标

        board.plugin(m);

        //在主板上安装键盘

        board.plugin(m);

    }

}

请问:使用USB接口后,哪里出现多态了?

若要获得最好的学习效果,需要配合对应教学视频一起学习。需要完整教学视频,请参看https://ke.qq.com/course/272077。

你可能感兴趣的:(Java面向对象三大特性:多态)