Java多态的使用注意事项

 更新时间:2013年11月14日 14:38:11   作者:  
本文讲解了什么是JAVA多态和Java多态是如何实现的,在使用Java多态时需要注意什么,具体大家看下面的内容

Java多态是如何实现的?
Java的多态和C++一样,是通过延时绑定(late binding)或者说运行时绑定(runtime binding)来实现的。当调用某一个对象引用的方法时,因为编译器并不知道这个引用到底指向的是变量声明时说明的类型对象,还是该类型子类的对象。因此编译器无法为这次调用绑定到具体的某个方法。只有通过java中的运行时类型识别(RTTI, Runtime type identification)在运行时绑定到具体的方法。下面是一个具体的例子:

复制代码 代码如下:

class shape
{
    public void draw()
    {

   print("shape");
    }
}
class triangle extends shape
{
    public void draw()
    {

   print("triangle");
    }
}
public class Polymorphism {
public static void main(String[] args)
{
    shape s=new triangle();
    s.draw();
}


结果是triangle
s是一个shape引用,但是在运行时因为是triangle对象,所以还是调用了triangle的draw方法。

Java多态中的一些陷阱

重写私有方法?
Java里面是不能重写私有方法的,这个其实很好理解,因为私有方法在子类是不可见的。子类没有继承父类的私有方法,更谈不上重写了。因此在子类中的同名方法是一个全新的方法。

复制代码 代码如下:

public class Polymorphism {
    private void show()
    {

   print("show parent");
    }
public static void main(String[] args)
{
    Polymorphism p=new privateMethod();
    p.show();
}
}
class privateMethod extends Polymorphism
{
    public void show()
    {

   print("show derived");
    }
}


结果是 show parent

字段和静态方法的多态?
子类可以继承父类的非私有字段,子类的字段是否也具有多态性呢?我们来看一个实际的例子:

复制代码 代码如下:

class shape
{
    protected int perimeter=1;
    public void draw()
    {

   print("shape");
    }
    public int getPerimeter()
    {

   return perimeter;
    }
}
class triangle extends shape
{

int perimeter=3;
    public void draw()
    {

   print("triangle");
    }
    public int getPerimeter()
    {

   return perimeter;
    }
    public int getSuperPerimeter()
    {

   return super.perimeter;
    }
}
public class Polymorphism {

public static void main(String[] args)
{
    shape s=new triangle();
    print("s.perimeter:"+s.perimeter);
    print("s.getperimeter:"+s.getPerimeter());
    triangle t=new triangle();
    print("t.perimeter:"+t.perimeter);
    print("t.getperimeter:"+t.getPerimeter());
    print("t.getsuperperimeter:"+t.getSuperPerimeter());
}
}


以下是运行结果:

这个运行结果包含了以下信息:
1.triangle对象向上转型成shape后字段直接访问都是由编译器确定的,因此不会表现出多态性,返回的是1。
2.triangle对象向上转型成shape后调用方法访问字段是根据运行时对象类型延时绑定调用了triangle的getperimeter方法,返回的是3
3.t对象中包含了两个perimeter字段,一个来自于他本身,一个来自于他的父类。同时用字段名去调用该字段时默认返回的是他本身的perimeter字段,要调用从父类继承的该字段,要用super.perimeter的方法。
这个结果看起来多多少少让人有些疑惑,为了避免这种情况出现,我们一般都把字段声明为private(子类就无法继承),同时我们在子类中声明的字段最好不要与从父类继承的字段同名。
静态方法是没有多态性的,因为静态方法是和类绑定的,不会存在不知道具体类型的情况。

构造函数的多态性?
构造函数是不具有多态性的,因为构造方法本身是静态方法(如果不是的话,就会陷入鸡生蛋,蛋生鸡的死循环了)。要引入我们的问题,先来看一下构造函数的调用顺序。
1.为这个对象分配的存储空间都被初始化为0(对象初始化为null)
2.父类的构造函数调用(这样才能保证在子类的构造函数中访问的字段被初始化)
3.成员变量初始化
4.子类的构造函数调用

现在假设如果在第二步中,我们在父类的构造函数里调用了某个方法,这个方法是不是多态的?还是来看一个具体的例子:

复制代码 代码如下:

class shape
{
    protected int perimeter=1;
    public shape()
    {

   draw();

   print("shape created");
    }
    public void draw()
    {

   print("draw shape "+perimeter);
    }

}
class triangle extends shape
{

int perimeter=3;

public triangle()

{

    print("triangle created");

}
    public void draw()
    {

   print("draw triangle "+perimeter);
    }
    public int getPerimeter()
    {

   return perimeter;
    }
}

public class Polymorphism {

public static void main(String[] args)
{
    shape s=new triangle();
}
}


运行结果:

 

我们可以看到虽然triangle对象还没有构造完毕,draw方法仍是动态绑定到了triangle的draw方法。同时注意到perimeter的值还没有初始化为3,而是0。

这样的结果就是我们在triangle对象还没有被初始化之前就访问了其中的字段。因此我们在实际应用中要避免在构造函数中调用其他方法,或者只调用私有方法(不会被继承,因此不会引发该问题)

相关文章

  • springboot框架的全局异常处理方案详解

    springboot框架的全局异常处理方案详解

    这篇文章主要介绍了springboot框架的全局异常处理方案,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • java动态构建数据库复杂查询教程

    java动态构建数据库复杂查询教程

    这篇文章主要介绍了java动态构建数据库复杂查询的实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2021-11-11
  • springboot集成nacos的配置方法

    springboot集成nacos的配置方法

    这篇文章主要介绍了springboot集成nacos的配置方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • Java面向对象之继承的概念详解

    Java面向对象之继承的概念详解

    这篇文章主要介绍了Java面向对象之继承的概念详解,Java是一种面向对象的编程语言,继承是实现面向对象编程的基础之一。通过继承,我们可以使代码更具可读性、可重用性和可维护性,从而提高程序的效率和可靠性,需要的朋友可以参考下
    2023-04-04
  • java swing实现电影购票系统

    java swing实现电影购票系统

    这篇文章主要为大家详细介绍了java swing实现电影购票系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • 官方详解HDFS Balancer工具主要调优参数

    官方详解HDFS Balancer工具主要调优参数

    这篇文章主要为大家介绍了HDFS Balancer工具主要调优参数的 官方详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • 如何使用Java操作Zookeeper

    如何使用Java操作Zookeeper

    这篇文章主要介绍了如何使用Java操作Zookeeper,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下
    2021-04-04
  • Java案例使用比较排序器comparator实现成绩排序

    Java案例使用比较排序器comparator实现成绩排序

    这篇文章主要介绍了Java案例使用比较排序器comparator实现成绩排序,主要通过案例用TreeSet集合存储多个学生信息,并遍历该集合,要按照总分从高到低进行排序,下文介绍需要的朋友可以参考一下
    2022-04-04
  • Java枚举学习之定义和基本特性详解

    Java枚举学习之定义和基本特性详解

    枚举是JAVA 5.0后增加的一个重要类型。可以用来表示一组取值范围固定的变量。本文将通过示例为大家详细讲解枚举的定义和基本特性,感兴趣的可以了解一下
    2022-08-08
  • 解决Spring Security 用户帐号已被锁定问题

    解决Spring Security 用户帐号已被锁定问题

    这篇文章主要介绍了解决Spring Security 用户帐号已被锁定问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01

最新评论