学习内容:
掌握对象多态性的作用。
了解instanceof关键字。
掌握常见的设计模式。
目录
1、对象的多态性
2、instanceof关键字
3、抽象类与接口的应用
(1)为抽象类与接口实例化
(2)抽象类的实际应用——模板设计
(3)接口的实际应用——制定标准
(4)设计模式 ——工厂设计
(5)设计模式 ——代理设计
(6)设计模式 ---- 适配器设计
(7)抽象类与接口之间的关系
1、对象的多态性
多态性在面向对象中是一个最重要的概念,在Java中面向对象主要有以下两种主要体现:
(1)方法的重载与覆写。
(2)对象的多态性。
对象的多态性主要分为以下两种类型:
(1)向上转型:子类对象—>父类对象。
(2)向下转型:父类对象一>子类对象。
对于向上转型,程序会自动完成,而对于向下转型时,必须明确地指明要转型的子类类型。
🍆对象转型的格式:
对象向上转型:父类 父类对象=子类实例; 对象向下转型:子类 子类对象=(子类)父类实例;
🍆范例:
class A{ // 定义类A public void fun1(){ // 定义fun1()方法 System.out.println("A --> public void fun1(){}") ; } public void fun2(){ this.fun1() ; // 调用fun1()方法 } } class B extends A{ public void fun1(){ // 此方法被子类覆写了 System.out.println("B --> public void fun1(){}") ; } public void fun3(){ System.out.println("B --> public void fun3(){}") ; } } public class PolDemo02{ public static void main(String asrgs[]){ A a = new B() ; // 向上转型关系 B b = (B)a ; // 发生了向下转型关系 b.fun1() ; b.fun2() ; b.fun3() ; } }
🍆运行结果:
B --> public void fun1( ) { } B --> public void fun1( ) { } B --> public void fun3( ) { }
说明:如果要想调用子类自己的方法,则一定只能用子类声明对象,另外,在子类中调用了父类中的fun2()方法,fun2()方法要调用fun1()方法,但此时fun1()方法己经被子类所覆写,所以,此时调用的方法是被子类覆写过的方法。在进行对象的向下转型前,必须首先发生对象向上转型,否则将出现对象转换异常
2、instanceof关键字
在Java中可以使用instanceof关键字判断一个对象到底是哪个类的实例。
🍆格式如下:
对象 instanceof 类 —>返回boolean类型 lean result = obj instanceof Class
🍆用法:
声明一个 class 类的对象,判断 obj 是否为 class 类的实例对象
声明一个 class 接口实现类的对象 obj,判断 obj 是否为 class 接口实现类的实例对象
obj 是 class 类的直接或间接子类
3、抽象类与接口的应用
(1)为抽象类与接口实例化
在Java中可以通过对象的多态性为抽象类和接口实例化,这样在使用抽象类和接口时即可调用子类中所覆写过的方法
🍆范例1:通过子类为抽象类实例化
abstract class A{ // 定义抽象类A public abstract void print() ; // 定义抽象方法print() } class B extends A { // 定义子类,继承抽象类 public void print(){ // 覆写抽象方法 System.out.println("Hello World!!!") ; } } public class Demo1{ public static void main(String[] args){ A a = new B() ; // 通过子类为抽象类实例化 a.print() ; } }
🍆范例2:通过子类为接口实例化
interface A{ // 定义接口A void print() ; // 定义抽象方法print() } class B implements A { // 定义子类,实现接口 public void print(){ // 覆写抽象方法 System.out.println("Hello World!!!") ; } } public class Demo2{ public static void main(String[] args){ A a = new B() ; // 通过子类为接口实例化 a.print() ; } }
🍆运行结果:
Hello World!!!
(2)抽象类的实际应用——模板设计
现有以下一种场景:假如人分为学生和工人,两者都可以发言,发言的内容由学生和工人自己决定,从程序上来讲,学生和工人可以看作继承了“人类”的子类,此时就可以使用抽象类来实现这种场景。
🍆范例:
abstract class Person { //定义抽象类Person private String name; private int age; public Person(String name,int age) { this.name = name; this.age = age; } public String getName() { return this.name; } public int getAge() { return this.age; } public void say() { //发言功能 System.out.println(this.getContent()); //发言内容由子类决定 } public abstract String getContent(); //定义抽象方法,由子类覆写,决定发言内容 } class Student extends Person { //定义Student类继承Person类 private String school; public String getSchool(){ return this.school; } public Student(String name,int age,String school) { super(name,age); this.school = school; } public String getContent() { //覆写Person类方法,决定发言内容 return "学生的发言内容 --> 姓名:" + super.getName() + ", 年龄:" + super.getAge() + ", 学校:" + this.getSchool(); } } class Worker extends Person { //定义Worker类继承Person类 private float salary; public float getSalary(){ return this.salary; } public Worker(String name,int age,float salary) { super(name,age); this.salary = salary; } public String getContent() { //覆写Person类方法,决定发言内容 return "工人的发言内容 --> 姓名:" + super.getName() + ", 年龄:" + super.getAge() + ", 薪水:" + this.getSalary(); } } public class Demo { public static void main(String[] args) { Person per1 = new Student("李华",20,"xx学校"); //由子类实例父类对象,即可调用子类所覆写过的方法 Person per2 = new Worker("张三",30,3000.0f); //由子类实例父类对象,即可调用子类所覆写过的方法 per1.say(); //学生发言的内容 per2.say(); //工人发言的内容 } }
🍆运行结果:
学生的发言内容 --> 姓名:李华,年龄:20,学校:xx学校 工人的发言内容 --> 姓名:张三,年龄:30,薪水:3000.0
在Person类中就相当于定义了一个模板,在主方法中调用时,调用的就是普通方法,而子类只需要实现父类中的抽象方法,就可以取得一个具体的信息。每个子类实现模板中的抽象方法就能够产生不同的模板内容 。
(3)接口的实际应用——制定标准
现实生活中,U盘和打印机等设备均可以通过USB接口在计算机上使用,因为他们都符合 USB接口 标准。以下实例通过接口模拟制定USB接口标准,实现此场景。
🍆范例:制定USB接口
interface USB { //定义USB接口 void start(); void stop(); } class Computer { //计算机 public static void plugin(USB usb) { //只要是符合USB接口的设备都可以接入 usb.start(); //让USB设备开始工作 System.out.println("-----------USB设备工作中----------"); usb.stop(); //让USB设备停止工作 } } class UDisk implements USB { //U盘 public void start() { //覆写start()方法 System.out.println("U盘已接入"); } public void stop() { //覆写stop()方法 System.out.println("安全移除设备"); } } class Print implements USB { //打印机 public void start() { //覆写start()方法 System.out.println("打印机已接入"); } public void stop() { //覆写stop()方法 System.out.println("打印机停止工作"); } } public class Demo { public static void main(String[] args) { Computer.plugin(new UDisk()); //接入U盘 System.out.println(); //换行 Computer.plugin(new Print()); //接入打印机 } }
🍆运行结果:
U盘已接入 -----------USB设备工作中---------- 安全移除设备 打印机已接入 -----------USB设备工作中---------- 打印机停止工作 接口就是一个标准,计算机认的只是接口,而对于具体的设备,计算机本身并不关心.
(4)设计模式 ——工厂设计
工厂设计是Java开发中使用得最多的一种设计模式,那么什么叫工厂设计?
🍆范例:
interface Fruit{ void eat(); } class Apple implements Fruit{ public void eat(){ System.out.println("吃苹果"); } } class Orange implements Fruit{ public void eat(){ System.out.println("吃橘子"); } } public class InterfaceCaseDemo02 { public static void main(String[] args) { Fruit f1 = new Apple(); f1.eat(); Fruit f2 = new Orange(); f2.eat(); } }
🍆运行结果:
吃苹果 吃橘子
在主方法中,子类为接口实例化后,调用被子类覆写过的方法,从程序中可以发现,每更换一个子类,都需要进行实例化,那么此时就可以在接口和子类之间加入一个过渡端,通过此过渡端进行实例化过程,返回接口实例
interface Fruit{ void eat(); } class Apple implements Fruit{ public void eat(){ System.out.println("==吃苹果=="); } } class Orange implements Fruit{ public void eat(){ System.out.println("==吃橘子=="); } } class Factory { //定义工厂类 public static Fruit getInstance(String className) { Fruit f = null; if("apple".equals(className)){ //判断是哪个子类 f = new Apple(); //进行实例化 } if("orange".equals(className)){ f = new Orange(); } return f; //返回接口实例 } } public class Demo1 { public static void main(String[] args) { Fruit f1 = null; f1 = Factory.getInstance("apple"); //通过工厂取得实例 f1.eat(); //调用方法 } }
🍆运行结果:
吃苹果
(5)设计模式 ——代理设计
代理设计是指由一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其它相关业务的处理,就好像生活中,用户通过网络代理服务器进行上网,由代理服务器完成用户权限和访问限制等相关的控制操作,而真实主题的服务器负责用户上网操作过程
🍆范例:
interface Network{ //定义上网接口 void browse(); //上网操作抽象方法 } class Real implements Network{ //真实的上网操作 public void browse(){ System.out.println("上网浏览信息"); } } class Proxy implements Network{ //代理上网 private Network network; public Proxy(Network network){ this.network = network; } public void check(){ //上网相关的控制操作 System.out.println("检查用户是否合法"); } public void browse(){ this.check(); //执行代理上网的相关控制操作 this.network.browse(); //调用真实的上网操作 } } public class Demo { public static void main(String[] args) { Network net = new Proxy(new Real()); //实例化代理,传入真实的上网操作 net.browse(); } }
🍆运行结果:
检查用户是否合法 上网浏览信息
(6)设计模式 ---- 适配器设计
在Java程序中,如果一个类要实现一个接口,则必须要覆写此接口中的全部抽象方法,那么如果此时一个接口中定义的抽象方法过多,但是子类又用不到这么多的抽象方法,那么就比较麻烦。所以此时可以定义一个抽象类作为过渡,即一个接口首先被一个抽象类先实现(此抽象类通常称为适配器类),并在此抽象类中实现若干方法(方法体为空),则以后的子类直接继承此抽象类,就可以有选择地覆写所需要的方法 。
🍆范例:
interface Window{ // 定义Window接口,表示窗口操作 public void open() ; // 打开 public void close() ; // 关闭 public void activated() ; // 窗口活动 public void iconified() ; // 窗口最小化 public void deiconified();// 窗口恢复大小 } abstract class WindowAdapter implements Window{ public void open(){} ; // 打开 public void close(){} ; // 关闭 public void activated(){} ; // 窗口活动 public void iconified(){} ; // 窗口最小化 public void deiconified(){};// 窗口恢复大小 }; class WindowImpl extends WindowAdapter{ public void open(){ System.out.println("窗口打开。") ; } public void close(){ System.out.println("窗口关闭。") ; } }; public class Demo{ public static void main(String args[]){ Window win = new WindowImpl() ; win.open() ; win.close() ; } }
🍆运行结果:
窗口打开。 窗口关闭。
以上代码中因为采用了适配器这个中间环节,所以子类就不用必须实现接凵中的全部方法,而是有选择地实现所需要的方法。
(7)抽象类与接口之间的关系
抽象类与接口在系统设计上都是用得最多的
🍆两者的主要区别: