从虚拟机角度理解Java中的多态


title: 从虚拟机角度理解Java中的多态 date: 2018-09-29 09:37:08 tags:编程

  • Java
  • 多态 categories: 虚拟机

  众多周知,面向对象的编程思想中包含四大特性:抽象、封装、继承和多态。Java中有三种实现多态的方法:重载、重写和覆盖。关于三者的差别,已经有大量的技术博客给予了详细的分析与总结,本文从虚拟机角度对三者进行全新的阐释。在虚拟机看来,所谓的重载、重写和覆盖,其实是一个选择方法或属性版本的问题,这叫作分派。Java中有两种分派,静态分派和动态分派。静态分派是编译期肯定的,而动态分派是运行期肯定的。重载和覆盖是静态分派,而重写是运行期肯定的。app

重载

  先看一段代码:spa

public static void main(String[] args) {
		Human human = new Human();
		Woman woman = new Woman();
		Man man = new Man();
		Wrapper wrapper = new Wrapper();
		wrapper.sayHello(human); // Hello,human 
		wrapper.sayHello(woman); // Hello,woman
		wrapper.sayHello(man); // Hello,man

	}

	public static class Wrapper {
		public void sayHello(Human human) {
			System.out.println("Hello,human");
		}

		public void sayHello(Woman woman) {
			System.out.println("Hello,woman");
		}

		public void sayHello(Man man) {
			System.out.println("Hello,man");
		}
	}

	public static class Human {

	}

	public static class Woman extends Human {

	}

	public static class Man extends Human {

	}
复制代码

  因为重载是静态分派,是由编译器完成的。编译器并不清楚变量woman和man的实际类型,只知道它们的外观类型是Woman和Man,所以选择和外观类型最接近的方法版本进行调用。code

重写

  再看一段代码:对象

public static void main(String[] args) {
		Human human = new Human();
		Human woman = new Woman();
		Human man = new Man();
		human.sayHello(); // Hello,human
		woman.sayHello(); // Hello,woman
		man.sayHello(); // Hello,man
	}

	public static class Human {
		public void sayHello() {
			System.out.println("Hello,human");
		}

	}

	public static class Woman extends Human {
		public void sayHello() {
			System.out.println("Hello,woman");
		}
	}

	public static class Man extends Human {
		public void sayHello() {
			System.out.println("Hello,man");
		}
	}
复制代码

  因为重写是动态分派,是由虚拟机完成的。虚拟机清楚地知道每一个变量的实际类型,所以会调用实际类型的方法。继承

覆盖

  仍是再看一段代码:编译器

public static void main(String[] args) {
		Human human = new Human();
		Human woman = new Woman();
		Human man = new Man();
		System.out.println(human.name); // Human
		System.out.println(woman.name); // Human
		System.out.println(man.name); // Human
	}

	public static class Human {
		public String name = "Human";

	}

	public static class Woman extends Human {
		public String name = "Woman";
	}

	public static class Man extends Human {
		public String name = "Man";
	}
复制代码

  三个方法的输出都是"Human"!是否是难以理解?缘由在于,属性覆盖也是一个静态分派过程,由编译器完成,编译器只知道外观类型,因此就选择外观类型中的属性版本。博客

相关文章
相关标签/搜索