Java多态
多态是同一个行为具有多个不同表现形式或形态的能力。
多态性是对象多种表现形式的体现。
比如我们说"宠物"这个对象,它就有很多不同的表达或实现,比如有小猫、小狗、蜥蜴等等。那么我到宠物店说"请给我一只宠物",服务员给我小猫、小狗或者蜥蜴都可以,我们就说"宠物"这个对象就具备多态性。
public interface Vegetarian{}
public class Animal{}
public class Deer extends Animal implements Vegetarian{}
//因为Deer类具有多重继承,所以它具有多态性。以上实例解析如下:
一个 Deer IS-A(是一个) Animal
一个 Deer IS-A(是一个) Vegetarian
一个 Deer IS-A(是一个) Deer
一个 Deer IS-A(是一个)Object
Java中,所有的对象都具有多态性,因为任何对象都能通过IS-A测试的类型和Object类。
访问一个对象的唯一方法就是通过引用型变量。
引用型变量只能有一种类型,一旦被声明,引用型变量的类型就不能被改变了。
引用型变量不仅能够被重置为其他对象,前提是这些对象没有被声明为final。还可以引用和它类型相同的或者相兼容的对象。它可以声明为类类型或者接口类型。
Deer d = new Deer();
Animal a = d;
Vegetarian v = d;
Object o = d;
//当我们将引用型变量应用于Deer对象的引用时,以上的声明是合法的,所有的引用型变量都指向相同的对象Deer
多态的实现方法:
重写,接口,抽象类和抽象方法
抽象类
Java 面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类不能实例化对象,但是类的其他功能依然存在,成员变量,成员方法,构造方法的访问方式和普通类一样。
抽象类必须要被继承才能使用,所以在设计阶段就应该决定要不要抽象类
如果父类包含子类集合的常见方法,但是由于父类本身是抽象的,所以不能使用这些方法
//定义一个抽象类,和正常类没有什么不同,存在成员变量,构造器,方法。但是抽象类不能被实例化
public abstract 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 double computePay()
{
System.out.println("Inside Employee computePay");
return 0.0;
}
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;
}
}
怎么才能使用定义好的抽象类呢,使用一般的方法继承abstract类
//创建一个类继承抽象类
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;
}
}
//不能实例化一个抽象类对象,可以通过继承,实例化
public class AbstractDemo
{
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();
}
}
抽象方法
抽象方法存在抽象类,接口中。
抽象类中可以存在普通方法,可以没有抽象方法,全部都是普通方法都可以。但是一个类只要有了抽象方法,就一定是抽象类
设计一个抽象类,再设计一个抽象方法,抽象方法中无具体实现,具体实现由它的子类来实现,
抽象方法只有一个方法名,中无方法体
public abstract class Employee
{
private String name;
private String address;
private int number;
public abstract double computePay();
//其余代码
}
任何继承抽象方法的子类必须重写该方法。否则声明子类也是抽象类,最终必须有一个子类实现该抽象方法。
public class Salary extends Employee
{
private double salary; // Annual salary
public double computePay() //重写来自父类的抽象方法
{
System.out.println("Computing salary pay for " + getName());
return salary/52;
}
//其余代码
接口
接口(Interface)在java中是一个抽象类型,是抽象方法的集合,一个类可以继承接口,从而继承接口的抽象方法。
接口不等于类,只是两者的编写方式很相似。类描述对象的属性和方法,接口包括类要实现的方法。
接口(eg List)无法被实例化,同抽象类相似,但是可以被实现,一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在Java中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
接口与类相似点:
- 一个接口可以有多个方法。
- 接口文件保存在.java结尾的文件中,文件名使用接口名。
- 接口的字节码文件保存在.class结尾的文件中。
- 接口相应的字节码文件必须在与包名称相匹配的目录结构中。
接口与类的区别:
- 接口不能用于实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法。
- 接口不能包含成员变量,除了static和final变量。
- 接口不是被类继承了,而是要被类实现。
- 接口支持多重继承。
//接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字
interface Animal {
//接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。接口中的方法都是公有的。
public void eat();
public void travel();
}
接口的实现
当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。
类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。
实现一个接口的语法,可以使用这个公式:
... implements 接口名称[, 其他接口, 其他接口..., ...] ...
public class MammalInt implements Animal{
//实现Animal接口的eat()方法
public void eat(){
System.out.println("Mammal eats");
}
//实现Animal接口中的travel()方法
public void travel(){
System.out.println("Mammal travels");
}
public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
实现接口的时候,也要注意一些规则:
- 一个类可以同时实现多个接口。
- 一个类只能继承一个类,但是能实现多个接口。
- 一个接口能继承另一个接口,这和类之间的继承比较相似。
接口的继承
一个接口能继承另一个接口,和类之间的继承方式比较相似。接口的继承使用extends关键字,子接口继承父接口的方法。
下面的Sports接口被Hockey和Football接口继承:
public interface Sports
{
public void setHomeTeam(String name);
public void setVisitingTeam(String name);
}
// 文件名: Football.java
public interface Football extends Sports
{
public void homeTeamScored(int points);
public void visitingTeamScored(int points);
public void endOfQuarter(int quarter);
}
// 文件名: Hockey.java
public interface Hockey extends Sports
{
public void homeGoalScored();
public void visitingGoalScored();
public void endOfPeriod(int period);
public void overtimePeriod(int ot);
}
接口允许多重继承
public interface Hockey extends Sports, Event
接口中可以不包含任何方法
标识接口
标识接口是没有任何方法和属性的接口.它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情。
标识接口作用:简单形象的说就是给某个对象打个标(盖个戳),使对象拥有某个或某些特权。
例如:java.awt.event包中的MouseListener接口继承的java.util.EventListener接口定义如下:
package java.util;
public interface EventListener
{}
标记接口主要用于以下两种目的:
- 建立一个公共的父接口:
正如EventListener接口,这是由几十个其他接口扩展的Java API,你可以使用一个标记接口来建立一组接口的父接口。例如:当一个接口继承了EventListener接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。
- 向一个类添加数据类型:
这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过多态性变成一个接口类型。