java 多态
1.多态释义
多态是指同一操作用于不同的类的实例,不同的类将进行不同的解释,最后产生不同的结果,也就是,相同的语句在不同的运行环境中可以产生不同的运行结果。
多态的本质特征就是父类(或接口)变量可以引用子类(或实现接口的类)对象,也就是子类对象可以被当做基类对象使用。
Parent p=new Child1();
Parent p=new Child2();
总是可以让更一般的对象容纳更具体的对象
子类与基类间的赋值:
子类对象可以直接赋给基类变量,但是基类对象要想赋给子类变量必须执行类型转换,语法为:
子类变量=(子类名)基类对象名;
这种转换失败会抛出ClassCastException异常。通过instanceof判断对象是否可转换为指定类型。
下面代码便于理解类型转换:
public class TestMain {
public static void main(String[] args) {
// TODO Auto-generated method stub
Parent parent=new Parent();
parent.printVal();//100
Child child=new Child();
child.printVal();//200
parent=child;
parent.printVal();//200,调用子类方法
parent.val++;//父类字段
System.out.println(parent.val);//101
parent.printVal();//200,子类方法
((Child)parent).val++;//子类字段
parent.printVal();//201//子类方法
}
}
class Parent{
public int val=100;
public void printVal(){
System.out.println("Parent.printVal,val="+val);
}
}
class Child extends Parent{
public int val=200;
public void printVal(){
System.out.println("Childs.printVal,val="+val);
}
}
总结一下输出这样结果的原因:
1.子类与父类有同名方法时:
一个父类变量引用一个子类对象时,具体调用哪个方法由对象”真实”类型决定,就是说,对象是子类型就调用子类型方法,是父类型就调用父类型方法。
2.子类父类具有同类型同名字段时:
子类字段会隐藏父类字段,子类方法访问的是子类字段(而不是父类字段)。如果子类确实想访问父类字段,可以用super关键字访问。
但如果子类被当做父类使用,即父类变量名子类对象,则访问的字段是父类的。
注意当把子类对象当成父类对象使用时,子类对象将失去所有的子类特性,只保留与父类同名的属性和方法(同名方法不仅是函数名相同,而且参数类型也要一样,否则不予保留)。
下面举个例子来说明多态的使用:
动物类:
public class Animal {
public void cry(){
System.out.println("我不知道叫什么");
}
public void eat(){
System.out.println("我不知道吃什么");
}
}
猫类:
public class Cat extends Animal{
public void cry(){
System.out.println("喵喵");
}
public void eat(){
System.out.println("我是猫,我吃鱼");
}
}
狗类:
public class Dog extends Animal{
public void cry(){
System.out.println("旺旺");
}
public void eat(){
System.out.println("我是狗,我吃骨头");
}
}
食物接口:
public interface Food {
public void showName();
}
食物骨头:
public class Bone implements Food {
@Override
public void showName() {
// TODO Auto-generated method stub
System.out.println("食物:骨头");
}
}
食物鱼:
public class Fish implements Food {
@Override
public void showName() {
// TODO Auto-generated method stub
System.out.println("食物:鱼");
}
}
主人类:
public class Master {
public void feed(Animal an,Food f){
an.eat();
f.showName();
}
}
测试:
public class TestMain {
public static void main(String[] args) {
Master master=new Master();
master.feed(new Dog(), new Bone());
master.feed(new Cat(), new Fish());
}
}
输出:
我是狗,我吃骨头
食物:骨头
我是猫,我吃鱼
食物:鱼
可以看出多态在代码量非常巨大的时候,当需要修改代码或扩展系统时需要修改的地方非常少。
再来一份代码练习:
public class TestMain {
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(a1.show(b));//b是a子类,调用show2
System.out.println(a1.show(c));//c是a子类,调用show2
System.out.println(a1.show(d));//d就是D,调用show1
//a2是A变量名,B对象,应调用B方法覆盖掉A的方法即B的第二个show,B自身特性消失
System.out.println(a2.show(b));//show3消失,show4覆盖show1,故调用show4
System.out.println(a2.show(c));//同上
System.out.println(a2.show(d));//直接调用show1
System.out.println(b.show(b));//原生B,直接用show3,4
System.out.println(b.show(c));//同上
System.out.println(b.show(d));//由于B也有A的属性,故含有show1方法,所以调用show1
}
}
class A
{
public String show(D obj){//show1
return ("A and D");
}
public String show(A obj){//show2
return ("A and A");
}
}
class B extends A
{
public String show(B obj){//show3
return ("B and B");
}
public String show(A obj){//show4
return ("B and A");
}
}
class C extends B{
}
class D extends B{
}
输出:
A and A
A and A
A and D
B and A
B and A
A and D
B and B
B and B
A and D
参考:
金旭亮Java编程系列