多态性及其应用
多态性
多态—在Java中,子类的对象可以替代父类的对象使用
一个变量只能有一种确定的数据类型
一个引用类型变量可能指向(引用)多种不同类型的对象
Person p = new Student();
Object o = new Person();//Object类型的变量o,指向Person类型的对象
o = new Student(); //Object类型的变量o,指向Student类型的对象
父类类型的变量可以指向子类的对象
一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法
Student m = new Student();
m.school = “pku”; //合法,Student类有school成员变量
Person e = new Student();
e.school = “pku”; //非法,Person类没有school成员变量
属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。
虚拟方法调用(Virtual Method Invocation)
正常的方法调用
Person e = new Person();
e.getInfo();
Student e = new Student();
e.getInfo();
虚拟方法调用(多态情况下)
Person e = new Student();
e.getInfo(); //调用Student类的getInfo()方法
编译时类型和运行时类型
编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。—— 动态绑定
多态性应用举例
方法声明的形参类型为父类类型,可以使用子类的对象作为实参调用该方法
public class Test {
public void method(Person e) {
//……
e.getInfo();
}
public static void main(Stirng args[]) {
Test t = new Test();
Student m = new Student();
t.method(m); //子类的对象m传送给父类类型的参数e
}
}
Person类
1 public class Person { 2 3 //仅在类的内部可以访问. 4 private String email; 5 //在同一个包内该属性可以被访问. 6 String major; 7 //在子类中该属性可以被访问, 且该子类可以跨包 8 protected int salary; 9 10 //访问权限最高, 无论是否在一个包内, 无论是否是子类都可以被访问. 11 public String name; 12 public int age; 13 public Date birth; 14 15 private String lover; 16 17 public Person(int i) { 18 System.out.println("[Person‘s constructor...]"); 19 } 20 21 public Person() { 22 // TODO Auto-generated constructor stub 23 } 24 25 public String getInfo(){ 26 return "name: " + name + ", " + "age: " + age + ", " + "birth: " + birth; 29 } 30 }
Man类继承Person类
1 public class Man extends Person{ 2 3 public void work(){ 4 System.out.println("男人工作..."); 5 } 6 7 @Override 8 public String getInfo() { 9 return "Man‘s getInfo"; 10 } 11 }
Woman类继承Person类
1 public class Woman extends Person{ 2 3 public void shopping(){ 4 System.out.println("女人购物..."); 5 } 6 }
TestPerson类
1 public class TestPerson { 2 public static void main(String[] args) { 3 4 //多态 5 6 //1. 创建一个 Man 的实例 7 Man m1 = new Man(); 8 9 //2. 创建一个 Woman 的实例 10 Woman w1 = new Woman(); 11 12 //3. 创建一个 Person 的实例 13 Person p1 = new Person(); 14 15 /** 16 * 多态: 在Java中,父类的引用可以指向子类的对象. 17 * 1. 在多态情况下, 父类的实例变量不能再访问子类中添加的属性和方法 18 * 2. 方法的调用是在运行时确定的,所以调用的是 Man 类的 getInfo() 方法。—— 动态绑定(虚拟方法法调用) 19 * 3. 在存在父子关系(多态)的情况下, 可以把父类的引用类型强制转换为子类的引用类型. 若实际上不能进行转换则系统 20 * 会抛出 java.lang.ClassCastException 异常. 21 * 4. 如何避免出现 java.lang.ClassCastException 异常呢? 在转换之前可以先判断一下对象实际上是否为指定的子类类型. 22 * 使用 instanceof 运算符. 注意, 使用 instanceof 运算符, 必须要求前面的引用指向的变量和后边的类之间存在父子关系 23 */ 24 //需要一个人, 但来的是一个男人! OK. 因为男人一定是一个人. 25 Person p2 = new Man(); 26 System.out.println(p2.getInfo()); 27 28 //需要一个人, 但来的是一个女人! OK. 因为女人一定是一个人 29 Person p3 = new Woman(); 30 31 //在多态情况下, 可以进行强制的类型转换 32 Man m2 = (Man) p2; 33 34 System.out.println(p3 instanceof Man); 35 System.out.println(p3 instanceof Woman); 36 37 // System.out.println(m2 instanceof Person); 38 39 // Man m3 = (Man) p3; 40 41 //需要一个男人, 但来的是个人! NO. 因为人不一定是男人. 42 //Man m2 = new Person(); 43 44 //需要个男人, 但来的是一个女人。 NO! 45 //Man m3 = new Woamn(); 46 47 Student student = new Student(); 48 student.name = "Jerry"; 49 student.birth = new Date(); 50 student.age = 1; 51 student.school = "atguigu"; 52 53 System.out.println(student.getInfo()); 54 } 55 }
instanceof 操作符
x instanceof A:检验x是否为类A的对象,返回值为boolean型。
要求x所属的类与类A必须是子类和父类的关系,否则编译错误。
如果x属于类A的子类B,x instanceof A值也为true。
public class Person extends Object {…}
public class Student extends Person {…}
public class Graduate extends Person {…}
public void method1(Person e) {
if (e instanceof Person)
// 处理Person类及其子类对象
if (e instanceof Student)
//处理Student类及其子类对象
if (e instanceof Graduate)
//处理Graduate类及其子类对象
}
练习
建立TestInstance 类,在类中定义方法method1(Person e); 在method1中:
(1)根据e的类型调用相应类的getInfo()方法。
(2)根据e的类型执行: 如果e为Person类的对象,输出:“a person”; 如果e为Student类的对象,输出 “a student” “a person ” 如果e为Graduate类的对象,输出: “a graduated student” “a student” “a person”
1 class Person { 2 protected String name="person"; 3 protected int age=50; 4 public String getInfo() { 5 return "Name: "+ name + "\n" +"age: "+ age; 6 } 7 } 8 class Student extends Person { 9 protected String school="pku"; 10 public String getInfo() { 11 return "Name: "+ name + "\nage: "+ age + "\nschool: "+ school; 13 } 15 } 16 class Graduate extends Student { 17 public String major="IT"; 18 public String getInfo(){ 20 return "Name: "+ name + "\nage: "+ age + "\nschool: "+ school+"\nmajor:"+major; 22 } 23 }
对象类型转换 (Casting )
基本数据类型的Casting:
小的数据类型可以自动转换成大的数据类型
如long g=20; double d=12.0f
可以把大的数据类型强制转换(casting)成小的数据类型
如 floate f=(float)12.0 int a=(int)1200L
对Java对象的强制类型转换称为造型
从子类到父类的类型转换可以自动进行
从父类到子类的类型转换必须通过造型(强制类型转换)实现
无继承关系的引用类型间的转换是非法的
在造型前可以使用instanceof操作符测试一个对象的类型
对象类型转换举例
public class Test {
public void method(Person e) { //设Person类中没有getschool()方法
System.out.pritnln(e.getschool()); //非法,编译时错误
if(e instanceof Student) {
Student me = (Student)e; //将e强制转换为Student类型
System.out.pritnln(me.getschool());
}
}
public static void main(Stirng args[]) {
Test t = new Test();
Student m = new Student();
t.method(m);
}
}
Person类
1 public class Person { 2 protected String name="person"; 3 protected int age=50; 4 public String getInfo() { 5 return "Name: "+ name + "\n" +"age: "+ age; 6 } 7 } 8 class Student extends Person { 9 protected String school="pku"; 10 public String getInfo() { 11 return "Name: "+ name + "\nage: "+ age 12 + "\nschool: "+ school; 13 } 14 15 } 16 class Graduate extends Student{ 17 public String major="IT"; 18 public String getInfo() 19 { 20 return "Name: "+ name + "\nage: "+ age 21 + "\nschool: "+ school+"\nmajor:"+major; 22 } 23 }
TestInstance类
1 package com.atgugu.java.ex; 2 3 public class TestInstance { 4 5 /* 6 在类中定义方法method1(Person e); 7 在method1中: 8 (1)根据e的类型调用相应类的getInfo()方法。 9 (2)根据e的类型执行: 10 如果e为Person类的对象,输出:“a person”; 11 如果e为Student类的对象,输出 12 “a student” 13 “a person ” 14 如果e为Graduate类的对象,输出: 15 “a graduated student” 16 “a student” 17 “a person” 18 */ 19 20 public void method1(Person e) { 21 String info = e.getInfo(); 22 System.out.println(info); 23 24 if(e instanceof Graduate){ 25 System.out.println("a graduated student"); 26 } 27 if(e instanceof Student){ 28 System.out.println("a student"); 29 } 30 if(e instanceof Person){ 31 System.out.print("a person"); 32 } 33 34 System.out.println("\n"); 35 36 } 37 38 public static void main(String[] args) { 39 40 TestInstance ti = new TestInstance(); 41 42 Person p1 = new Person(); 43 ti.method1(p1); 44 45 Person p2 = new Student(); 46 ti.method1(p2); 47 48 Person p3 = new Graduate(); 49 ti.method1(p3); 50 } 51 }