JavaSE基础知识(十八)--Java多态之向上转型(多态的"缺陷")

Java SE 是什么,包括哪些内容(十八)?

本文内容参考自Java8标准
再次感谢Java编程思想对本文的启发!

缺陷一:无法"覆盖"私有方法

如果我们试图像下面这样做也是无可厚非的:

// 试图"覆盖"私有方法
   //类PrivateOverride
   public class PrivateOverride{
      //私有方法f()
      private void f(){
         //打印字符串"private f()"
        System.out.println("private f()");
      }
      //程序执行入口main方法
      public static void main(String[] args) {
         //创建类Derived的对象,赋值给类PrivateOverride的引用po
         PrivateOverride po = new Derived();
         //调用方法f()
         po.f();
      }
   }
   //类Derived继承类PrivateOverride
   class Derived extends PrivateOverride{
      //方法f()
      public void f(){
         //打印字符串"public f()"
         System.out.println("public f()");
      }
   }

按照多态的一贯思路,我们所期望的输出是public f(),但是由于private方法被自动认为是final方法,同时对子类也是屏蔽、不可见的。因此,在这种情况下,Derived类中的方法f()就是一个全新的方法;既然父类中的方法f()在子类Derived中不可见,所以不能被重载(也可以说是不能被重新实现)。
**结论:**只有非private方法才可以被覆盖,但是还是需要密切关注"覆盖"private方法的现象,虽然编译器不会对此报错,但是也不会按照我们期望的结果来执行,确切的说:在子类中,对于父类中的private方法,最好采用不同的名字。

缺陷二:域与静态方法

一旦你了解了多态机制,可能就会开始认为所有事物都可以多态地发生,然而,只有普通的方法调用是多态的。例如,你可以直接访问某个域,这个访问就将在编译器进行解析,就像下面的示例所演示的:
代码示例:

// 访问域
   //父类Super
   class Super{
      //int类型的类变量(域)field,初始化值为0
      public int field = 0;
      //方法getField()
      public int getField(){
         //返回类变量field
         return field;
      }
   }
   //类Sub继承类Super
   class Sub extends Super{
      //int类型的类变量(域)field,初始化值为1
      public int field = 1;
      //方法getField()
      public int getField(){
         //返回类变量field
         return field;
      }
      //方法getSuperField()
      public int getSuperField(){
         //返回父类变量field
         //在继承关系中,在子类中都是通过关键字super
         //类明确调用父类的组成部分(域,方法等)
         return Super.field;
      }
   }
   //类FieldAccess
   public class FieldAccess{
      //程序执行入口main方法
      public static void main(String[] args) {
         //创建子类Sub的对象赋值给父类的引用sup
         //这里会自动发生向上转型
         Super sup = new Sub();
         //打印字符串"sup.field = "+sup.field+",sup.getField() =
         //"+sup.getField()
         System.out.println("sup.field = "+sup.field+",sup.getField() =
         "+sup.getField());
         //创建子类Sub的对象,赋值给子类的引用sub
         Sub sub = new Sub();
         //打印字符串"sub.field = "+sub.field+",sub.getField() =
         //"+sup.getField()+",sub.getSuperField()="+sub.getSuperField()
         System.out.println("sub.field = "+sub.field+",sub.getField() =
         "+sup.getField()+",sub.getSuperField()="+sub.getSuperField());
      }
   }

结果示例:
结果示例
当Sub对象转型为Super引用时,任何域访问操作都将由编译器解析,因此不是多态的(如果域访问也是多态的,那么第一条打印语句中sup.field的值应该是1,而不是父类的0,但是方法是多态的,所以第二条打印语句sup.getField()值为1)。
在上面的例子中,为Super.field和Sub.field分配了不同的存储空间,这样,子类Sub中实际上包含了两个称为field的域:它自己的和它从父类Super得到的。然而,在引用Sub中的field时所产生的默认域并非Super版本的field域,因此,为了得到Super.field(也就是为了得到父类中的field,必须通过关键字super),必须显式地指明super.field。
尽管上面的示例代码看起来好像会成为一个容易令人混淆的问题,但是在实践中,它实际上从来不会发生。主要基于以下两点:
⑴、通常会将所有的域都设置成private,因此不能直接访问。之多通过set/get方法来访问。
⑵、你可能不会选择对父类中的域和子类中的域赋予相同的名字。因为这种做法本身就容易令人产生混淆。
如果某个方法是静态的(也就是有static关键字修饰的),它就不具有多态性
代码示例:

// 静态方法不具有多态性
   class StaticSuper{
      public static String staticGet(){
         return "Base statcGet()";
      }
      public String dynamicGet(){
         return "Base dynamicGet()";
      }
   }
   class StaticSub extends StaticSuper{
      public static String staticGet(){
         return "Derived statcGet()";
      }
      public String dynamicGet(){
         return "Derived dynamicGet()";
      }
   }
   public class StaticPolymorphism{
      //程序执行入口main方法
      public static void main(String[] args) {
          StaticSuper sup = new StaticSub();
          System.out.println(sup.staticGet());
          System.out.println(sup.dynamicGet());
      }
   }

结果示例:
结果示例
你需要明确知道的是:静态方法是与类,而并非与单个对象相关联的。
PS:时间有限,有关Java SE的内容会持续更新!今天就先写这么多,如果有疑问或者有兴趣,可以加QQ:2649160693,并注明CSDN,我会就博文中有疑义的问题做出解答。同时希望博文中不正确的地方各位加以指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值