/*
- java面向对象三大特性之多态性
- 1,多态性可以理解为一个事物的多种形态
- 2,对象的多态性:父类的引用指向子类的对象或者说子类的对象赋给父类的引用。
- 3,多态的使用:虚拟方法调用
- 子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父
- 类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法
- 确定的。所以多态性是运行时行为,而非编译时行为。
- 对象有了多态性以后,在编译期,只能调用父类中声明的方法,在运行时,实际执行的是
- 子类重写父类的方法,编译看左侧,运行看右侧。
- 4,多态性使用的前提,1,类有继承关2,子类中有重写的方法,否则没有必要使用多态性。
- 5,多态性适用于方法,不适用于属性。属性的编译和运行都看左侧。
- 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中。
- 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量
- 6,方法重载与重写:
- 重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不
- 同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了
- 不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类
- 和子类的,即子类可以重载父类的同名不同参数的方法。
- 所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,
- 这称为“早绑定”或“静态绑定”; 而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体
- 方法,这称为“晚绑定”或“动态绑定”。
- 7,多态总结:
- 多态的作用:提高代码通用性,常称作接口重用
- 多态的前提:需要存在继承或者实现关系,子类中有方法的重写
- 多态的效果:编译时:要查看引用变量所声明的类(父类)中是否有所调用的方法。运行时:调用实际new的对象所属的类(子类)中的重写方法。
- 类中的属性:成员变量不具备多态性,只看引用变量所声明的类的属性。
- 8有了对象的多态性以后,内存中依然加载了子类的属性和方法,由于对象声明为父类类型,导致编译时只能调用父类的属性和方法
- ,子类特有的属性和方法无法调用。
- 如果想要调用子类的属性和方法,需要使用向下转型的方式将对象转换为子类对象
- 类似基本数据类型的强制转换会出现精度损失的问题,向下转型有可能失败(classcastexception)的问题,必须有继承关系才能向下转型。
- 需要先用 instanceof关键字判断对象是否是类的实例,如实是返回true否则返回false。
- 注意:多态(向上转型)与强制类型转换(向下转型)不限于直接父类和直接子类,父类对象可以被孙类赋值,使用孙类重写方法。
- 也可以强制转换为孙类对象,调用孙类特有的属性和方法。
- 9,类B为类A的父类, 如果对象a instanceof 类A为true,那么a instanceof B也为true。
- 如果类C为类A的子类,那么对于A类的实例化对象a有a instanceof C为false。
**
个人理解
instanceof关键字判断的是,被判断的类A的结构是否存在于在对象a的内存结构中,如果有则返回true,否则返回false。
类C为类A的子类,包含超出类A的方法和属性,在对象a的内存结构中不存在,a instanceof C就会返回false,
类D与类A类B类C不存在继承关系,其中的结构在对象a的内存中也不存在,a instanceof D也会返回false。
也只有在返回true 的情况下,a才能调用类A的所有结构,强制转换才能成功。
类B为类A的父类, 当向上类型转换(多态性) B b = new A();时,b的内存空间中拥有父类B与子类A的所有结构,所以 b instanceof A 返回true,表示b可以向下转型为A的对象。
在 A a = (A)b;向下转型时,a可以调用类A的结构**
*/
package object_chapter2;
import java.util.Random;
public class Object_Polymorphism {
public static void main(String[] args) {
Person p = new Person();
p.eat();
System.out.println(p.number);
p = new Man();//多态的形式,父类的引用指向子类的对象
p.eat();//多态的使用,执行的是子类重写的方法,称作虚拟方法调用
//p.work();//子类特有的方法无法调用
System.out.println(p instanceof Man);//使用instanceof判断p的结构是否存在于Man类中
Man m = (Man)p;//使用向下转型的方式调用子类的方法
// Women w = (Women)p;//可以编译过,但运行出错,p的结构中有Man类的结构,但Man类的部分结构与Women不同,无法强转到Women。
// w.investigate();
System.out.println(p instanceof Women);
m.work();
p = new Women();
p.eat();
System.out.println(p.number);//输出的依然是父类属性的值
//p.investigate();
Object_Polymorphism o = new Object_Polymorphism();
o.function(new Person());//正常调用
o.function(new Man());//参数使用子类对象赋值,执行子类重写方法
o.function(new Women());
int value = new Random().nextInt(2);//输出随机数,0或1
System.out.println(value);
Person p1 = o.getInstance(value);
p1.eat();//输出结果根据随机数确定,说明多态性是运行时行为
Base base = new Sub();//多态性,子类对象赋值
base.add(1, 2, 3);//调用的是子类中的重写的方法,没有重写则调用父类中的方法
Sub s = (Sub)base;//强制类型转换为sub类型的对象
s.add(1,2,3);//先调用确定形参的方法,没有再调用可变形参的方法,都没有再调用父类方法
}
public Person getInstance(int value) {
switch (value) {
case 0:
return new Man();
default:
return new Women();
}
}
public void function(Person p) {//方法中参数声明的是父类person的对象
p.eat();//方法体中执行父类的方法
if(p instanceof Man) {
Man m = (Man)p;
m.game();
}else if(p instanceof Women) {
Women w = (Women)p;
w.shopping();
}
}
// public void function(Man m) {//使用多态性可以省略这些重载的方法
// m.eat();
// }
// public void function(Women w) {
// w.eat();
// }
public void method(Object obj) {//因为Object类是所有类的父类,此处可以用任意类的对象赋值
}
}
class Person{
String name;
int age;
int number = 2;
void move() {
System.out.println("运动是放电");
}
void eat() {
System.out.println("进食是充电");
}
void talk(){
System.out.println("通话基本靠吼");
}
void walk() {
System.out.println("交通基本靠走");
}
}
class Man extends Person{
int number = 1;
void eat() {
System.out.println("吃得多,干的多");
}
void work() {
System.out.println("努力工作赚钱");
}
}
class Women extends Person{
int number = 0;
void eat() {
System.out.println("吃的少,身材好");
}
void investigate() {
System.out.println("收集信息,坐镇指挥");
}
}
class Base {
public void add(int a, int... arr) {
System.out.println("base");
}
}
class Sub extends Base {
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");
}
}