從虛擬機角度理解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"!是否是難以理解?緣由在於,屬性覆蓋也是一個靜態分派過程,由編譯器完成,編譯器只知道外觀類型,因此就選擇外觀類型中的屬性版本。博客

相關文章
相關標籤/搜索