`
m635674608
  • 浏览: 5080769 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Java中多态变量的讨论和总结

 
阅读更多
一、多态的表现形式

多态的表现形式有方法重载,方法改写,多态变量和泛型。重载是一种静态的多态性,在程序编译时确定被调用的方法,称为早绑定。而多态变量和改写相结合之后,方法的调用在运行时才能确定,是动态的多态性,称为晚绑定。

二、里氏替换原则(The Liskov Principle of Substitution)

在静态类型语言中,在父类和子类之间的关系存在下面的现象:

子类的实例必须拥有父类的所有数据成员;
子类的实例必须至少通过继承(如果不是显示地改写)实现父类所定义的所有功能;
这样,在某种条件下,如果用子类实例来替换父类实例,那么将会发现子类实例可以完全模拟父类的行为,二者毫无差别;
替换原则是指如果有A和B两个类,类B是类A的子类,那么在任何情况下都可以用类B来替换类A,而外界则毫无察觉。

不是所有继承产生的子类都符合替换原则,符合替换原则的子类称为子类型。

三、静态类型和动态类型

在静态类型面向对象语言中,一个变量所存储的值的类型并不等同于这个变量所声明的类型。声明为父类类型的变量可以包含子类的实例值。

静态类型是指变量在声明时所确定的类型,并且一经声明就不会改变;动态类型是指这个变量实际存储的值的类型。在静态类型的面向对象程序设计语言中,在编译时消息传递表达式的合法性不是基于接收器的动态类型,而是基于接收器的静态类型。而对象对消息的响应取决于对象的动态类型。(就是说:写代码的时候“点”不出该对象动态类型包含而静态类型不包含的变量、方法;动态类型就是程序运行过程中被重新赋值为对其他对象的引用,这时候他就可以含有动态类型对象的方法了。)

这样的变量在多态中称为多态变量。

考虑下面的类图:




对应的程序如下:

class SuperClass {      public int x;      public void f1() {      }      public void f2() {      }}class SubClass extends SuperClass{      public int y;      public void f1() {      }      public void f3() {      }}public class Test{      public static void main(String[] args){        SuperClass ob=new SuperClass(); //(1)        ob=new SubClass();  //(2)        ob.x=1;  //(3)        ob.y=2;  //(4)        ob.f1(); //(5)        ob.f2(); //(6)        ob.f3(); //(7)      }}
程序中,子类改写了父类中的f1()方法,添加了自己的属性y和方法f3()。语句(1)中变量ob的静态类型是SuperClass,动态类型是SuperClass;语句(2)中变量ob的静态类型不变,动态类型是SubClass(子类类型),子类对象的地址可以存放在父类类型的引用变量中,即父类引用变量引用子类对象;(3)、(5)、(6)是正确的,(4)、(7)是错误的,因为对于引用的合法性依赖于变量的静态类型,属性y和方法f3()在SuperClass中不存在,故有错,还应该注意参数的匹配;(5)调用的f1()是子类的f1(),(6)调用的f2()是父类的f2(),这是因为对于消息的响应取决于变量的动态类型,因此f1()是SubClass中的f1()。
如果在父类和子类中存在属性的覆盖,则通过ob(父类对象名)访问的x是父类中被覆盖的属性。

class SuperClass {      public int x=1;      public void f1() {      }      public void f2() {      }}class SubClass extends SuperClass{    public int x=2;      public int y;      public void f1() {      }      public void f3() {      }}class Test{      public static void main(String[] args){        SuperClass ob=new SuperClass(); //(1)        ob=new SubClass();  //(2)      System.out.println(ob.x);        ob.f1(); //(5)        ob.f2(); //(6)      }}显示结果为:1
四、父类对象和子类对象

子类从父类继承了所有的属性和方法,因此作用在父类上的方法应用在子类对象上也是合法的。由于继承表达的是一种is a关系,即子类对象可以被视为父类的一个对象,因此可以把子类对象的引用赋给父类对象;反之,父类对象不一定是其某个特定子类的对象,因此不一定满足is a关系,因此不能把父类对象的引用直接赋给子类对象。

class Employee {   private String name;   private int salary;      Employee(String name,int salary){         this.name=name;         this.salary=salary;   }       public String getDetails() {         return Name: " + name + "\nSalary: " + salary;   }}   class Manager extends Employee {   String department;      Manager(String name,int salary,String department){         super(name,salary);         this.department=department;   }       public String getDetails() {          return super.getDetails() + "\nDepartment: " + department;   }}   public class Test{   public static void main(String args[]){         Employee a=new Employee("Mike",800);         Manager b=new Manager("Tom",1200,"Research");         Manager c=a; //Error         Employee d=b; //True         System.out.println(A.getDetails());          System.out.println(D.getDetails());   }}
根据消息传递的概念,对消息的响应取决于接收器。而这又依赖于接收器的动态类型。因此,当父类对象中存放了子类对象的引用,并且父类和子类中有方法覆盖时,通过父类对象将会调用子类中的方法。

同时,在编译时消息传递表达式的合法性不是基于接收器的动态类型,而是基于接收器的静态类型。因此,当父类对象中存放了子类对象的引用时,不能通过父类对象名引用子类中新定义的成员(包括属性和方法)。例如,下面的语句是错误的:

System.out.println(d.department);

可以通过强制类型转换把父类对象转换成子类对象,然后再进行访问:

Manager e=(Manager) d;
System.out.println(e.department);

五、运行时类型识别和向下造型

替换原则将数据的类型从子类提升到了父类。有时也需要做相反的事情,例如判断父类对象所存放的值是否是某个子类的对象。

类型的强制类型转换只能用于子类唯一这种确定的情况下,如果子类不止一个,则可能发生错误,可以通过instanceof运算符来识别子类对象所属的类。

public class Manager extends Employee
public class Contractor extends Employee

假设有一个子类对象,可以通过下面的语句来判断它所述的类并执行相应的操作:

if(a instanceof Manager){
Manager b=(Manager) a;
......
}
else if(a instance of Contractor){
Contractor b=(Contractor) a;
......
}

例如在上面的操作中,可以把a这个父类对象转换成相应的子类对象,从而去访问子类中新增的属性或方法,这称为向下造型(down casting)。造型(cast)也就是通常所说的类型转换。类型的提升称为向上造型(up casting)。

六、多态和抽象类、抽象方法

抽象类不能实例化,但是可以声明抽象类的变量用以存放其子类对象的引用。另外,抽象方法为其子类规定了一个必须实现的接口,这样在多个子类中就拥有一个相同的接口方法。

在程序中可以定义一个父类的数组用于保存所有子类的对象,从而保持程序的简洁和灵活性。下面的程序说明了这个问题。


abstract class Shape{    public abstract void draw();}class Circle extends Shape{    private int x;    private int y;    private int radius;    public Circle(int x,int y,int radius){        this.x=x;        this.y=y;        this.radius=radius;    }    public void draw() {        System.out.println("draw circle: ("+x+","+y+"),radius="+radius);    }}class Line extends Shape{      private int x1,y1,x2,y2;      public Line(int x1,int y1,int x2,int y2){        this.x1=x1;        this.x2=x2;        this.y1=y1;        this.y2=y2;      }      public void draw(){        System.out.println("draw line,("+x1+","+y1+")-("+x2+","+y2+")");      }}public class TestShape{      public static void main(String[] args){        Shape[] s=new Shape[4];        s[0]=new Circle(1,1,10);        s[1]=new Line(3,4,20,12);        s[2]=new Circle(3,10,20);        for(int i=0;i<s.length;i++){          if(s[i]!=null)            s[i].draw();        }      }}
如果没有多态这个特性或者不利用多态这个特性,则程序将复杂得多。

Java中所有的类的最终根类是java.lang.Object,因此可以Object类型的引用变量可以存放所有Java对象的引用,也使用一个Object数组保存Java中所有的对象。


















分享到:
评论

相关推荐

    深入Java核心 Java中多态的实现机制编程资料

    ### 深入Java核心:Java中...通过以上讨论,我们可以看到Java中的多态机制是如何工作的,以及它是如何提高代码的复用性和灵活性的。多态是Java面向对象编程的核心概念之一,掌握好它对于编写高质量的Java程序至关重要。

    Java——多态与接口.rar

    接口在Java中是一个完全抽象的类,只包含常量和抽象方法,不包含任何实例变量。接口是用来定义行为规范的,它允许不同的类实现相同的接口,从而实现多态性。一个类可以实现一个或多个接口,通过关键字`implements`来...

    java 继承和多态的讲解

    Java中的继承和多态是面向对象编程的重要概念,它们为代码的复用、扩展和维护提供了便利。在Java中,类的继承允许一个类(子类)从另一个类(父类)继承属性和方法,从而实现代码的共享和结构的层次化。这使得子类...

    java编程中的继承和多态PPT

    总结一下,Java编程中的继承和多态是面向对象设计的重要概念。继承允许代码重用,减少重复,并使类层次结构更加清晰。多态则提供了代码的可扩展性和可维护性,使得程序能够处理不同类型的对象,而无需了解它们的具体...

    黑马程序员 - Java基础教学 - 08 - 面向对象(4)-多态.doc

    在本文中,我们将讨论Java语言中的一种重要概念 —— 多态(Polymorphism)。多态是面向对象编程(OOP)中的一个核心概念,它允许我们编写更加灵活和可扩展的代码。 一、多态的体现 多态的体现是指父类的引用指向...

    JAVA中类的多态的理解.pdf

    根据提供的文件内容,我们可以了解Java多态主要涉及以下几个方面: 1. 方法重载(Overloading)与方法重写(Overriding): 在Java中,可以在同一个类中或不同的类中定义相同名称的方法,这称为方法重载。但多态性...

    JAVA自测自己编写,充分了解封装继承多态,适用于初学JAVA编程

    在本资源中,我们将探讨 JAVA 编程语言的基本概念和技术,涵盖了封装、继承、多态等重要知识点。通过实践编程题和多选题,我们将深入了解 JAVA 编程语言的核心内容。 封装 封装是 JAVA 编程语言中的一种基本概念,...

    Java相关知识的学习(关键字)(多态)

    Java编程语言中,`final`关键字是一个非常重要的概念,它具有三个主要的使用场景:修饰类、修饰变量和修饰方法。 12.1 修饰类:当`final`关键字用于修饰一个类时,这意味着该类不能被其他类继承。这在设计不可变类...

    毕向东多态0803

    在Java中,成员变量(包括实例变量和静态变量)在多态中的表现遵循“静态绑定”(早期绑定),即在编译阶段就已经确定了调用哪个类的成员变量。因此,无论通过父类还是子类的引用访问这些变量,都将得到与引用类型...

    Java教学大纲总结

    * Java Applet 中对图形、图像和声音资源的基本用法 * Applet 下的动画和声音的加载 ### 第八章 Java 高级特性 * Java 异常处理机制:异常的种类、层次关系、如何抛出异常和捕捉异常 * Java 多线程编程方法 * 输入...

    corejava高级特性总结.pdf

    从给定的文件信息来看,主要讨论了Java的高级特性,包括多态、关键字static以及其在类中的应用。下面将详细阐述这些知识点。 ### 多态 多态是面向对象编程的重要特性之一,允许子类重写父类的方法,从而实现同名...

    java 中继承和多态详细介绍

    总结来说,Java中的继承提供了代码复用和类的层次结构,多态则增强了程序的灵活性和可扩展性。通过理解并熟练运用这些概念,开发者能够编写出更加高效、易于维护的代码。感谢阅读,希望本文能帮助你深入理解Java中的...

    最新Java面试八股文10万字总结

    其次,深入篇讨论了面向对象编程的三大特性:封装、继承和多态。封装涉及访问修饰符,继承则要理解子类与父类的关系,以及方法覆盖和向上转型。多态性是Java强大的特性之一,包括方法重载和方法重写。此外,接口和...

    类和对象、对象和封装、继承、多态、异常等教学...

    在"第一章 类和对象.pdf"中,会详细介绍如何声明和创建类,包括类的构造器、成员变量和方法。 - **对象**:对象是类的实例,它们是程序运行时的实际参与者。对象通过调用类的方法来执行操作。 2. **对象和封装**:...

    Java基础总结.pdf

    在Windows系统中,配置环境变量一般包括设置JAVA_HOME为JDK的安装目录,CLASSPATH包括相关的jar包路径和当前路径".",PATH则添加JDK bin目录和jre bin目录。这样配置后,便可以使用命令行工具来编译和运行Java程序...

    Java学习笔记&工作经验总结.rar

    这可能是学员在学习过程中对所学知识的个人理解和总结,包含了一些实践经验和项目案例。通过这些笔记,读者可以了解到实际开发中的问题和解决方案,以及如何将理论知识应用到实际项目中,这对于提高实践能力非常有...

    Java版精华帖java讨论

    - 学习Java的基础部分,如变量、数据类型、运算符、控制结构(if、for、while)、类与对象、封装、继承、多态等。 - 掌握Eclipse或IntelliJ IDEA等IDE的使用,了解如何创建项目、编写代码、调试程序。 - 学习Java...

    JAVA 面向对象程序设计第3章 继承与多态.pptx

    面向对象编程是Java的核心特性,本章主要讨论了三个关键概念:包、继承和多态。这都是理解和编写复杂Java程序的基础。 首先,我们来看包(Package)的概念。包是Java提供的一种组织类的方式,类似于文件系统中的...

    11_Java面向对象_第3天(接口、多态)_讲义

    总结来说,Java中的接口提供了规范,使得不同类可以共享相同的行为,而多态则允许我们使用同一接口调用不同类的方法,增强了代码的复用性和可扩展性。在实际开发中,熟练掌握接口和多态的运用是成为优秀Java开发者的...

    JavaSE之多态体系

    1.1.1-1.4和1.1.1-1.5部分讨论了多态中成员方法的使用特点。成员方法的访问遵循“编译看左边,运行看右边”的原则,即编译时检查对象的引用类型,运行时根据实际对象的类型调用对应的方法。例如: ```java obj....

Global site tag (gtag.js) - Google Analytics