Java多态机制

在学习多态之前,需要先了解后期绑定(又称为动态绑定),它的含义就是在运行时根据对象的类型进行绑定,从而调用恰当的方法。Java支持动态绑定!

Java中除了static方法和final方法(private方法也属于final方法)之外,其它所有方法都是后期绑定。

这里举个列子:

package s1;

public class B {
	public static void main(String[] args) {
		Shape shape1 = new Shape();
		Shape shape2 = new Circle();
		Shape shape3 = new Square();
		shape1.draw();
		shape2.draw();
		shape3.draw();
	}

}

class Shape{
	void draw() {
		System.out.println("Shape draw");
	}
}

class Circle extends Shape {
	void draw() {
		System.out.println("Circle draw");
	}
}

class Square extends Shape {
	void draw() {
		System.out.println("Square draw");
	}
}

运行结果:(之所以有下面的运行结果是因为shape1、shape2、shape3虽然都是Shape变量,但是所指向的对象却分别是Shape、Circle、Square,由于运行时绑定,所以才会调用不同对象的方法)

Shape draw
Circle draw
Square draw

这里再举另一个列子:

package s1;

public class B {
	public static void main(String[] args) {
		Shape shape1 = new Shape();
		Shape shape2 = new Circle();
		Shape shape3 = new Square();
		shape1.test();
		shape2.test();
		shape3.test();
	}
	
}

class Shape{
	void test() {
		draw();
	}
	
	void draw() {
		System.out.println("Shape draw");
	}
}

class Circle extends Shape {
	void draw() {
		System.out.println("Circle draw");
	}
}

class Square extends Shape {
	void draw() {
		System.out.println("Square draw");
	}
}

运行时结果:

Shape draw
Circle draw
Square draw

如果是私有方法,则会被自动认为是final方法,并且对子类(导出类)也是不可见的,因而无法实现多态机制。

package s1;

public class B {
	public static void main(String[] args) {
		Shape shape1 = new Shape();
		Shape shape2 = new Circle();
		Shape shape3 = new Square();
		shape1.test();
		shape2.test();
		shape3.test();
	}
}

class Shape{
	void test() {
		draw();
	}
	
	private void draw() {
		System.out.println("Shape draw");
	}
}

class Circle extends Shape {
	void draw() {
		System.out.println("Circle draw");
	}
}

class Square extends Shape {
	void draw() {
		System.out.println("Square draw");
	}
}

运行结果:

Shape draw
Shape draw
Shape draw

多态机制对域和静态方法是不支持的。因为任何域访问都是编译器解析,因此不支持多态。

下面举个关于域的例子:

package s1;

public class B {
	public static void main(String[] args) {
		Shape shape1 = new Shape();
		Shape shape2 = new Circle();
		Shape shape3 = new Square();
		System.out.println("shape1 value:" + shape1.value);
		shape1.getValue();
		System.out.println("shape2 value:" + shape2.value);
		shape2.getValue();
		System.out.println("shape3 value:" + shape3.value);
		shape3.getValue();
	}
}

class Shape{
	int value = 0;
	
	void getValue() {
		System.out.println("Shape vlaue:" + value);
	}
}

class Circle extends Shape {
	int value = 1;
	
	void getValue() {
		System.out.println("Circle vlaue:" + value);
	}
}

class Square extends Shape {
	int value = 2;
	
	void getValue() {
		System.out.println("Square vlaue:" + value);
	}
}

运行结果如下:

shape1 value:0
Shape vlaue:0
shape2 value:0
Circle vlaue:1
shape3 value:0
Square vlaue:2

下面举个关于静态方法的例子:

package s1;

public class B {
	public static void main(String[] args) {
		Shape shape = new Circle();
		shape.staticGet();
		shape.dynamicGet();
	}
}

class Shape{
	public static void staticGet() {
		System.out.println("Shape staticGet");
	}
	
	public void dynamicGet() {
		System.out.println("Shape dynamicGet");
	}
}

class Circle extends Shape {
	public static void staticGet() {
		System.out.println("Circle staticGet");
	}
	
	public void dynamicGet() {
		System.out.println("Circle dynamicGet");
	}
}

运行结果:

Shape staticGet
Circle dynamicGet

构造器和多态,如果在类的构造方法中出现多态,会有怎么样的情况发生,请看下面的例子:

package s1;

public class B {
	public static void main(String[] args) {
		Shape shape = new Circle();
	}
}

class Shape{
	public Shape() {
		draw();
	}
	
	public void draw() {
		System.out.println("Shape draw");
	}
}

class Circle extends Shape {
	int value = 1;
	public void draw() {
		System.out.println("Circle draw");
		System.out.println("value:"+value);
	}
}

运行结果:

Circle draw
value:0

从上面的结果,我们可以发现构造器内,依然可以发生多态。但是value的值却是0而不是1。这和初始化的顺序有关(具体可参见https://blog.csdn.net/GracefulGuigui/article/details/103856984)。

在其它任何事物发生之前,将分配给对象的存储空间初始化成二进制的零。由于Shape类的构造器调用的draw()是Circle的draw(),而此时Circle类还没初始化。所以value的值依然是最开始的二进制零。

注意:多态仅发生在非静态方法,并且子类B(B extends A)可以调用父类A中的同名方法。注意类A和B的同名方法的返回类型可以不一致,但是父类的返回类型范围不小于子类的返回类型!

1、public方法完全支持多态机制,包括在同一个包(package)内+不在同一个包内

2、protected方法完全支持多态机制,包括在同一个包(package)内+不在同一个包内

3、默认(包)方法不完全支持多态机制,必须要在同一个包(package)内;不在同一个包内无法发生多态,因为子类B无法调用父类的同名方法

4、private方法完全不支持多态机制

下面举个例子,注意Shape和Circle是在不同的包下的!并且二者的draw()方法的返回类型也不同!

package s1;

import s2.Circle;

public class B {
	public static void main(String[] args) {
		Shape shape = new Circle();
		shape.draw();
	}
}
package s1;

public class Shape {
	public Shape() {
		draw();
	}
	
	public Object draw() {
		System.out.println("Shape draw");
		return "";
	}
}
package s2;

import s1.Shape;

public class Circle extends Shape {
	int value = 1;
	public String draw() {
		System.out.println("Circle draw");
		System.out.println("value:"+value);
		return "";
	}
}

运行结果:

Circle draw
value:0
Circle draw
value:1
发布了64 篇原创文章 · 获赞 4 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/GracefulGuigui/article/details/103869327