java ocp原则中的多态

什么是多态
1.面向对象的三大特性:封装、继承、多态。从一定角度来看,封装和继承几乎都是为多态而准备的。这是我们最后一个概念,也是最重要的知识点。
2.多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
3.实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
4.多态的作用:消除类型之间的耦合关系。
5.现实中,关于多态的例子不胜枚举。
下面是多态存在的三个必要条件,要求大家做梦时都能背出来!
多态存在的三个必要条件
一、要有继承;
二、要有重写;
三、父类引用指向子类对象。
多态的好处:
1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
Java中多态的实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。
1.Java中除了static和final方法外,其他所有的方法都是运行时绑定的。private方法都被隐式指定为final的,因此final的方法不会在运行时绑定。当在派生类中重写基类中static、final、或private方法时,实质上是创建了一个新的方法。
2.在派生类中,对于基类中的private方法,最好采用不同的名字。
3.包含抽象方法的类叫做抽象类。注意定义里面包含这样的意思,只要类中包含一个抽象方法,该类就是抽象类。抽象类在派生中就是作为基类的角色,为不同的子类提供通用的接口。
4.对象清理的顺序和创建的顺序相反,当然前提是自己想手动清理对象,因为大家都知道Java垃圾回收器。
5.在基类的构造方法中小心调用基类中被重写的方法,这里涉及到对象初始化顺序。
6.构造方法是被隐式声明为static方法。
7.用继承表达行为间的差异,用字段表达状态上的变化。
在JAVA中有两种多态是指:运行时多态和编译时多态。
关于类的多态性简介如下:
多态性是面向对象的核心特征之一,类的多态性提供类中成员设计的灵活性和方法执行的多样性.
1、类多态性表现
(1)方法重载
重载表现为同一个类中方法的多态性.一个类生命多个重载方法就是为一种功能提供多种实现.编译时,根据方法实际参数的数据类型\个数和次序,决定究竟应该执行重载方法中的哪一个.
(2)子类重定义从父类继承来的成员
当子类从父类继承来的成员不适合子类时,子类不能删除它们,但可以重定义它们,使弗雷成员适应子类的新需求.子类重定义父类成员,同名成员在父类与子类之间表现出多态性,父类对象引用父类成员,子类对象引用子类成员,不会产生冲突和混乱.
子类可重定义父类的同名成员变量,称子类隐藏父类成员变量.子类也可以重定义父类的同名成员方法,当子类方法的参数列表与父类方法参数列表完全相同时,称为子类方法覆盖(override)父类方法。覆盖父类方法时,子类方法的访问权限不能小于父类方法的权限。
由于Object类的equals()方法比较两个对象的引用是否相等而不是值是否相等,因此一个类要覆盖Object类的equals()方法,提供本类两个对象比较相等方法.
覆盖表现为父类与子类之间方法的多态性.java 寻找执行方法的原则是:从对象所属的类开始,寻找匹配的方法执行,如果当前类中没有匹配的方法,则逐层向上依次在父类或祖先类中寻找匹配方法,直到Object类.
2、super 引用
在子类的成员方法中,可以使用代词super引用父类成员.super引用的语法如下:
super([参数列表]) //在子类的构造方法体中,调用父类的构造方法
super.成员变量 //当子类隐藏父类成员变量时,引用父类同名成员变量
super.成员方法([参数列表]) //当子类覆盖父类成员方法时,调用父类同名成员方法
*注意:super引用没有单独使用的语法
3、多态性有两种:
1)编译时多态性
对于多个同名方法,如果在编译时能够确定执行同名方法中的哪一个,则称为编译时多态性.
2)运行时多态性
如果在编译时不能确定,只能在运行时才能确定执行多个同名方法中的哪一个,则称为运行时多态性
方法覆盖表现出两种多态性,当对象获得本类实例时,为编译时多态性,否则为运行时多态性,例如:
XXXX x1 = new XXXX(参数列表); //对象获得本类实例,对象与其引用的实例类型一致
XXX xx1 = new XXX(参数列表);
x1.toString(); //编译时多态性,执行XXX类的方法.
xx1.toString(); //编译时多态性,执行XXXX类覆盖的方法.
XXXX为XXX的父类.
由于子类对象既是父类对象,父类对象与子类对象之间具有赋值相容性,父类对象能够被赋值为子类对象.例如,
XXXX x2 = new XXX(参数列表); //父类对象获得子类实例,子类对象即是父类对象
x2.toString(); //运行时多态
x2声明为父类对象却获得子类XXX的实例,那么x2.toString()究竟执行父类方法还是执行子类覆盖的方法呢?
这分为两种情况:
取决于子类是否覆盖父类方法.如果子类覆盖父类方法,则执行子类方法;
如果没有覆盖,则执行父类方法.
在编译时,仅仅依据对象所属的类,系统无法确定到底应该执行那个类的方法,只有运行时才能确定,因此这是运行时多态.
父类对象并不能执行所有的子类方法,只能执行那些父类中声明\子类覆盖的子类方法.
在这样一个体系中,多态表现出多种形式的能力。通用多态引用有相同结构类型的大量对象,他们有着共同的特征。特定的多态涉及的是小部分没有相同特征的对象。四种多态可做以下描述:
强制的:一种隐式做类型转换的方法。
  重载的:将一个标志符用作多个意义。
  参数的:为不同类型的参数提供相同的操作。
  包含的:类包含关系的抽象操作。
我将在讲述子类型多态前简单介绍一下这几种多态。
  强制的多态
  强制多态隐式的将参数按某种方法,转换成编译器认为正确的类型以避免错误。在以下的表达式中,编译器必须决定二元运算符‘+’所应做的工作:
  2.0 + 2
  2.0 + "2"
第一个表达式将两个double的操作数相加;Java中特别声明了这种用法。
第二个表达式将double型和int相加。Java中没有明确定义这种运算。不过,编译器隐式的将第二个操作数转换为double型,并作double型的加法。做对程序员来说十分方便,否则将会抛出一个编译错误,或者强制程序员显式的将int转换为double。
第三个表达式将double与一个String相加。Java中同样没有定义这样的操作。所以,编译器将double转换成String类型,并将他们做串联。
强制多态也会发生在方法调用中。假设类Derived继承了类Base,类C有一个方法,原型为m(Base),在下面的代码中,编译器隐式的将 Derived类的对象derived转化为Base类的对象。这种隐式的转换使m(Base)方法使用所有能转换成Base类的所有参数。
C c = new C();
Derived derived = new Derived();
c.m( derived );
并且,隐式的强制转换,可以避免类型转换的麻烦,减少编译错误。当然,编译器仍然会优先验证符合定义的对象类型。
重载的多态
重载允许用相同的运算符或方法,去表示截然不同的意义。‘+’在上面的程序中有两个意思:两个double型的数相加;两个串相连。另外还有整型相加, 长整型,等等。
这些运算符的重载,依赖于编译器根据上下文做出的选择。以往的编译器会把操作数隐式转换为完全符合操作符的类型。虽然Java明确支持重 载,但不支持用户定义的操作符重载。
  Java支持用户定义的函数重载。一个类中可以有相同名字的方法,这些方法可以有不同的意义。这些重载的方法中,必须满足参数数目不同,相同位置上的参数类型不同。
这些不同可以帮助编译器区分不同版本的方法。
 编译器以这种唯一表示的特征来表示不同的方法,比用名字表示更为有效。据此,所有的多态行为都能编译通过。
 强制和重载的多态都被分类为特定的多态,因为这些多态都是在特定的意义上的。这些被划入多态的特性给程序员带来了很大的方便。强制多态排除了麻烦的类型和编译错误。
重载多态像一块糖,允许程序员用相同的名字表示不同的方法,很方便。
参数的多态
   参数多态允许把许多类型抽象成单一的表示。例如,List抽象类中,描述了一组具有同样特征的对象,提供了一个通用的模板。
你可以通过指定一种类型以重 用这个抽象类。这些参数可以是任何用户定义的类型,大量的用户可以使用这个抽象类,因此参数多态毫无疑问的成为最强大的多态。
包含的多态
  包含多态通过值的类型和集合的包含关系实现了多态的行为.在包括Java在内的众多面向对象语言中,包含关系是子类
阅读(...) 评论()本节我们来学习JAVA的继承和多态&-&这是Java中的一个非常重要的概念。如果你想学习Java,必须更好地理解它。
继承和多态&-&这是Java中的一个非常重要的概念。如果你想学习Java,必须更好地理解它。
2-&类,构造函数和实例
需要在开始学习Java之前明确有关类,继承,构造函数和实例理解。&我们考虑一下 Person类,描述了全名,出生年份,生日,逝世日期等信息。
Person.java
package com.yiibai.tutorial.inheritance.
public class Person {
// Field name - name of person
// Field bornYear
private Integer bornY
// Field diedYear.
private Integer diedY
// Constructor with 3 parameters. The aim is to assign value for the field of Person.
// Specify the name, year of birth, died year.
public Person(String name, Integer bornYear, Integer diedYear) {
this.name =
this.bornYear = bornY
this.diedYear = diedY
// Constructor with 2 parameters.
// The aim is to assign value for the field of Person.
// Not assign for diedYear
public Person(String name, Integer bornYear) {
this.name =
this.bornYear = bornY
public String getName() {
public void setName(String name) {
this.name =
public Integer getBornYear() {
return bornY
public void setBornYear(Integer bornYear) {
this.bornYear = bornY
public Integer getDiedYear() {
return diedY
public void setDiedYear(Integer diedYear) {
this.diedYear = diedY
PersonDemo.java
package com.yiibai.tutorial.inheritance.
public class PersonDemo {
public static void main(String[] args) {
// Instance: Thomas Edison.
Person edison = new Person("Thomas Edison", );
System.out.println("Info:");
System.out.println("Name: " + edison.getName());
System.out.println("Born Year: " + edison.getBornYear());
System.out.println("Died Year: " + edison.getDiedYear());
// Instance: Bill Gates
Person billGates = new Person("Bill Gate", 1955);
System.out.println("Info:");
System.out.println("Name: " + billGates.getName());
System.out.println("Born Year: " + billGates.getBornYear());
System.out.println("Died Year: " + billGates.getDiedYear());
区分类,构造函数和实例
Person模拟某一种人的类,这是抽象的东西,但它的信息,在上面的例子中,信息是姓名,出生年份,死亡年份。
构造函数总是与类的名称相同
一个类拥有一个或多个构造函数。
构造函数可带或不带参数,没有参数构造函数是默认调用构造函数。
构造函数是用来创建类的实例。
看下面的例子,创建一个构造函数对象(实例)
3-&Java继承
我们需要几个类的作为练习例子。
Animal:&模拟动物类
Duck:&&动物(Animal)的子类
Cat:&动物(Animal)的子类
Mouse:&&动物(Animal)的子类
在这里,我们有&Animal&类,它没有方法体。
public abstract String getAnimalName();
这种方法是一个抽象方法,在子类中,你需要声明和实现这个方法。
Animal&类如果有一个以上抽象方法,它必须声明为抽象的类。抽象类有构造函数,但不能用它创建的实例。
在本质上意味着如果要创建动物的一个对象,需要从一个特定的动物物种创建,在我们的这个实例中,就必须从猫(Cat),鼠标(Mouse)或鸭(Duck)的构造函数来创建。
Animal.java
package com.yiibai.tutorial.inheritance.
// Class with at least one abstract method must be declared as abstract.
public abstract class Animal {
// Name, for example, Tom Cat, Jerry Mouse.
// Default constructor
public Animal() {
// Assign the default
this.name = this.getAnimalName();
public Animal(String name) {
this.name =
public String getName() {
public void setName(String name) {
this.name =
// Returns the name of this animal.
// An abstract method.
// The specific contents of this method will be written in the subclass.
public abstract String getAnimalName();
接下来看看从Animal继承的Cat类
Cat还具有构造函数,也有自己的字段。在构造函数中的第一行必须调用super(..),这意味着调用父类的构造函数,给父类的字段赋值。
如果你不调用super()&,JAVA在编译时构造函数的第一行会自动插入super()&。
package com.yiibai.tutorial.inheritance.
public class Cat extends Animal {
public Cat(int age, int height) {
// Call the default Constructor of the parent class (Animal)
// Aims initialize the fields in the parent class.
// Next, Assign value to its fields
this.age =
this.height =
public Cat(String name, int age, int height) {
// Call the default Constructor of the parent class (Animal)
// Aims initialize the fields in the parent class.
super(name);
// Next, Assign value to its fields
this.age =
this.height =
public int getAge() {
public void setAge(int age) {
this.age =
public int getHeight() {
public void setHeight(int height) {
this.height =
// Implement content for abstract methods declared in the parent class.
public String getAnimalName() {
return "Cat";
当创建一个Cat对象,会发生什么?
来看看动物的子类Mouse类
Mouse.java
package com.yiibai.tutorial.inheritance.
public class Mouse extends Animal {
// Default constructor
public Mouse() {
// Call to constructor Mouse(int)
this(100);
// Constructor with one parameter.
public Mouse(int weight) {
// If you does not call super(..)
// then java will call to default Constructor of the parent class.
// super()
this.weight =
// Constructor with 2 parameters.
public Mouse(String name, int weight) {
super(name);
this.weight =
public int getWeight() {
public void setWeight(int weight) {
this.weight =
public String getAnimalName() {
return "Mouse";
InstanceofDemo.java
package com.yiibai.tutorial.inheritance.
import com.yiibai.tutorial.inheritance.animal.A
import com.yiibai.tutorial.inheritance.animal.C
import com.yiibai.tutorial.inheritance.animal.M
public class InstanceofDemo {
public static void main(String[] args) {
// Create an Animal object.
// Animal is abstract class
// It can not create the object from its constructors.
Animal tom = new Cat("Tom", 3, 20);
System.out.println("name: " + tom.getName());
System.out.println("animalName: " + tom.getAnimalName());
// Using instanceof operator to
// check if an object is an instance of a specific class.
boolean isMouse = tom instanceof M
System.out.println("Tom is mouse? " + isMouse);
boolean isCat = tom instanceof C
System.out.println("Tom is cat? " + isCat);
boolean isAnimal = tom instanceof A
System.out.println("Tom is animal? " + isAnimal);
运行示例的结果:
animalName: Cat
Tom is mouse? false
Tom is cat? true
Tom is animal? true
InheritMethodDemo.java
package com.yiibai.tutorial.inheritance.
import com.yiibai.tutorial.inheritance.animal.C
public class InheritMethodDemo {
public static void main(String[] args) {
// Create instance of Cat.
Cat tom = newCat("Tom", 3, 20);
// Call the method inherited from the parent class.
System.out.println("name: "+ tom.getName());
System.out.println("animalName: "+ tom.getAnimalName());
System.out.println("-----------------");
// Call the method declared in the class Cat.
System.out.println("Age: "+ tom.getAge());
System.out.println("Height: "+ tom.getHeight());
运行示例的结果:
animalName: Cat
-----------------
Height: 20
Java类转换
CastDemo.java
package com.yiibai.tutorial.inheritance.
import java.util.R
import com.yiibai.tutorial.inheritance.animal.A
import com.yiibai.tutorial.inheritance.animal.C
import com.yiibai.tutorial.inheritance.animal.M
public class CastDemo {
// Method returns a random animal.
public static Animal getRandomAnimal() {
// Returns a random value 0 or 1
int random = new Random().nextInt(2);
Animal animal =
if (random == 0) {
animal = new Cat("Tom", 3, 20);
animal = new Mouse("Jerry", 5);
public static void main(String[] args) {
Animal animal = getRandomAnimal();
if (animal instanceof Cat) {
// Cast to Cat
Cat cat = (Cat)
// And call method of the Cat class.
System.out.println("Cat height: " + cat.getHeight());
} else if (animal instanceof Mouse) {
// Cast to Mouse
Mouse mouse = (Mouse)
// And call method of the Mouse class.
System.out.println("Mouse weight: " + mouse.getWeight());
4-&Java多态
假设你有一只猫Asian&Cat,,你可以作为一只猫或者作为一种动物调用是多态的体现。
或者另外一个例子:你简历的记录是一个亚洲男子,而你实际上是一个中国人。
下面的例子说明了如何声明和现实行为。
AsianCat 是 Cat 类的子类。
AsianCat.java
package com.yiibai.tutorial.inheritance.
public class AsianCat extends Cat {
public AsianCat(String name, int age, int height) {
super(name, age, height);
// Override methods of the parent class (Cat)
public String getAnimalName() {
return "Asian Cat";
Java的多态性如下图所述:
PolymorphismDemo.java
package com.yiibai.tutorial.
import com.yiibai.tutorial.inheritance.animal.AsianC
import com.yiibai.tutorial.inheritance.animal.C
public class PolymorphismDemo {
public static void main(String[] args) {
Cat cat1 = new Cat("Tom", 3, 20);
Cat cat2 = new AsianCat("ATom", 2, 19);
System.out.println("Animal Name of cat1: " + cat1.getAnimalName());
System.out.println("Animal Name of cat2: " + cat2.getAnimalName());
运行示例的结果如下:
Animal Name of cat1: Cat
Animal Name of cat2: Asian Cat
加QQ群啦!
JAVA技术群(2000人群):
MySQL/SQL群(2000人群):
Python技术群(2000人群):
大数据开发群(2000人群): (Java,Python,R,Scala,Hadoop,Spark,zookeeper,kafka等技术)
Web开发群(新群):
(PHP,HTML/HTML5,JS/JQuery,CSS等技术)
Linux技术群(新群): (Redhat/Centos,Ubuntu,Shell,运维,监控等技术)
易百教程移动端:请扫描本页面底部(右侧)二维码关注微信公众号,或直接手机访问:
上一篇:下一篇:多态成员变量的特点:
1 class DuotaiTest2
public static void main(String[] args)
A a = new A();
A b1 = new B();
B b2 = new B();
System.out.println(a.name);
System.out.println(a.a);
<span style="color: #
System.out.println(b1.name);
<span style="color: #
System.out.println(b1.a);//子类向上转型成父类,再调用子类特有成员变量,编译报错
<span style="color: #
System.out.println(((B)b1).name);
<span style="color: #
System.out.println(((B)b1).b);
<span style="color: #
System.out.println(b2.name);
<span style="color: #
System.out.println(b2.b);
<span style="color: #
<span style="color: # }
<span style="color: #
<span style="color: # class A
<span style="color: # {
<span style="color: #
String name = "A";//父子类同名变量
<span style="color: #
int a = 1;//父类特有变量
<span style="color: # }
<span style="color: #
<span style="color: # class B extends A
<span style="color: # {
<span style="color: #
String name = "B";
<span style="color: #
int b = 2;//子类特有变量
<span style="color: # }
<span style="color: #
<span style="color: # /*
<span style="color: # 总结:
<span style="color: #
调用成员变量时, 类变量.成员变量 语句在执行时依据类变量类型进行选择入口
<span style="color: # */
运行结果:
  java中,子类的实例对象在堆内存中的存放应如图所示,既有子类的成员变量,又有父类的成员变量;
  同一对象可以有多态,当父类变量指向时,从A入口进入,可以访问父类的所有成员变量;当子类变量指向时,从B入口进入,可以访问子类的所有成员变量和父类非同名变量;
调用成员变量时, 类变量.成员变量 语句在执行时依据类变量类型进行选择入口多态(非静态)成员函数的特点:  我写了一个“重写”过程的思想本质,那个可以解释多态(非静态)成员函数的特点原理。图解:
  java中,实例对象即使被向上转型成父类,其实其在内存中的存储形式依旧是子类实例对象(转型...有讲),基于这个结论就好解释了
    多态是将子类实例对象向上转型后赋给父类变量,其在内存中依旧是子类实例对象,在通过该变量调用方法时,JVM会通过判断该变量指向的实例对象在内存的形式来确定进入方法区的那块去寻找方法
    因为转型后类型不变,所以JVM还是进入Child的方法区寻找方法,而Child自己定义了show()方法,所以调用了子类的show()
总结:  (非静态)成员函数的访问原则是通过判断调用对象在内存中的形式而进行的,是子类实例则运行子类方法,是父类示例则运行父类方法,与变量类型无关多态静态方法的特点:  
需求:设计一个简单的java程序,确定多态中静态方法的访问特点
思路:设计一对子父类,创建子类实例,子类变量和父类变量同时指向该实例,通过不同变量调用查看结果
DuotaiTest3
public static void main(String[] args)
Child c = new Child();
<span style="color: #
Father f =
<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: # }
<span style="color: #
<span style="color: # class Father
<span style="color: # {
<span style="color: #
static void show(){
<span style="color: #
System.out.println("Father show run.");
<span style="color: #
<span style="color: # }
<span style="color: #
<span style="color: # class Child extends Father
<span style="color: # {
<span style="color: #
static void show(){
<span style="color: #
System.out.println("Child show run.");
<span style="color: #
<span style="color: # }
<span style="color: #
<span style="color: # /*
<span style="color: # 总结:
<span style="color: #
同一个实例对象,不同类型的变量指向,通过不同变量调用会得到不同的结果表明:
<span style="color: #
静态方法调用的判断是依据调用者的变量类型而进行的。
<span style="color: #
类变量.方法 语句中,类变量类型决定着JVM在静态方法区的入口选择
<span style="color: # */
同一个实例对象,不同类型的变量指向,通过不同变量调用会得到不同的结果表明:
静态方法调用的判断是依据调用者的变量类型而进行的。
类变量.方法 语句中,类变量类型决定着JVM在静态方法区的入口选择
阅读(...) 评论()多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:
多态性是对象多种表现形式的体现。
现实中,比如我们按下 F1 键这个动作:
如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。
多态的优点
1. 消除类型之间的耦合关系
2. 可替换性
3. 可扩充性
多态存在的三个必要条件
继承重写父类引用指向子类对象
比如:Parent p = new Child();
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。
以下是一个多态实例的演示,详细说明请看注释:
Test.java 文件代码:
public class Test {
public static void main(String[] args) {
show(new Cat());
show(new Dog());
Animal a = new Cat();
Cat c = (Cat)a;
public static void show(Animal a) {
if (a instanceof Cat) {
Cat c = (Cat)a;
} else if (a instanceof Dog) {
Dog c = (Dog)a;
abstract class Animal {
abstract void eat();
class Cat extends Animal {
public void eat() {
System.out.println(&吃鱼&);
public void work() {
System.out.println(&抓老鼠&);
class Dog extends Animal {
public void eat() {
System.out.println(&吃骨头&);
public void work() {
System.out.println(&看家&);
执行以上程序,输出结果为:
我们将介绍在Java中,当设计类时,被重写的方法的行为怎样影响多态性。
我们已经讨论了方法的重写,也就是子类能够重写父类的方法。
当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。
要想调用父类中被重写的方法,则必须使用关键字super。
Employee.java 文件代码:
public class Employee {
private String name;
private String address;
private int number;
public Employee(String name, String address, int number) {
System.out.println(&Employee 构造函数&);
this.name = name;
this.address = address;
this.number = number;
public void mailCheck() {
System.out.println(&邮寄支票给: & + this.name
+ & & + this.address);
public String toString() {
return name + & & + address + & & + number;
public String getName() {
return name;
public String getAddress() {
return address;
public void setAddress(String newAddress) {
address = newAddress;
public int getNumber() {
return number;
假设下面的类继承Employee类:
Salary.java 文件代码:
public class Salary extends Employee
private double salary;
public Salary(String name, String address, int number, double salary) {
super(name, address, number);
setSalary(salary);
public void mailCheck() {
System.out.println(&Salary 类的 mailCheck 方法 &);
System.out.println(&邮寄支票给:& + getName()
+ & ,工资为:& + salary);
public double getSalary() {
return salary;
public void setSalary(double newSalary) {
if(newSalary &= 0.0) {
salary = newSalary;
public double computePay() {
System.out.println(&计算工资,付给:& + getName());
return salary/52;
现在我们仔细阅读下面的代码,尝试给出它的输出结果:
VirtualDemo.java 文件代码:
public class VirtualDemo {
public static void main(String [] args) {
Salary s = new Salary(&员工 A&, &北京&, 3, 3600.00);
Employee e = new Salary(&员工 B&, &上海&, 2, 2400.00);
System.out.println(&使用 Salary 的引用调用 mailCheck -- &);
s.mailCheck();
System.out.println(&\n使用 Employee 的引用调用 mailCheck--&);
e.mailCheck();
以上实例编译运行结果如下:
Employee 构造函数
Employee 构造函数
使用 Salary 的引用调用 mailCheck --
Salary 类的 mailCheck 方法
邮寄支票给:员工 A ,工资为:3600.0
使用 Employee 的引用调用 mailCheck--
Salary 类的 mailCheck 方法
邮寄支票给:员工 B ,工资为:2400.0
实例中,实例化了两个 Salary 对象:一个使用 Salary 引用 s,另一个使用 Employee 引用 e。
当调用 s.mailCheck() 时,编译器在编译时会在 Salary 类中找到 mailCheck(),执行过程 JVM 就调用 Salary 类的 mailCheck()。
因为 e 是 Employee 的引用,所以调用 e 的 mailCheck() 方法时,编译器会去 Employee 类查找 mailCheck() 方法 。
在编译的时候,编译器使用 Employee 类中的 mailCheck() 方法验证该语句,
但是在运行的时候,Java虚拟机(JVM)调用的是 Salary 类中的 mailCheck() 方法。
以上整个过程被称为虚拟方法调用,该方法被称为虚拟方法。
Java中所有的方法都能以这种方式表现,因此,重写的方法能在运行时调用,不管编译的时候源代码中引用变量是什么数据类型。
多态的实现方式
方式一:重写:
这个内容已经在上一章节详细讲过,就不再阐述,详细可访问:。
方式二:接口
1. 生活中的接口最具代表性的就是插座,例如一个三接头的插头都能接在三孔插座中,因为这个是每个国家都有各自规定的接口规则,有可能到国外就不行,那是因为国外自己定义的接口类型。
2. java中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现。具体可以看
这一章节的内容。
方式三:抽象类和抽象方法
7个月前 (03-29)
记住登录状态
重复输入密码

我要回帖

更多关于 字节流和字符流的区别 的文章

 

随机推荐