一、多态
理解:多态本意是指同一事物在不同的条件会有不同的形态;
映射到Java中可以理解为:同一个父类方法被不同的子类调用,会产生不同的行为(重写父类的方法);
也可表述为:不同子类的对象对父类同一消息能做出不同的响应(重写父类的方法)。 即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用)。
1、面向对象的多态的实现前提:
(1)要有继承:类与类之间必须有继承关系;
(2)要有重写:子类重写父类的成员方法(可以不重写,但这就失去了多态的意义);
(3)向上转型:父类引用可以指向任何一个子类的对象。
2、向上转型(子类自动转为父类):子类"伪装"成父类,执行子类的方法;
class Fu {
.....
}
class Zi extends Fu {
.....
}
Fu fu = new Zi();
父类 父类引用 = 子类对象
注:
1、Java指向的两个时期:编译器与执行器,编译期看类型,执行期看对象。
2、多态调用函数的处理过程: 编译器从父类查找是否有该函数,没有的话报错,有的话在执行期执行子类中重写的同名函数,而不是父类。
例程:duotai包:ZMS.java ZMSSON.java
3、向下转型(父类强制转化为子类):"伪装"成父类的"子类"还原成真正的子类
Zi zi = (Zi) fu; //类似于强制转换大范围到小范围
例程:duotai包:ZMS.java ZMSSON.java
ZMS.java
1 package duoTai; 2 3 public class ZMS { 4 String name; 5 int age; 6 7 public void teach() { 8 9 System.out.println("我是父类ZMS教Java"); 10 } 11 12 public void show() { 13 System.out.println(name+age); 14 15 } 16 17 }
ZMSSON.java
1 package duoTai; 2 /** 3 * 创建ZMS子类 4 * 多态的测试 5 * 6 * */ 7 public class ZMSSON extends ZMS { 8 9 //重写父类中同名方法 10 public void teach() { 11 12 System.out.println("我是ZMS子类教文学"); 13 // like(); 14 } 15 16 //子类自己的成员方法 17 public void like() { 18 System.out.println("ZMSSON喜欢踢球"); 19 20 } 21 22 public static void main(String[] args) { 23 24 /* 25 * 多态的表示:父类 父类引用名 = 子类对象 26 * 多态调用函数的处理过程: 编译器从父类查找是否有该函数,没有的话报错, 27 * 有的话在执行期执行子类中重写的同名函数,而不是父类。 28 * 29 * */ 30 ZMS zmsText = new ZMSSON(); 31 zmsText.teach(); 32 33 //调用不了父类没有的方法 34 //zmsText.like(); 35 36 //调用父类的成员变量方法 37 zmsText.name = "zms"; 38 zmsText.age = 65; 39 zmsText.show(); 40 41 // 42 ZMSSON zmsSon = (ZMSSON) zmsText; 43 zmsSon.teach(); 44 zmsSon.like(); 45 46 } 47 48 }
4、多态的好处:
(1)提高了代码的复用性(继承)
(2)提高了代码的扩展性(多态)
5、instanceof 关键字:
boolean b = a instanceof b;
判断a类是否属于另一个b类,是返回true,否则返回false。
练习:跟据从键盘输入数字不同选择不同的子类对象,执行不同的响应(重点理解);
例程:duotai包:Animal.java duoTaiAnimal.java
创建父类:
1 package duoTai; 2 3 public class Animal { 4 public String name ; 5 public int age; 6 7 public void eat() { 8 System.out.println(name+"动物吃东西"); 9 } 10 11 }
创建两个子类:
1 package duoTai; 2 3 public class Cat extends Animal{ 4 5 //重写父类方法 6 public void eat() { 7 System.out.println("猫吃鱼"); 8 9 } 10 11 //写子类自己的方法 12 public void catchMouse() { 13 System.out.println("抓老鼠"); 14 } 15 16 } 17 18 19 // 在另一个java文件中创建 20 package duoTai; 21 22 public class Dog extends Animal{ 23 24 //重写父类方法 25 public void eat() { 26 System.out.println("吃狗粮"); 27 } 28 29 //写子类自己的方法 30 public void kanMen() { 31 System.out.println("狗看门"); 32 } 33 }
创建测试功能类:
1 package duoTai; 2 3 /** 4 * @author Kanekiyi 5 * 理解多态的意义:同一消息(函数)可以根据发出的对象不同而产生不同的行为方式。 6 * Or 不同的对象调用同一个函数能够产生不同的行为方式。 7 */ 8 import java.util.Scanner; 9 10 public class duoTaiAnimal { 11 12 @SuppressWarnings("resource") 13 public static void main(String[] args) { 14 15 System.out.println("请输入数字1选择猫,数字2选择狗"); 16 Scanner sc = new Scanner(System.in); 17 18 int num = sc.nextInt(); 19 Animal animal = new Animal(); 20 /* 21 * 向上转型时,根据指令选择不同的对象源 22 */ 23 if (num == 1) { 24 animal = new Cat(); 25 } else if (num == 2) { 26 animal = new Dog(); 27 } else { 28 System.out.println("输入数字错误请重新输入数字1或者2"); 29 } 30 31 runAnimal ( animal); 32 33 } 34 35 public static void runAnimal(Animal a) { 36 37 //根据对象的不同执行子类重写的eat()方法; 38 a.eat(); 39 40 /* 41 * 向下转型时,注意转型目标子类类型是否符合 42 * 目的:执行子类中特有的功能 43 * 44 */ 45 46 if (a instanceof Cat) { 47 Cat cat = (Cat) a; 48 cat.catchMouse(); 49 50 } else if (a instanceof Dog) { 51 Dog dog = (Dog) a; 52 dog.kanMen(); 53 54 } else { 55 System.out.println("输入错误,不属于cat类也不属于Dog类"); 56 } 57 58 } 59 60 }
二、final 关键字
2.1 final修饰类
final修饰的类不能被继承;
2.2 final修饰变量
final 变量能被显式地初始化并且只能初始化一次。被声明为 final 的对象的引用不能指向不同的对象,但是 final 对象里的数据可以被改变。也就是说 final 对象的引用不能改变,但是里面的值可以改变。(存疑)。
final与static一起修饰成员变量构成常量,声明的时候常量名全部大写,可以直接通过类名访问。
例程:
1 package Fianal; 2 3 4 //public class Final1 extends Final0{ final修饰的类不能够被继承 5 public class Final1 { 6 7 int IDCard ; 8 //final修饰的成员变量声明时初始化且有且只初始化一次。 9 final int IDCardNum =314; 10 final int IDCardNum1; 11 12 static final String IDCARD= "36452345245X"; 13 14 //通过构造函数给final修饰的成员变量初始化 15 public Final1() { 16 super(); 17 IDCardNum1 =314; 18 19 } 20 21 public final void textMath() { 22 23 System.out.println("我是Final1类的final方法"); 24 } 25 26 27 }
2.3 final 修饰方法
final 修饰成员方法,可以被子类继承,但是不能被重写;
注:
1、final 修饰的成员变量初始化的两种方式:
(1) 声明时就初始化;
(2)通过构造函数初始化。
且只初始化一次,初始化后就不能修改。
2、final 修饰的变量为常量时,在加载时系统会将变量替换为其所表示的常量。
例程:
1 package Fianal; 2 3 public class Final2 extends Final1 { 4 5 //父类final修饰的成员方法不能重写,只能调用 6 //public final void textMath() {} 7 8 public static void main(String[] args) { 9 Final2 textFinal = new Final2(); 10 textFinal.IDCard = 2; 11 12 //final修饰的变量在声明时就初始化且只能初始化一次,只能被调用不能被修改 13 //textFinal.IDCardNum = 3; 14 System.out.println("普通成员变量IDCard:"+textFinal.IDCard); 15 System.out.println("final修饰的成员变量IDCardNum:"+textFinal.IDCardNum); 16 //System.out.println("final和static修饰的成员变量IDCARD:"+textFinal.IDCARD); 17 //常量可以直接调用或类名调用 18 System.out.println("final和static修饰的成员变量IDCARD:"+Final1.IDCARD); 19 System.out.println("final和static修饰的成员变量IDCARD:"+IDCARD); 20 21 textFinal.textMath(); 22 23 } 24 25 }