文档章节

java基础---->多态性

小强斋太
 小强斋太
发布于 2016/11/09 20:07
字数 1458
阅读 1
收藏 0

多态性 

在面向对象中多态性实际上是面向对象里的一个最大的最有用的特点,对于多态性在java中有两种体现:

   1、  方法的重载及覆写

   2、  对象多态性:指的是父类对象和子类对象之间的转型操作

一、对象多态性:

继承允许将对象视为它本身或者它的父类的类型来处理,即将继承自同一父类的基类可以视为同一类处理,一份代码就可以毫无差别的运行在这些不同类型上。多态方法调用允许一种类型表现出与其他相似类型之间的区别,只要它们是从同一基类导出的。虽然这些方法都通过基类调用。

实现原理:后期绑定:在运行时根据对象的类型进行绑定。后期绑定也称为多态绑定或者运行时绑定。

Java中除了static方法和final方法(private方法属于final方法),其他的方法都是后期绑定。

只有普通方法调用时多态的。

对象多态性的例子

基类,形状类 Shape.java

public class Shape {
  public void draw() {}
  public void erase() {}
}

子类1,圆形 Circle.java

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

子类2,三角形 Triangle.java

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

子类3,正方形 Square.java

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

多态性体现

public class Shapes {

	public static void main(String[] args) {
		Shape shape1 = new Circle();
		Shape shape2 = new Triangle();
		Shape shape3 = new Square();

		shape1.draw();
		shape2.draw();
		shape3.draw();
	}
} 
/* Output:
Circle.draw()
Triangle.draw()
Square.draw()
*/

二、多态性理解:

 2.1只有非私有方法才可以被覆盖

“覆盖”私有方法:

class PrivateOverride {

    private void f() {

       System.out.println("privatef()");

    }

}

 

public class Derived extends PrivateOverride {

 

    public void f() {

       System.out.println("publicf()");

    }

 

    public static void main(String[] args) {

       PrivateOverride po = new Derived();

       po.f();//异常The method f() from the type PrivateOverride is not visible

    }

 

}


例子2:覆盖私有方法的现象,编译器不报错,但是不会按照我们期望的执行。

public class PrivateOverride {

    private void f() {

       System.out.println("private f()");

    }

 

    public static void main(String[] args) {

       PrivateOverride po = new Derived();

       po.f();

    }

}

 

class Derived extends PrivateOverride {

    public void f() {

       System.out.println("public f()");

    }

}

/*

 * Output: private f()

 */

2.2、父类和子类有相同的属性,且为public的情况疑问

只有普通方法的调用时多态的,如果访问某一个成员变量,该成员变量是public的,且父类子类都有这个属性,它的访问是在编译期进行解析。

虽然发生向上转型,Super sup = new Sub();sup.field就没有多态性,访问的是父类的field。

class Super {
	public int field = 0;

	public int getField() {
		return field;
	}
}

class Sub extends Super {
	public int field = 1;

	public int getField() {
		return field;
	}

	public int getSuperField() {
		return super.field;
	}
}

public class FieldAccess {
	public static void main(String[] args) {
		Super sup = new Sub(); // Upcast
		System.out.println("sup.field = " + sup.field + ", sup.getField() = "
				+ sup.getField());
		Sub sub = new Sub();
		System.out.println("sub.field = " + sub.field + ", sub.getField() = "
				+ sub.getField() + ", sub.getSuperField() = "
				+ sub.getSuperField());
	}
} 
/* Output:
sup.field = 0, sup.getField() = 1
sub.field = 1, sub.getField() = 1, sub.getSuperField() = 0
*/

2.3静态方法不具有多态性

如果某一个方法是静态的,它的行为就不具有多态性。

class StaticSuper {
	public static String staticGet() {
		return "Base staticGet()";
	}

	public String dynamicGet() {
		return "Base dynamicGet()";
	}
}

class StaticSub extends StaticSuper {
	public static String staticGet() {
		return "Derived staticGet()";
	}

	public String dynamicGet() {
		return "Derived dynamicGet()";
	}
}

public class StaticPolymorphism {
	public static void main(String[] args) {
		StaticSuper sup = new StaticSub(); // Upcast
		System.out.println(sup.staticGet());//静态方法,调用子类的
		System.out.println(sup.dynamicGet());//非静态方法
	}
}
/*
 * Output: Base staticGet() Derived dynamicGet()
 */

三、构造器内部调用的方法被子类覆盖的情况

构造器内部调用的方法被子类覆盖了。这个调用的效果很难预料,因为被覆盖的方法在对象被完全构造之前就会调用。这一定会造成一些难以发现的错误。

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

	Glyph() {
		System.out.println("Glyph() before draw()");
		draw();
		System.out.println("Glyph() after draw()");
	}
}

class RoundGlyph extends Glyph {
	private int radius = 1;

	RoundGlyph(int r) {
		radius = r;
		System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
	}

	void draw() {
		System.out.println("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
*/

输出结果显示当Glyph的构造器调用draw()方法时候,radius不是默认初始值1而是0。

仔细分析这段代码,可以发现

1.在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的零。

2.如前所述那样调用基类构造器,此时,调用被覆盖后的draw()方法(注意,要在调用RoundGlyph构造器之前调用),由于步骤1的缘故,我们此时会发现radius的值为0

3.按照声明的顺序调用成员的初始化方法。

4调用导出类的构造器主体

这样有一个优点,至少保证所有的东西初始化为零或者null,而不仅仅是垃圾。其中通过‘组合’而嵌入到一个类内部的对象引用,其值是null,如果忘记为该值进行初始化,均会在运行时候出现异常。查看结果时候,发现其他所有的东西都是0.

结论:编写构造器的准则

用尽可能简单的方法使对象进入正常状态,可以的话,避免调用其他的方法。构造器内唯一能够安全调用的方法是基类中的final方法(也适用于private,它们自动属于final方法),这些方法不能被覆盖,因此也不会出现上述令人惊讶的问题。

四、向上转型

发生向上转型后,子类中自己的定义的操作是无法通过父类对象找到的。

class Useful {
	public void f() {}
	public void g() {}
}

class MoreUseful extends Useful {

	public void f() {}
	public void g() {}
	public void u() {}
	public void v() {}
	public void w() {}

}

public class RTTI {
	public static void main(String[] args) {
		Useful[] x = { new Useful(), new MoreUseful() };
		x[0].f();
		x[1].g();
//		x[1].u();// 编译错误 The method u() is undefined for the type Useful
		((MoreUseful) x[1]).u(); // 
		((MoreUseful) x[0]).u(); // 必须现有upCast才能有downCast,错误的向下转型,java.lang.ClassCastException
	}

}

本文转载自:http://www.cnblogs.com/xqzt/archive/2012/07/26/5637290.html

共有 人打赏支持
小强斋太
粉丝 0
博文 181
码字总数 0
作品 0
广州
私信 提问
「JAVA基础」面向对象的特征有哪些方面

老师为大家整理JAVA基础:面向对象的特征有哪些方面 面向对象的特征主要有以下几个方面: 1)抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关...

启示录是真的
06/01
0
0
java新手学习,学到迷茫了……

我刚刚学了C++的基本语法,学到了继承派生、多态性虚函数那里,然后要是继续学的话,该学什么内容啊???到这里开始迷茫了。 因为觉得java和C++蛮像的,也比较实用,所以想同时对比着学习j...

螭离得心.
2012/08/30
992
12
小谈Java Enum的多态性

Enum+多态,我没说错,不过Enum是不可以被继承的,也不可以继承自别人,只是能实现接口而已,何谈多态? 不过还是先看看“现象”吧: Java代码 public enum Fruit { APPLE, PEAR, PEACH, OR...

关西大汉弹琵琶
2015/05/30
0
0
I'm not me? —— 多态的另一个例子

按:我感觉我出了一个还不错的面试题~ 代码如下: SuperClass.java SubClass.java Client.java Client 的几个输出语句的输出结果写在代码注释中了。其中,需要特别注意的是:s.a != s.getA...

Iridium
11/25
0
0
Java编程思想 第1章 对象导论

Bruce Eckel 前辈写的《Java编程思想》把问题探讨得非常深入,非常建议同行都学习一下。学习 Java 语言时,老师告诉你 What,自己练习知道 How ,Bruce Eckel 告诉你Why 。 之前已经把后面的...

木云凌
2016/02/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Eos如何删除钱包

在使用Eos的keosd钱包软件时,如果要删除EOS中指定名称的钱包,最简单的办法是直接删除钱包文件,不过在删除钱包之前,需要先停止钱包软件的运行。 学习EOS应用开发要选这个:【EOS智能合约与...

geek12345
1分钟前
0
0
js操作时间

获取当前时间 function getSystemDate(){ var systemDate = new Date(); // 获取当年 var year = systemDate.getFullYear(); // 获取当月 (月+1是因为js中......

简心
8分钟前
0
0
区块链开发教程推荐

区块链的重要性已经毋庸置疑,但对大多数跃跃欲试的开发者而言,去中心化思想、非对称加密、共识算法等技术点的理解和运用,都是入门区块链开发的挑战。合适的区块链开发教程可以极大地缩短区...

笔阁
8分钟前
0
0
菜单menuView总结

1、FTPopOverMenu

_____1____
19分钟前
1
0
MyEclipse教程:Web开发——部署和测试Web项目

MyEclipse 在线订购年终抄底促销!火爆开抢>> MyEclipse最新版下载 本教程向用户展示了使用关联的Web项目创建Web片段项目的机制。用户还可以获得要检查的示例项目。在本教程中,用户将学习如...

电池盒
35分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部