java多态

多态可以分为编译时多态(静态绑定),和运行时多态(动态绑定)。编译时多态就是重载,但是我们主要介绍的运行时多态。

静态绑定

在程序运行之前就知道属于哪个类,在编译的时候就能连接到类,定位找到该方法。
关键字final、private、构造函数和static属于静态绑定。

  1. final:方法内数据不可变,子类不能覆盖父类或者说防止方法的重写,所以对象调用该方法是明确的。

  2. private:有private的方法是不能继承的,所以对象调用该方法是也是明确的。

  3. 构造函数:构造函数定义就是不能继承的。调用构造函数不会出现不明确的情况,有就对,没有的话就报错。Super()只是调用父类的构造方法,不是继承。

  4. 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); 不可能
  }
}

当一个类实现多个接口,但是多个接口都用相同的方法时,不用重复写多个方法,只要在该类写一个方法就好了,无论是哪个接口引用调用该方法,都是执行该类的同一个方法。

多态的优点

  1. 消除类型之间的耦合关系
  2. 可替换性
  3. 可扩充性
  4. 接口性
  5. 灵活性
  6. 简化性

接口优点的参考
https://blog.csdn.net/yu555666/article/details/1515674
接口和抽象类的区别参考
https://blog.csdn.net/fenglibing/article/details/2745123

你可能感兴趣的:(java)