Java语言中的多态性
概述
多态是面向对象的三大特征之一,另外两个是封装、继承。
之前看过一个对多态很形象的解释:如果编译时类型和运行时类型不一样的话,就会出现多态。
编译时类型与运行时类型
这里有编译时类型和运行时类型,这是因为Java有点特别,因为java代码都要编译成*.class文件(此阶段叫编译),然后*.class文件在JVM里面运行(此阶段叫运行)。所以,这两种类型的区别之处就在于:
1、编译时类型就是在声明一个变量时,指定该变量的类型。
2、而运行时类型,就是真正赋值给这个变量的值的类型。
为了方便理解,下面举一个简单的例子:
double a = 10;
上面这行代码中,声明了一个变量,变量的编译时类型是double类型,而赋值给a的值是int类型,所以a的运行时类型是int。这个例子只是为了方便理解,解释不一定正确。
对象中的多态
直接看例子吧:
class BaseClass{
public int age = 100;
public void showInfo(){
System.out.println("Base class showInfo");
}
public void say(){
System.out.println("Base class say");
}
}
class SubClass extends BaseClass{
public int age = 200;
public String name = "demo";
public void say(){
System.out.println("Sub class say");
}
public void speak(){
System.out.println("sub class speak");
}
}
public class Test{
public static void main(String[] args){
BaseClass bc = new SubClass();
// 注意,BaseClass是编译时类型,而SubClass是运行时类型
bc.showInfo();
// Base class showInfo
bc.say();
// Sub class say
// 编译出错
// bc.speak();
System.out.println(bc.age);
// 100
// 编译出错
// System.out.println(bc.name);
}
}
多态的原则(结论),有几个注意点:
1、编译时类型必须是运行时类型的父类或者间接父类。编译时类型不能是运行时类型的子类。可以形象记忆:父类比子类范围大,将父类赋值给子类,会有精度损失,所以会出错。
2、子类可以继承、覆盖父类的成员属性,或者增加自己的成员属性;同样子类也可以继承、重写父类的成员方法,或者增加自己的成员方法。
3、创建的对象(编译时类型为父类类型,运行时类型为子类类型),通过该对象,只能访问或者调用编译类型的成员属性和成员方法(父类中定义的成员属性和成员方法),而不能访问子类中新增的成员属性和成员方法。这是在编译阶段需要注意的,如果通过该对象访问子类中的成员属性和成员方法,就会报错。
4、前面已经说了,通过对象引用,只能访问或者调用两个类中共有的那些成员属性和方法。但是前面也,在子类中,子类是可以覆盖或者重写从父类中继承过来的成员属性和成员方法。
I、对于成员属性来说:无论在子类中是否覆盖父类中的成员属性,在真正运行时,访问该成员属性,得到的值都是父类中那个成员属性值(即使子类重写之后赋了其他值)。
II、对于成员方法来说:如果子类中没有重写父类中的方法,那么调用的就是父类中的成员方法;如果子类中重写了父类中的方法,那么运行时调用的就是子类中重写之后的成员方法。
5、如果非要使用子类中新增的成员属性或者覆盖的成员属性,或者新增的成员方法,可以使用(type)variable来强制将编译类型为父类,运行类型为子类的对象转换为子类类型,之后就可以了。
class BaseClass{
public int age = 100;
public void showInfo(){
System.out.println("Base class showInfo");
}
public void say(){
System.out.println("Base class say");
}
}
class SubClass extends BaseClass{
public int age = 200;
public String name = "demo";
public void say(){
System.out.println("Sub class say");
}
public void speak(){
System.out.println("sub class speak");
}
}
public class Test{
public static void main(String[] args){
BaseClass bc = new SubClass();
bc.showInfo();
// Base class showInfo
bc.say();
// Sub class say
// 编译错误
// bc.speak();
((SubClass)bc).speak();
// sub class speak
System.out.println(bc.age);
// 100
// 编译错误
// System.out.println(bc.name);
System.out.println(((SubClass)bc).name);
// demo
}
}
浙公网安备 33010602011771号