Java引用变量有两个类型分别是
编译时类型:声明的类型
运行时类型:实际赋值的类型
如果这两个类型不一样就会出现多态
举例现有类A
class A{
public int field = 5;
public void fun(){
System.out.println("A类的方法1");
}
public void funA(){
System.out.println("A类的方法A");
}
}
B类继承A类
class B extends A{
public String field = "B类的字符串field";
public void fun(){
System.out.println("B类的方法1");
}
public void funB(){
System.out.println("B类的方法B");
}
}
两个类都有实例变量field,一个为整型,一个为字符串
两个类都有不同的普通实例方法分别是funA()和funB()
A类中的fun()被B类重写了
一般情况下我们会这么写
A a = new A();
System.out.println(a.field);
a.fun();
a.funA();
输出为
5
A类的方法1
A类的方法A
或者我们会这么写
B b = new B();
System.out.println(b.field);
b.fun();
b.funB();
输出为
B类的字符串field
B类的方法1
B类的方法B
以上两种情况中,我们声明了一个类A(或B)的的引用变量a(或b),并且new了一个类A(或B)的实例
说明编译类型和运行类型一致,不会出现什么特殊的情况
但是如果我们写
A c = new B();
情况就会变得特殊一些,我们声明了一个类A(编译类型)的引用变量c,但其实际被赋值为类B(运行类型)的一个实例引用
这时就产生了多态
System.out.println(c.field);
我们输出c的field变量,结果为5,说明访问的是父类A的实例变量
c.fun();
我们调用方法fun()发现输出为“B类的方法1”,说明此时访问的是子类B的实例方法
这就是多态
总结:多态的情况下,调用实例方法时,总是表现出子类方法(运行时类型)的行为特征,而实例变量不存在多态性,系统总是试图访问其定义类型(编译时类型)的实例变量
一个特别需要注意的是,以下的代码将引发编译错误
c.funB();
这是因为引用变量c的编译类型为类A,而类A中不含有方法funB(),即使c确实含有这个方法