Java 引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就可能出现所谓的多态(Polymorphism)。
1,多态性
package com.demo;
class BaseClass{
public int book = 6;
public void base(){
System.out.println("父类的普通方法");
}
public void test(){
System.out.println("父类的被覆盖的方法");
}
}
public class SubClass extends BaseClass {
//重新定义一个 book 实例 Field 隐藏父类的 book 实例 Field
public String book = "java书";
public void test(){
System.out.println("子类的覆盖父类的方法");
}
public void sub(){
System.out.println("子类的普通方法");
}
public static void main(String[] args) {
//下面编译时类型和运行时类型完全一样,因此不存在多态
BaseClass bc = new BaseClass();
//输出6
System.out.println(bc.book);
//下面两次调用将执行BaseClass的方法
bc.base();
bc.test();
//下面编译时类型和运行时类型完全一样,因此不存在多态
SubClass sc = new SubClass();
//输出 java书
System.out.println(sc.book);
//下面调用将执行从父类继承到的base方法
sc.base();
//下面调用将执行当前类的test方法
sc.test();
//下面编译时类型和运行时类型不一样,多态发生
BaseClass ploymophicBc = new SubClass();
//输出 6 -- 表明访问的是父类 Field
System.out.println(ploymophicBc.book);
//下面调用执行从父类继承到的base 方法
ploymophicBc.base();
//下面调用将执行当前类的 test 方法
ploymophicBc.test();
//因为 ploymophicBc 的编译时类型是 BaseClass
//BaseClass 类没有提供 sub 方法,所以下面代码编译时出现错误
//ploymophicBc.sub();
}
}
6
父类的普通方法
父类的被覆盖的方法
java书
父类的普通方法
子类的覆盖父类的方法
6
父类的普通方法
子类的覆盖父类的方法
上面的程序的 main 方法中显示创建了三个引用变量,对于前两个引用变量bc 和 sc, 它们编译时类型和运行时类型完全相同,因此调用它们的 Field 和方法非常正常,完全没有任何问题。但第三个引用变量 ploymophicBc 则比较特殊,它的编译时类型是BaseClass,而运行时类型是 SubClass,当调用该引用变量的test方法(BaseClass类中定义了该方法,子类SubClass覆盖了父类的该方法)时,实际执行的是 SubClass 类中覆盖后的 test 方法,可就可能不吃按多态了。
相同类型的变量、调用同一个方法时呈现出多种不同的I型能够为特征,这就是多态。
上面的 main 的方法中注释了 ploymophicBc.sub();,这行代码会在编译时引发错我。虽然ploymophicBc 引用变量实际上确实包含 sub() 方法,但因为它的编译时类型为 BaseClass,因此编译时无法调用 sub() 方法。
2,引用变量的强制类型转换
编写 Java 程序是,引用变量值能调用它编译时类型的方法,而不能调用它运行时类型的方法,即使它实际所引用的队形确实包含该方法,如果需要让这个引用变量调用它运行时类型的方法,则必须把他强制类型转换成运行时类型,强制类型转换需要借助于类型转换运算符。
这中强制类型转换不是万能的,当进行强制类型转换时需要注意:
基本类型之间的转换只能在数值类型值间进行,这里所说的数值类型包括整数型、字符型和浮点型。但数值类型和布尔类型之间不能进行类型转换。
引用类型支架你的转换只能在具有继承关系的两个类型之间进行,如果是两个没有任何继承关系的类型,则无法进行类型转换,否则编译时会出现错误。
3,instanceof 预算法
instanceof 运算符的前一个操作数通常是一个引用类型变量,后一个操作数通常是一个类(也可以是接口,可以把接口理解成一种特殊的类),它用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是,则返回true,否则返回false。
package com.demo;
public class InstanceofTest {
public static void main(String[] args) {
//声明 hello 时使用 Object 类,则hello 的编译类型是 Object
//Object 是所有类的父类,但hello变量的实际类型是String
Object hello = "Hello";
//String 是 Object 类的子类,可以进行 instanceof 运算。返回true
System.out.println("字符串是否是 Object 类的实例:" + (hello instanceof Object));
//返回true
System.out.println("字符串是否是String 类的实例" + (hello instanceof String));
//Math是Object类的子类,可以进行
System.out.println("字符串是否是 Math 类的实例:" + (hello instanceof Math));
//String实现了Comparable接口,所以返回 true
System.out.println("字符串是否是Comparable接口的实例:" + (hello instanceof Comparable));
String a = "Hello";
//String类既不是Math类,也不是Math类的父类
//所以下面代码编译无法通过
System.out.println("字符串是否是Math类的实例:" + (a instanceof Math));
}
}