多态性
概念
- 对象的多态性:父类的引用指向子类的对象
- 理解多态性:一个事物的多种形态
- 多态的使用,虚拟方法的调用
- 子类中定义了与父类同名同参数的方法,在多态的情况下,此时父类的方法为虚拟方法,父类根据赋给他的不同子类对象,动态调用属于子类的该方法。这样的方法在编译器是无法确定的。
- 有了对象多态性以后,在编译期,只能调用父类中声明的方法;在运行期,我们实际执行的是子类重写父类的方法
- 总结:编译看右边,执行看左边。
- 多态性的使用前提:
- 类的继承
- 子类重写父类的方法。
- 对象的多态性,只适用于方法,不适用于属性。
- 多态性是运行时行为,不是编译时行为。
举例1
准备
创建一个Person类,声明公开的name
、id
和age
属性,提供eat()
和walk()
方法。
创建Man类继承Person类,提供isSmoking
、id
属性和重写父类方法,独有sleep()
方法
创建Woman类继承Person类,提供属性packageNum
属性和重写父类方法,独有goShopping()
方法
public class Person {
String name;
int age;
int id = 1001;//身份证号
public void eat() {
System.out.println("人吃饭");
}
public void walk() {
System.out.println("人说话");
}
}
public class Man extends Person {
boolean isSmoking;
int id = 1002;//工号
@Override
public void eat() {
System.out.println("男人赚钱养家,多吃饭");
}
@Override
public void walk() {
System.out.println("男人声音粗犷");
}
public void sleep() {
System.out.println("男人少睡觉,多干活");
}
}
public class Woman extends Person {
int packageNum;
@Override
public void eat() {
System.out.println("女人减肥:少吃饭");
}
@Override
public void walk() {
System.out.println("女人细声细语");
}
public void goShopping() {
System.out.println("女人逛街购物");
}
}
练习1
创建多态,格式:父类 名称 = new 子类()
// 多态
Person p1 = new Man();
p1.age = 24;
p1.name = "王哈哈";
p1.eat();
p1.walk();
- 我们可以看到,多态就是父类的引用指向子类的对象。
- 我们发现,创建的对象是Person,结果Person对象调用的
eat()
和walk()
方法输出的是子类重写的方法。 - 内存结构:
练习2
通过多态,调用子类的特有方法和属性。
p1.isSmoking = false;
p1.sleep();
- 我们发现提示如下错误:isSmoking cannot be resolved or is not a field。
- 说明多态对象,只能调用父类已有的方法和属性,不能调用子类特有的方法和属性。
- 通过练习1和练习2,发现有了对象多态性以后,在编译期,只能调用父类中声明的方法;在运行期,我们实际执行的是子类重写父类的方法。
- 总结:编译看右边,执行看左边。
练习3
在子类(Man)和父类(Person)都有一个id
的属性,通过父类引用子类对象,查看调用的是哪一个id
。
System.out.println(p1.id);
- 我们发现通过
p1.id
调用的是Person
类中的id
属性 - 说明对象的多态性,只适用于方法,不适用于属性。
举例2
//考查多态的笔试题目:
public class InterviewTest1 {
public static void main(String[] args) {
Base1 base = new Sub1();
base.add(1, 2, 3);
Sub1 s = (Sub1)base;
s.add(1,2,3);
}
}
class Base1 {
public void add(int a, int... arr) {
System.out.println("base1");
}
}
class Sub1 extends Base1 {
public void add(int a, int[] arr) {
System.out.println("sub_1");
}
public void add(int a, int b, int c) {
System.out.println("sub_2");
}
}
/*
*sub_1
*sub_2
*/
关键字 instanceof
引出
在使用多态的时候,想调用子类的独有属性和方法,那该如何实现呢?(通过上面的案例继续编写)
答:强制类型转换
//使用强制类型转换,可以调用子类对象的内容
Man m1 = (Man) p1;
m1.isSmoking = false;
m1.sleep();
但是随之而来的问题就出来了,如果不小心强制转换错误,会导致异常。
// 强制类型转换可能存在异常
Woman w1 = (Woman) p1;
w1.packageNum = 10;
类型转换异常。因为p1
引用的子类对象是Man
类型的,所以强制转换成Woman
会引发异常。
解决办法就是通过instanceof
。
概念
- 格式:
a instanceof A
,判断a是不是A的对象(包括子类对象);是返回true,不是返回false。
举例1
通过上面的案例继续编写
// 优雅的判断强转
if (p1 instanceof Woman) {
System.out.println("*****Woman*****");
Woman w2 = (Woman) p1;
w2.packageNum = 10;
}
if (p1 instanceof Man) {
System.out.println("*****Man*****");
Man m2 = (Man) p1;
m2.isSmoking = false;
m2.sleep();
}
举例2
判断类型为直接父类或间接父类
if (p1 instanceof Person) {
System.out.println("*****Person*****");
}
if (p1 instanceof Object) {
System.out.println("*****Object*****");
}
面试题
class Base {
int count = 10;
public void display() {
System.out.println(this.count);
}
}
class Sub extends Base {
int count = 20;
public void display() {
System.out.println(this.count);
}
}
public class FieldMethodTest {
public static void main(String[] args) {
Sub s = new Sub();
System.out.println(s.count);//20
s.display();//20
Base b = s;//多态性
//==:对于引用数据类型来讲,比较的是两个引用数据类型变量的地址值是否相同
System.out.println(b == s);//true
System.out.println(b.count);//10
b.display();//20
}
}
Day12问题
- 什么是多态性?什么是虚拟方法调用?
- 多态性:父类的引用指向子类的对象
- 举例:Person p = new Man()
- 虚拟方法调用:子类中定义了与父类相同方法名、相同参数的方法。在多态的情况下,此时父类的方法为虚拟方法,父类根据赋予他的不同子类对象,动态调用属于子类的该方法。
- 多态性:父类的引用指向子类的对象
- 一个类可以有几个父类?一个父类可以有几个子类?子类能获取直接父类中的结构吗?子类能否获取父类中private权限的属性和方法?
- 一个类只能有一个父类
- 一个父类可以有N个子类
- 可以直接获取父类中的结构
- 能够获取到,只不过收封装性的影响,无法直接调用。
- 方法的重写具体规则有哪些?
- 同名、同参数列表
- 权限修饰符
- 返回值类型:
- void:父类为void,子类为void
- 引用数据类型:父类为A类型,子类为A类型或者A类型的子类。
- 基本数据类型:父类为int类型,子类为int类型。
- 异常
- super调用构造器,有哪些具体的注意点
- 必须在首行
- 在下面代码结构中:使用关键字:this,super方法的重写;继承。
本文由 Gorrywang 创作,严禁转载与复制!
最后编辑时间为: Aug 13,2016