typora-copy-images-to: images
什么是多态?
举例:
一般对象这样创建:
猫 x = new 猫();建立了猫的对象,并通过本类引用x指向了这个猫对象;
多态中的对象:
动物 x1 = new 猫();父类引用x1指向了子类这个猫对象;
x1这个引用即具备猫的形态,又具备着动物的形态。
简单的说:就是一个对象对应着不同类型,在代码中如何体现呢?父类或者接口的引用指向其子类的对象。
多态存在的三个前提:
- 要有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
多态举例
父类Animal
class Animal {
int num = 10;
static int age = 20;
public void eat() {
System.out.println("动物吃饭");
}
public static void sleep(){
System.out.println("动物睡觉");
}
public void run(){
System.out.println("动物在奔跑");
}
}
子类Cat
class Cat extends Animal{
int num = 66;
static int age = 40;
String name = "tomCat";
public void eat() {
System.out.println("猫吃饭");
}
public static void sleep(){
System.out.println("猫睡觉");
}
public void catMouse(){
System.out.println("猫在抓老鼠");
}
}
测试类
/**
* @ClassName: DuotaiDemo
* @author: benjamin
* @version: 1.0
* @description: 多态举例
*/
public class DuotaiDemo {
public static void main(String[] args) {
// 父类引用指向了子类对象
Animal am = new Cat();
am.eat();
am.sleep();
am.run();
System.out.println(am.num);
System.out.println(am.age);
}
}
结果
猫吃饭
动物睡觉
动物在奔跑
10
20
发现问题
子类重写了非静态成员方法eat(): 猫吃饭
子类重写了静态成员方法sleep(): 动物睡觉
子类未重写父类成员方法run():动物在奔跑
总结:
成员变量:编译看左边(父类),运行看左边(父类)
成员方法:编译看左边(父类),运行看右边(子类)
静态方法:不涉及对象的多态性。因为静态函数随着类的加载而加载。直接用类名调用即可。
特点举例
成员变量
简单地说:编译和运行都参考等号的左边
编译时:参考引用型变量所属的类中是否有调用的成员变量,有,编译通过,没有,编译失败;
运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类中的成员变量。
举例:
执行DuotaiFu f = new DuotaiZi(); 此时子类型提升为父类型,用父类型找父
public class DuotaiDemo2 {
public static void main(String[] args) {
DuotaiFu f = new DuotaiZi();
System.out.println(f.num);//3
}
}
class DuotaiFu{
int num = 3;
}
class DuotaiZi extends DuotaiFu{
int num = 4;
}
内存图解
成员函数(重点)
非静态函数
简单说:编译时看左边,运行时看右边
编译时:参考引用变量所属的类中是否有调用的函数,有,编译通过,没有,编译失败;
运行时:参考的是对象所属的类中是否有调用的函数。
举例:
show函数运行时,持有this引用,指向了0x0034的对象(new Zi() ),找到该对象的show方法运行;
public class DuotaiDemo2 {
public static void main(String[] args) {
DuotaiFu f = new DuotaiZi();
f.show();
}
}
class DuotaiFu{
void show(){
System.out.println("fu show...");
}
}
class DuotaiZi extends DuotaiFu{
void show(){
System.out.println("zi show...");
}
}
// zi show...
内存图解:
静态函数
不涉及对象的多态性。因为静态函数随着类的加载而加载。直接用类名调用即可。
编译时:参考引用型变量所属的类中是否有调用的静态方法;
运行时:参考引用型变量所属的类中是否有调用的静态方法;
举例:
非静态方法必须绑定到指定的对象上,才能运行;
package java_demo_2;
public class DuotaiDemo2 {
public static void main(String[] args) {
DuotaiFu f = new DuotaiZi();
f.method();
DuotaiFu.method();
DuotaiZi.method();
}
}
class DuotaiFu{
void show(){
System.out.println("fu show...");
}
static void method(){
System.out.println("父类静态方法");
}
}
class DuotaiZi extends DuotaiFu{
void show(){
System.out.println("zi show...");
}
static void method(){
System.out.println("子类静态方法");
}
}
结果:
父类静态方法
父类静态方法
子类静态方法
向上转型和向下转型
向上转型:
- 概念:
Animal a = new Cat();
猫提升成动物类型,但是猫特有的功能无法访问。 - 目的:限制对特有功能的访问,专业讲就是向上转型。
向下转型:
-
概念:如果还想用具体动物猫的特有功能,可以将对象进行向下转型。如:
Cat c = (Cat) am;
c.catchMouse();
-
目的:为了使用子类中的特有方法。
举例:
// 向上转型
Animal am = new Cat();
am.eat();
// 向下转型
Cat cat = (Cat) am;
cat.catMouse();
System.out.println(cat.name);
输出
猫在抓老鼠
tomCat
类型转换异常:
对于转型,自始至终都是在类对象在做着类型的变化。猫-动物-猫
Cat c2 = (Cat) d; c2.catchMouse();//ClassCastException // 不能把一个猫——动物——狗;报错
类型判断:
instanceof
:运行时指出对象是否是特定类的一个实例,只能用于引用数据类型判断,通常在向下转型前用于健壮性的判断。
举例:
public class DuotaiDemo {
public static void main(String[] args) {
//向上转型
Animal c = new Cat();
Animal d = new Dog();
method(c);
method(d);
public static void method(Animal a){
a.eat();
if(a instanceof Cat){
Cat c = (Cat) a;//向下转型,执行对象的特有方法;
c.catchMouse();
}
else if(a instanceof Dog){
Dog d = (Dog) a;
d.lookHome();
}
}
}
参考链接
JAVA的多态用几句话能直观的解释一下吗? - 程序狗的回答 - 知乎
https://www.zhihu.com/question/30082151/answer/120520568