Think in Java(五):多态

1. 动态绑定

又称"后期绑定"或"运行时绑定",它的含义就是在运行时判断对象的类型,从而调用恰当的方法

public class Shapes {
	private static RandomShapeGenerator gen = new RandomShapeGenerator();

	public static void main(String[] args) {
		Shape[] shapeArr = new Shape[9];
		// 填充数组
		for (int i = 0; i < shapeArr.length; i++){
			shapeArr[i] = gen.next();
		}
		// 动态调用方法
		for (Shape shape : shapeArr){
			shape.draw();
		}
	}
}

class RandomShapeGenerator {
	private Random rand = new Random(47);

	public Shape next() {
		switch (rand.nextInt(3)) {
			default:
			case 0:
				return new Circle();
			case 1:
				return new Square();
			case 2:
				return new Triangle();
			}
	}
}

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

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

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

	public void erase() {
		System.out.println("Circle.erase()");
	}
}

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

	public void erase() {
		System.out.println("Triangle.erase()");
	}
}

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

	public void erase() {
		System.out.println("Square.erase()");
	}
}
/* Output:
Triangle.draw()
Triangle.draw()
Square.draw()
Triangle.draw()
Square.draw()
Triangle.draw()
Square.draw()
Triangle.draw()
Circle.draw()
*///:~

2. "覆盖"私有方法:

我们期望的输出是public f(),但是由于private方法被自动认为是final方法,而且对子类是屏蔽的,因此在这种情况下,

Derived类中的f()方法就是一个全新的方法;

结论:只有非private方法才可以被覆盖,所以在子类中,对于父类中的private方法,最好采用不同的名字。

public class PrivateOverride {
	private void f() {
		print("private f()");
	}

	public static void main(String[] args) {
		PrivateOverride po = new Derived();
		po.f();
	}
}

class Derived extends PrivateOverride {
	public void f() {
		print("public f()");
	}
}
/* Output:
private f()
*///:~

3. 构造器和多态:

复杂对象调用构造器要遵循下面的顺序:

1) 调用父类构造器(如有多层,则会不断递归下去)

2) 按声明顺序调用成员的初始化方法

3) 调用子类构造器的主体

class Meal {
	Meal() {
		print("Meal()");
	}
}

class Bread {
	Bread() {
		print("Bread()");
	}
}

class Cheese {
	Cheese() {
		print("Cheese()");
	}
}

class Lettuce {
	Lettuce() {
		print("Lettuce()");
	}
}

class Lunch extends Meal {
	Lunch() {
		print("Lunch()");
	}
}

class PortableLunch extends Lunch {
	PortableLunch() {
		print("PortableLunch()");
	}
}

public class Sandwich extends PortableLunch {
	private Bread bread = new Bread();

	private Cheese cheese = new Cheese();

	private Lettuce lettuce = new Lettuce();

	public Sandwich() {
		print("Sandwich()");
	}

	public static void main(String[] args) {
		new Sandwich();
	}
}
/* Output:
Meal()
Lunch()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()

4. 编写构造器时,应尽可能简单地使对象进入正常状态,如果可以的话,避免调用其它方法。

下面的例子我们会发现radius的值为0,为什么?

一个动态绑定的方法调用会深入到继承层次结构内部,它可以调用子类的方法,然而此时方法所操纵的成员还没有进行初始化。

class Glyph {
	void draw() {
		print("Glyph.draw()");
	}

	Glyph() {
		print("Glyph() before draw()");
		this.draw();
		print("Glyph() after draw()");
	}
}

class RoundGlyph extends Glyph {
	private int radius = 1;

	RoundGlyph(int r) {
		radius = r;
		print("RoundGlyph.RoundGlyph(), radius = " + radius);
	}

	void draw() {
		print("RoundGlyph.draw(), radius = " + radius);
	}
}

public class PolyConstructors {
	public static void main(String[] args) {
		new RoundGlyph(5);
	}
}
/* Output:
Glyph() before draw()
RoundGlyph.draw(), radius = 0
Glyph() after draw()
RoundGlyph.RoundGlyph(), radius = 5
*///:~

之所以调用的是子类的draw方法,this的含义是谁调用我,this指向的就是谁,Glyph构造器是通过RoundGlyph类构造器中super()方法触发,所以this指向的是RoundGlyph中的draw方法

5. "向上转型"与"向下转型"

向上转型:List list = new ArrayList(); list.add("xxx") 此时调用的其实是ArrayList的方法

注意:向上转型之后,无法访问子类中的新加的方法

向下转型:其实就是强转,前提是我们知道它是某一种类型,否则运行时会报ClassCastException

时间: 2024-10-12 10:16:19

Think in Java(五):多态的相关文章

Java中多态的一些简单理解

什么是多态 1.面向对象的三大特性:封装.继承.多态.从一定角度来看,封装和继承几乎都是为多态而准备的.这是我们最后一个概念,也是最重要的知识点. 2.多态的定义:指允许不同类的对象对同一消息做出响应.即同一消息可以根据发送对象的不同而采用多种不同的行为方式.(发送消息就是函数调用) 3.实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法. 4.多态的作用:消除类型之间的耦合关系. 5.现实中,关于多态的例子不

个人对Java中多态的一些简单理解

什么是多态 面向对象的三大特性:封装.继承.多态.从一定角度来看,封装和继承几乎都是为多态而准备的.这是我们最后一个概念,也是最重要的知识点. 多态的定义:指允许不同类的对象对同一消息做出响应.即同一消息可以根据发送对象的不同而采用多种不同的行为方式.(发送消息就是函数调用) 实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法. 多态的作用:消除类型之间的耦合关系. 现实中,关于多态的例子不胜枚举. 下面是多态

JAVA泛型多态

先度娘一下多态的概念: 多态==晚绑定. 不要把函数重载理解为多态. 因为多态是一种运行期的行为,不是编译期的行为. 多态:父类型的引用可以指向子类型的对象. 比如 Parent p = new Child(); 当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误: 如果有,再去调用子类的该同名方法. (来源:http://www.cnblogs.com/mengdd/archive/2012/12/25/2832288.html) 那如果要在Java中泛型做多态如何使用

从虚拟机指令执行的角度分析JAVA中多态的实现原理

从虚拟机指令执行的角度分析JAVA中多态的实现原理 前几天突然被一个"家伙"问了几个问题,其中一个是:JAVA中的多态的实现原理是什么? 我一想,这肯定不是从语法的角度来阐释多态吧,隐隐约约地记得是与Class文件格式中的方法表有关,但是不知道虚拟机在执行的时候,是如何选择正确的方法来执行的了.so,趁着周末,把压箱底的<深入理解Java虚拟机>拿出来,重新看了下第6.7.8章中的内容,梳理一下:从我们用开发工具(Intellij 或者Eclipse)写的 .java 源程

Java:多态乃幸福本源

01 多态是什么 在我刻板的印象里,西游记里的那段孙悟空和二郎神的精彩对战就能很好的解释“多态”这个词:一个孙悟空,能七十二变:一个二郎神,也能七十二变:他们都可以变成不同的形态,但只需要悄悄地喊一声“变”. Java的多态是什么呢?其实就是一种能力——同一个行为具有不同的表现形式:换句话说就是,执行一段代码,Java在运行时能根据对象的不同产生不同的结果.和孙悟空和二郎神都只需要喊一声“变”,然后就变了,并且每次变得还不一样:一个道理. 多态的前提条件有三个: 子类继承父类 子类覆盖父类的方法

Java编程思想(五) —— 多态(上)

上一章,Java编程思想(四) -- 复用类里面讲到了向上转型,感觉和多态放在一起写更好. 多态,polymorphism.一个重要的特性,篇幅太长了,分上下两篇写. (1)向上转型 class TV{ public static void show(TV tv){ System.out.println("TV"); } } public class LeTV extends TV{ public static void main(String[] args) { LeTV letv

Java编程思想(五) —— 多态(下)

多态(上)基本讲解了很多多态的特性和问题.下面继续. 1)构造器和多态 这个问题其实前面写过了,构造器实际上是static方法,只不过是隐式声明,所以构造器并没有多态性. 但是需要知道加载的顺序. class GrandFather{ GrandFather(){ print(); } private int print(){ System.out.println("g"); return 1; } } class Father extends GrandFather{ Father(

巩固java(五)----通过实例理解java多态

package duotai; class A{ public String show(){ return "A"; } } class B extends A{ public String show(){ return "B"; } public String onlyB(){ return "onlyB"; } } class C extends B{ public String show(){ return "C"; }

Java(多态)动手动脑

1> 请看以下"变态"的类(参看示例ParentChildTest.java) 上述代码的特点是: 子类和父类定义了一模一样的字段和方法 运行以下测试代码 1. 上边的程序运行结果是什么? 2. 你如何解释会得到这样的输出? 第一个100:是parent调用PrintValue方法输出parent类中myValue值为100: 第二个200:是child调用PrintValue方法输出child类中myValue值为200: 第三个200:是parent = child,将子类对