文档章节

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 Enum的多态性

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

关西大汉弹琵琶
2015/05/30
0
0
第二十九节:Java基础知识-类,多态,Object,数组和字符串

前言 基础知识-类,多态,,数组和字符串,回顾,继承,类的多态性,多态,向上转型和向下转型,,数组,多维数组,字符串,字符串比较。 回顾 类的定义格式: 类的修饰符:, ,等。 privat...

达叔小生
08/15
0
0
有一到五年开发经验的JAVA程序员需要掌握的知识与技能!

JAVA是一种平台,也是一种程序设计语言,如何学好程序设计不仅仅适用于JAVA,对C++等其他程序设计语言也一样管用。有编程高手认为,JAVA也好C也好没什么分别,拿来就用。为什么他们能达到如此...

java高级架构牛人
06/02
0
0
作为一个java程序员这些技能你都知道吗?

一、Java特点 1、 面向对象 尽管受到其前辈的影响,但Java没被设计成兼容其他语言源代码的程序。这允许Java开发组自由地从零开始。这样做的一个结果是,Java语言可以更直接、更易用、更实际的...

java高级架构牛人
05/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

移除或自定义 WordPress 仪表盘欢迎面板

第一次登录 WordPress 后台仪表盘页面,默认都会显示 WordPress 的欢迎面板: 如果我们要移除这个面板,在主题的 functions.php 中添加下面的代码即可: 12 //移除 WordPress 仪表盘欢迎面...

james_laughing
22分钟前
0
0
HashMap实现原理及源码分析

HashMap实现原理及源码分析   哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,...

DemonsI
26分钟前
0
0
eggjs学习笔记

快速初始化 生成项目(要求最低的node版本8.x) npm i egg-init -gegg-init egg-example --type=simplecd egg-examplenpm i 启动项目 npm run dev 配置 环境配置会覆盖默认配置 config...

别人说我名字很长
29分钟前
1
0
Winform Timer控件时间间隔

sender as System.Timers.Timer).Interval = 23 * 60 * 60 * 1000.0;//将时间间隔改为23小时,23小时后重新发生timer_Elapsed事件。 //60000:时间间隔1分钟,300000:时间间隔5分钟,600000:...

笑丶笑
29分钟前
0
0
在win10系统下怎样快速切换任务视图

切换窗口:Alt + Tab 任务视图:Win + Tab (松开键盘界面不会消失) 切换任务视图:Win + Ctrl +左/右 创建新的虚拟桌面:Win + Ctrl + D 关闭当前虚拟桌面:Win + Ctrl + F4...

SummerGao
33分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部