多态是同一个行为具有多个不同表现形式或形态的能力。
多态性是对象多种表现形式的体现。
比如我们说"宠物"这个对象,它就有很多不同的表达或实现,比如有小猫、小狗、蜥蜴等等。那么我到宠物店说"请给我一只宠物",服务员给我小猫、小狗或者蜥蜴都可以,我们就说"宠物"这个对象就具备多态性。
接下来让我们通过实例来了解java的多态。
public interface vegetarian{}
public class animal{}
public class deer extends animal implements vegetarian{}
因为deer类具有多重继承,所以它具有多态性。以上实例解析如下:
在java中,所有的对象都具有多态性,因为任何对象都能通过is-a测试的类型和object类。
访问一个对象的唯一方法就是通过引用型变量。
引用型变量只能有一种类型,一旦被声明,引用型变量的类型就不能被改变了。
引用型变量不仅能够被重置为其他对象,前提是这些对象没有被声明为final。还可以引用和它类型相同的或者相兼容的对象。它可以声明为类类型或者接口类型。
当我们将引用型变量应用于deer对象的引用时,下面的声明是合法的:
deer d = new deer();
animal a = d;
vegetarian v = d;
object o = d;
所有的引用型变量d,a,v,o都指向堆中相同的deer对象。
我们将介绍在java中,当设计类时,被重写的方法的行为怎样影响多态性。
我们已经讨论了方法的重写,也就是子类能够重写父类的方法。
当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。
要想调用父类中被重写的方法,则必须使用关键字super。
/* 文件名 : employee.java */
public class employee
{
private string name;
private string address;
private int number;
public employee(string name, string address, int number)
{
system.out.println("constructing an employee");
this.name = name;
this.address = address;
this.number = number;
}
public void mailcheck()
{
system.out.println("mailing a check to " + this.name
+ " " + this.address);
}
public string tostring()
{
return name + " " + address + " " + number;
}
public string getname()
{
return name;
}
public string getaddress()
{
return address;
}
public void setaddress(string newaddress)
{
address = newaddress;
}
public int getnumber()
{
return number;
}
}
假设下面的类继承employee类:
/* 文件名 : salary.java */
public class salary extends employee
{
private double salary; //annual salary
public salary(string name, string address, int number, double
salary)
{
super(name, address, number);
setsalary(salary);
}
public void mailcheck()
{
system.out.println("within mailcheck of salary class ");
system.out.println("mailing check to " + getname()
+ " with salary " + salary);
}
public double getsalary()
{
return salary;
}
public void setsalary(double newsalary)
{
if(newsalary >= 0.0)
{
salary = newsalary;
}
}
public double computepay()
{
system.out.println("computing salary pay for " + getname());
return salary/52;
}
}
现在我们仔细阅读下面的代码,尝试给出它的输出结果:
/* 文件名 : virtualdemo.java */
public class virtualdemo
{
public static void main(string [] args)
{
salary s = new salary("mohd mohtashim", "ambehta, up", 3, 3600.00);
employee e = new salary("john adams", "boston, ma", 2, 2400.00);
system.out.println("call mailcheck using salary reference --");
s.mailcheck();
system.out.println("\n call mailcheck using employee reference--");
e.mailcheck();
}
}
以上实例编译运行结果如下:
constructing an employee
constructing an employee
call mailcheck using salary reference --
within mailcheck of salary class
mailing check to mohd mohtashim with salary 3600.0
call mailcheck using employee reference--
within mailcheck of salary class
mailing check to john adams with salary 2400.0
例子中,我们实例化了两个salary对象。一个使用salary引用s,另一个使用employee引用。
编译时,编译器检查到mailcheck()方法在salary类中的声明。
在调用s.mailcheck()时,java虚拟机(jvm)调用salary类的mailcheck()方法。
因为e是employee的引用,所以调用e的mailcheck()方法则有完全不同的结果。
当编译器检查e.mailcheck()方法时,编译器检查到employee类中的mailcheck()方法。
在编译的时候,编译器使用employee类中的mailcheck()方法验证该语句, 但是在运行的时候,java虚拟机(jvm)调用的是salary类中的mailcheck()方法。
该行为被称为虚拟方法调用,该方法被称为虚拟方法。
java中所有的方法都能以这种方式表现,借此,重写的方法能在运行时调用,不管编译的时候源代码中引用变量是什么数据类型。