多态是面向对象的重要特征,同时也是对象开发软件的一个特殊特性,指的是一个程序 总同名的不同方法共存的情况。
多态分为运行时多态与编译时多态。编译时多态用重载实现,即在.java 中的多个方法 在编译阶段即表现出多种形态(重载:同名不同参)。这种多态是通过参数的多样化来 实现的。
运行时多态:在运行阶段才表现出多种形态。基础:父类引用指向子类对象。
在 Human 中,定义了一个 name 属性:protected String name;定义了一个 eat 方法:public void eat(String food);
在 Sinaean 中,重写了继承自父类 Human 的 eat 方法;
在 Thai 中,重写了继承自父类 Human 的 eat 方法;
在 Englishman 中,重写了继承自父类 Human 的 eat 方法;
在运行阶段,Human 类型的引用变量引用那个子类类型的对象,就表芯那个对象的特征(就调用谁的 eat 方法)。
源码:
public class Human {
protected String name;
public void eat(String food){
System.out.println(this.name+"吃"+food);
}
}
public class Sinaean extends Human{
// 重写 eat
public void eat(String food){
System.out.println(this.name +"是中国人");
System.out.println("所以他一般用筷子吃 "+ food);
}
}
public class Thai extends Human{
// 重写 eat
public void eat(String food){
System.out.println(this.name +"是泰国人");
System.out.println("所以他一般用手抓着吃 "+ food);
}
}
public class Englishman extends Human {
// 重写 eat
public void eat(String food) {
System.out.println(this.name + "是英国人");
System.out.println("所以他一般用刀叉吃 " + food);
}
}
运行代码:
public class Main {
public static void main(String[] args) {
// Human 类型的引用变量h 引用了堆区中的Human类型的一个对象
Human h = new Human();
h.name = "瑞文";
h.eat("肉夹馍");
// Human 类型的引用变量h 引用了堆区中的Sinaean类型的一个对象
// 父类Human 类型的引用变量引用了 子类 Sinaean类型的一个对象
h = new Sinaean();
h.name = "诺克萨斯";
h.eat("肉夹馍");// 调用 Sinaean 重写的 eat 方法
}
}
注:在运行方法中,要把前边的三个都写上。
总结重点:
基础:子类继承父类,并重写继承自父类的方法,父类类型的引用 引用了子类类型的对象(所以表现不同的特征)。
运行时类型与编译时类型:
在运行时多态中声明的那个父类类型的变量(h)的类型 Human 是 h 变量的【编译 时类型】;// Human h; 编译阶段就能明确确定 h 是 Human 的类型。
在运行阶段,具体引用那个子类类型的对象,就表现那个类型的特征,这个类型叫【运 行时类型】;
//h = new Sinaean();在运行阶段 h 变量引用了 Sinaean,所以当前它 的运行时类型是 Sinaean 类。
Java 语言中,所有的类都继承了 java.lang.Object;因此所有的类都继承了 Object
的方法。Object 类中定义了一个方法:getClass(),所以任何对象都可以通过 getClass()来获得其运行时类型。
instanceOf
用于类型检查的运算符:instanceof 的作用类似于判定 " xxx 是 xxx 吗 ",insatanceOf 仅仅用与判断引用类型的变量是否是某个类型。
instanceof 用于判断某个引用类型的变量是否是某个类型:instanceof 操作符的左边是需要判断的引用类型的变量;instanceof 操作符的右边是某个类型(可以是类、接口等);instanceof 返回 boolean 类型的结果:仅当 前面的引用类型变量 的类型的确是后面的类型 时返回 true 。
/**
* 1、instanceof 仅用来判断引用类型的变量是否是某个类型
* 2、通常,用 instanceof 来判断 某个 引用 是否是某个类型
* 判断类型,可能是为了确定变量的类型,然后完成类型转换
* if( h instanceof Sinaean){// 验明正身
* Sinaean s = (Sinaean)h; // 如果是 ,就转换
* s.surname = "金毛狮王"; // 转换是为了访问只有Sinaean 所定义的属性 和方法
* }
*/
public class TestInstanceOf {
public static void main(String[] args) {
int[] array = {1,4,5,6,8,9};
// 判断array 变量是否是 int[] 类型
System.out.println(array instanceof int[]);
//h变量的【编译时类型】是 Human
// h变量的【运行时类型】 是Sinaean
Human h = new Sinaean();
h.name = "谢逊";
//h.surname = "金毛狮王"; // h 是Human 类型,而 Human 中没有
surname这个属性
System.out.println(h instanceof Human);
System.out.println(h instanceof Sinaean); // h所引用的变量是否是
Sinaean 类型
// 引用类型变量的强制类型转换
Sinaean s = (Sinaean)h;
s.surname = "金毛狮王"; // s的编译时类是是Sinaean,因此可以访问
surname
}
}
引用类型的强制类型转换:
/**
* 引用类型的强制转换,本质:
* 将栈中存放的对象的地址( h 中存放的地址) 赋值给另外一个变量( s ) 并转换成![](https://oscimg.oschina.net/oscnet/2f5997c075d9d8e651569c474ac8899b5fb.jpg)目标类型(Sinaean)
* Sinaean s = (Sinaean)h;
*/
public class TestConvert {
public static void main(String[] args) {
Human h = new Sinaean();
if( h instanceof Sinaean){
Sinaean s = (Sinaean)h;
s.surname = "金毛狮王";
s.name = "谢逊";
}
}
}
示意图如下 :