多态可以分为编译时多态(静态绑定),和运行时多态(动态绑定)。编译时多态就是重载,但是我们主要介绍的运行时多态。
静态绑定
在程序运行之前就知道属于哪个类,在编译的时候就能连接到类,定位找到该方法。
关键字final、private、构造函数和static属于静态绑定。
-
final:方法内数据不可变,子类不能覆盖父类或者说防止方法的重写,所以对象调用该方法是明确的。
-
private:有private的方法是不能继承的,所以对象调用该方法是也是明确的。
-
构造函数:构造函数定义就是不能继承的。调用构造函数不会出现不明确的情况,有就对,没有的话就报错。Super()只是调用父类的构造方法,不是继承。
-
static:静态方法或者变量应该用类名去调用,这样也就不存在访问的时候不明确。若硬要用引用类型去调用的话,只有在父类变量指向子类对象时,当父类子类都有相同的静态方法,调用时改静态变量时,调用的是父类的静态变量。这种现象和类中的成员变量一样,调用父类还是子类,只要看变量是父类还是子类类型,当向上造型是为父类类型,则调用父类里的变量。
总结:有不能继承或者不能重写或者覆盖的就是静态绑定。
动态绑定
在程序运行过程中,根据具体的实例对象才能具体确定是哪个方法
动态绑定是多态性得以实现的重要因素,它通过方法表来实现:每个类被加载到虚拟机时,在方法区保存元数据,其中,包括一个叫做 方法表(method table)的东西,表中记录了这个类定义的方法的指针,每个表项指向一个具体的方法代码。如果这个类重写了父类中的某个方法,则对应表项指向新的代码实现处。从父类继承来的方法位于子类定义的方法的前面。
静态和动态绑定的例子
class Father{
int weight=150;
static int age=30;
static void getAge() {
System.out.println("调用的是父类的静态方法");
}
void getweight() {
System.out.println("调用的是父类的非静态方法");
}
}
public class Son extends Father{
int weight=100;
static int age=15;
static void getAge() {
System.out.println("调用的是子类的静态方法");
}
//方法的重写
void getweight() {
System.out.println("调用的是子类的非静态方法");
}
void set() {
System.out.println("调用的是子类的特殊方法");
}
public static void main(String[] args) {
Father father=new Father();
Son son=new Son();
Father fs=new Son();
//调用非静态方法
father.getweight();
son.getweight();
fs.getweight();
System.out.println("--------");
//调用静态方法,但是会提醒警告,因为调用静态应该用类名调用
father.getAge();
son.getAge();
fs.getAge();
System.out.println("--------");
//调用成员变量
int a1=father.weight;
int a2=son.weight;
int a3=fs.weight;
System.out.println(a1);
System.out.println(a2);
System.out.println(a3);
System.out.println("--------");
//调用静态成员变量,但是会提醒警告,因为调用静态应该用类名调用
int b1=father.age;
int b2=son.age;
int b3=fs.age;
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
}
}
控制台输出:
调用的是父类的非静态方法
调用的是子类的非静态方法
调用的是子类的非静态方法
--------
调用的是父类的静态方法
调用的是子类的静态方法
调用的是父类的静态方法
--------
150
100
150
--------
30
15
30
多态的必要条件
继承
方法重写
父类引用指向子类对像(向上造型)
方法重写:
指的是子类继承父类时,当子类和父类的方法一样时(形参和类型也要一样),当子类访问该方法时,总是会指向子类中定义的方法。
要想调用父类的方法,必须要加上关键字super
向上造型:
1、父类的引用变量可以指向任何子类的对象。调用方法时先判断父类有没有该的方法,如果有,再去调用,反之会报错。
2、父类的引用也可以调用父类有但是子类没有的方法。
3、不能调用子类有但是父类没有的方法。
向下造型:强转后可以调用子类有父类没有的方法。
实现多态的方式
方法重写
接口
抽象类和抽象方法
抽象类和接口的区别:接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。
抽象类重点是关注这个类是什么,比如一个动物的抽象类,子类继承可以是狗、猫等。
而接口重点关注的是能做什么,比如同样是一个动物的接口,子类可以实现的动物的吃,动物的行走,动物的奔跑登一系类动作等。
接口实现多态
一个接口,多种方法
接口引用:一个接口被多个类实现,接口引用可以指向任何的实现类对象时(这里用了向上造型,实现类实例地址赋给接口引用)这样的话在运行的时候,接口引用访问方法时,能根据具体的实例对象,定位找到该对象实现接口的方法。
接口实现多态的例子
interface Vehicle {
public void getmoney();
}
class Car implements Vehicle {
public void getmoney() {
System.out.println("5万");
}
}
class Bus implements Vehicle {
public void getmoney() {
System.out.println("10万");
}
}
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Car car = new Car();
Bus bus = new Bus();
Vehicle vehicle = car;
vehicle.getmoney();
Vehicle vehicle2 = bus;
vehicle2.getmoney();
}
}
控制台输出:
5万
10万
一个类实现多个接口
一个普通类只能继承一个父类,但是一个类可以实现多个接口。
一个对象(类实例引用)的类型可以是本类及父类或者间接的父类,或者接口类型,那么当类实现了多个接口,那么该类的对象(实例引用)都带有多个接口的类型。
类实现多个接口的例子
public interface BritishSpy {
public String speak(); //英国间谍讲英语
}
public interface GermanSpy {
public String sprechen(); //德国间谍讲德语
}
public class DoubleAgent implements BritishSpy, GermanSpy {
public String speak() { return "Hello"; }
public String sprechen() { return "Gutentag"; }
}
public class Agency {
public static void toMI5(BritishSpy spy) {
//军情5处当然只能说英语,做英国间谍
spy.speak();
//spy.sprechen();不可见
}
public static void inGermany(GermanSpy spy) {
//spy.speak();不可见
spy.sprechen();
}
public static void main(String[] args) {
DoubleAgent da = new DoubleAgent();
BritishSpy es = (BritishSpy) da;
GermanSpy gs = (GermanSpy) da;
toMI5(da); //MI5也不知道他是一个双重间谍,只知道他是BritishSpy
toMI5(es); //更安全
//toMI5(gs); 不可能
inGermany(da); //在德国还是安全的,德国人不知道他的双重间谍身份,只知道他是GermanSpy
inGermany(gs);
//inGermany(es); 不可能
}
}
当一个类实现多个接口,但是多个接口都用相同的方法时,不用重复写多个方法,只要在该类写一个方法就好了,无论是哪个接口引用调用该方法,都是执行该类的同一个方法。
多态的优点
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
接口优点的参考
https://blog.csdn.net/yu555666/article/details/1515674
接口和抽象类的区别参考
https://blog.csdn.net/fenglibing/article/details/2745123