目录
一、是什么
父类的引用指向子类的对象,这就是多态。
我们从对象的内存存储形式来理解什么是多态
1.a这个对象的内存存储形式
A.java
public class A{
public String name;
public int age;
public void run(){
System.out.println("A跑的很快");
}
public void eat(String name){
System.out.println(name+"吃的很多");
}
}
Test.java
public class Test{
public static void main(String[] args){
A a=new A();
}
}
这就是a这个对象的内存存储形式
2.b这个对象的内存存储形式
A.java
public class A{
public String name;
public int age;
public void run(){
System.out.println("A跑的很快");
}
public void eat(String name){
System.out.println(name+"吃的很多");
}
}
B.java
public class B extends A{
public char sex;
public double height;
public void flay(){
System.out.println("B飞得很高");
}
}
Test.java
public class Test{
public static void main(String[] args){
B b=new B();
}
}
这就是b这个对象的内存存储形式
3.子类重写run()方法之后,b这个对象的内存存储形式
A.java
public class A{
public String name;
public int age;
public void run(){
System.out.println("A跑的很快");
}
public void eat(String name){
System.out.println(name+"吃的很多");
}
}
B.java
public class B extends A{
public char sex;
public double height;
public void flay(){
System.out.println("B飞得很高");
}
public void run(){
System.out.println("B跑的很快");
}
}
Test.java
public class Test{
public static void main(String[] args){
B b=new B();
}
}
这就是子类重写run()方法之后,b这个对象的内存存储形式
4.ab这个对象的内存存储形式
A.java
public class A{
public String name;
public int age;
public void run(){
System.out.println("A跑的很快");
}
public void eat(String name){
System.out.println(name+"吃的很多");
}
}
B.java
public class B extends A{
public char sex;
public double height;
public void flay(){
System.out.println("B飞得很高");
}
public void run(){
System.out.println("B跑得很快");
}
}
Test.java
public class Test{
public static void main(String[] args){
A ab=new B();
ab.run();
}
}
输出:
(1)创建子类对象一定会创建父类对象,所以在内存中A和B的对象都有
(2)数据类型决定了数据在内存中的存储形式,所以ab只能调用A中的变量和方法
(3)B中重写run()方法时把A中的覆盖掉了,相当于B中的run()方法在A、B里面共用,所以调用run()方法会输出B跑得很快
(4)这就是多态----------父类的引用指向子类的对象:A ab=new B();(创建方式)
创建的时子类的对象,但是类型是父类的
二、用法
向上转型
(向上转型是java自动完成的)
例题:(其中B是A的子类)
C.java
public class C{
public static void handler(A a){
System.out.println("C输出---");
}
}
test1.java
本来handler()方法里想要的是一个A类型的数据,但是传了一个B类型的数据并没有报错,是因为向上转型---------子类的对象可以被父类的类型所接受--->父类的引用指向子类的对象
三、用法例题
A.java
public class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
B.java
public class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
C.java
public class C extends B{
}
D.java
public class D extends B{
}
Test.java
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}
输出:
原因:
第一个输出:
a1这个对象能调用到的方法有A里面show(D)和show(A); b是B类型的数据,而B是A的子类,所以B类型的数据可以向上转型到A,所以输出 1--A and A
第二个输出:
a1这个对象能调用到的方法有A里面show(D)和show(A); c是C类型的数据,而C是B的子类,且B是A的子类,所以C类型的数据可以向上转型到B,且B类型的数据可以向上转型到A,所以输出 2--A and A
第三个输出:
a1这个对象能调用到的方法有A里面show(D)和show(A); d是D类型的数据,所以输出 3--A and D
第四个输出:
a2这个对象能调用到的方法有A里面show(D)和B里面的show(A); b是B类型的数据,而B是A的子类,所以B类型的数据可以向上转型到A,所以输出 4--B and A
第五个输出:
a2这个对象能调用到的方法有A里面show(D)和B里面的show(A); c是C类型的数据,而C是B的子类,且B是A的子类,所以C类型的数据可以向上转型到B,且B类型的数据可以向上转型到A,所以输出 5--B and A
第六个输出:
a2这个对象能调用到的方法有A里面show(D)和B里面的show(A); d是D类型的数据,所以输出 6--A and D
第七个输出:
b这个对象能调用到的方法有A里面show(D)和B里面的show(Object)、show(A); b是B类型的数据,而B是A的子类,所以B类型的数据可以向上转型到A,所以输出 7--B and A
第八个输出:
b这个对象能调用到的方法有A里面show(D)和B里面的show(Object)、show(A); c是C类型的数据,而C是B的子类,且B是A的子类,所以C类型的数据可以向上转型到B,且B类型的数据可以向上转型到A,所以输出 8--B and A
第九个输出:
b这个对象能调用到的方法有A里面show(D)和B里面的show(Object)、show(A); d是D类型的数据,所以输出 9--A and D