**注意事项:
**多态特性,只体现在成员方法上。
**对于成员变量,不具备多态性。只看引用变量所属的类。
多态的前提:
需要存在继承或者实现关系
要有覆盖操作
1.多态:
子类对象的多种父类形态
父类类型的引用变量指向多种不同的子类对象
本态:子类对象的本类形态
** 多态引用:子类对象赋值于父类类型的引用变量
本态引用:子类对象赋值于子类类型的引用变量
2.虚方法调用:
**虚拟方法调用(Virtual Method Invocation) : 多态引用调用覆盖方法
1)编译期检查父类类型
2)运行期执行子类类型
举例:
父类对象Person 有say()方法 (比如Person say()方法打印这是一个人)
子类对象继承,并重写了say()方法。 (比如Chinese say()方法打印这是一个中国人)
这时 Person p = new Chinese ();
p.say(); //在运行时看new的对象实体, 动态绑定
调用 p.say() 方法,就属于虚方法调用,只需要看new的是什么对象,是子类对象就打印子类方法。
父类的say方法也得有,不然编译会报错(也就是编译期检查父类类型)
运行时,还是看new的是子类对象,就打印子类say方法 (也就是运行期执行子类类型)
**此时父类里面的say() 方法 ,就是虚拟方法,唯一的作用就是让编译通过。
多态副作用:多态引用时, 子类特有的成员不能访问, 多态副作用. 只能访问父类与子类共有的方法。
举例:子类有test()方法,父类没有。这时如果用 p.test() 来调用,就会直接编译报错。因为父类没有这个方法。
多态的应用一:
多态数组,可以保存任意本类及子类对象
举例:比如要创建一个对象数组,能放下chinese,american两个类型。那就可以创建一个Person父类,让chinese,american作为子类继承。再创建 Person[] 数组,那么两种类型的子类对象都能加入了。
多态应用二:在方法传参时,使用父类引用。在调用该方法时可以传递子类对象,实现传参的多态。
子类继承父类:
--若子类重写了父类方法,则意味着子类中定义的方法,彻底覆盖了父类中的同名方法,系统将不可能把父类中的方法,转移到子类中。
--对于实例变量,则不存在这样的现象。即使子类中定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量。
属性无多态性,方法才具备多态性,例子:
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 TestFieldMethod {
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
}
}
关于多态参数的方法,在调用后需要使用子类特殊方法时的处理方式 - 造型处理: instanceof
package com.atguigu.javase.inheritence;
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 TestFieldMethod {
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
}
}
关于多态参数的方法,在调用后需要使用子类特殊方法时的处理方式 - 造型处理: instanceof
public static void test(Person p) { // 多态参数方法
p.sayHello();
//p.spring();
//if (是中国人) {
// 造型有风险, 需要先判断..
// 对于对象类型的判断顺序应该先从子到父
if (p instanceof Chinese) { // 判断p引用指向的对象实体是否是右侧Chinese类型的一个实例
Chinese c = (Chinese)p; // 造型
c.spring(); //想使用子类特有方法
} else if (p instanceof American) {
((American)p).thanksGiving(); // .号优先级最高, 所以需要()
} else {
System.out.println("普通人一个");
}
}
public static void main(String[] args) {
Chinese ch = new Chinese("李四", 40, "女", "牛");
American am = new American("Jack", 35, "male", true);
Person p = new Person("某人", 30, "未知");
test(ch);
test(am);
test(p);
}