欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

这是一篇关于如何正确理解Java转型机制的文章

程序员文章站 2024-03-01 18:32:40
...

这是一篇关于如何正确理解Java转型机制的文章

谨以此文纪念明天要默单词我还在复习Java谁让他明天考Java呢

什么是转型

就是转型啊还能怎么说!子类转父类,父类转子类巴拉巴拉。父类转子类需要注意

这里边有什么不好理解呢,主要有这几点:

  • 假如说子类重写了父类的一个函数,那么不管子类转父类或者父类转子类,转完了之后调用该函数,那么执行的是父类的函数还是子类的呢?
  • 到底谁可以转成谁?还是说可以随意互相转?(当然不是)
  • 强制类型转换是什么?

本文将以如下两个类进行讲解,第一个是父类Person,只有一个方法WhatAreYou:

class People
{
    public People() {
        // TODO Auto-generated constructor stub
        System.out.println("Father");
    }
    public void WhatAreYou()
    {
        System.out.println("我是一个人类");
    }
}

第一个子类,男人,继承了父类People的WhatAreYou,同时有自己独特的方法Hunt:

class Men extends People
{
    public Men() {
        // TODO Auto-generated constructor stub
        System.out.println("Men");
    }


    public void Hunt() {    
        //男人独有的打猎技能
        System.out.println("Men hunting");
    }

    public void WhatAreYou()
    {
        System.out.println("I am A Man");
    }
}

第二个子类,女人,继承了父类People的WhatAreYou,同时有自己独特的方法Breed(哺育小孩):

class Women extends People
{
    public Women() {
        // TODO Auto-generated constructor stub
        System.out.println("Women");
    }

    public void WhatAreYou()
    {
        System.out.println("I am a Woman");
    }

    public void Breed()
    {   
        //女人才能哺育小孩
        System.out.println("Women Breeding child");
    }
}

子类转父类

先来看一段代码:

public static void main(String[] args)
    {
        People people = new Men();
        people.WhatAreYou();
        people = new Women();
        people.WhatAreYou();
    }

输出结果是:

这是一篇关于如何正确理解Java转型机制的文章

第一行输出Father是父类构造函数,都是先执行父类构造函数后执行子类构造,可以显示调用父类构造函数(关键字Super) 第二行是子类Men的构造函数的输出。

高潮来了:

people是People型引用,但是给他一个Men的对象后,调用其WhatAreYou函数就是调用了子类的函数。

下一行的给people赋值Women也是一样道理。

父类转子类

这能行么…看下边这个代码(只截图了)

这是一篇关于如何正确理解Java转型机制的文章

把父类转到子类直接报错

来看看编译器给出的解决方案:

  • 第一种是把Men men = new People()改为Men men = (Men)new People()

    来看看这样改会怎么样:

    这是一篇关于如何正确理解Java转型机制的文章

    哦编译确实是不报错,但是运行阶段抛出异常

    也就是说,父类不能转换为子类.

    但是这也是有例外的,如果父类引用本就是由子类转化而来,那么他可以转为子类。看如下一段代码:

public static void main(String[] args)
    {
        People people = new Men();
        Men men = (Men)people;
        men.WhatAreYou();
    }

这段代码很皮地将子类转为父类,由转回子类。那么会不会报错呢?看运行:

这是一篇关于如何正确理解Java转型机制的文章

完美运行。

这里其实涉及到能不能强制转换的问题。比如一个Integer对象,就不能转换为一个string对象,谁让他不是string的子类呢?

java提供了用于判断能不能完成强制转型的关键字:instanceof,用法如下:

if ( A instanceof ClassB )
{ ClassB b = (ClassB)A ;}

总结

经过试验,得出结论:子类无压力转父类,父类转子类有条件,那就是该父类对象本就是由子类转的。

或许是这样:

子类转父类实际上是用一个父类型的引用指向子类型的对象,而父类型的引用这个东西,是专门为了服务父类的对象而产生的,可以说其中放了一个表,表项一个是父类中的变量和函数,另一个就是其指向的实体对象中相应的变量和函数。由于子类是父类的扩展,所以子类中一定有父类中有的变量和函数,所以该父类引用的表可以填满,正常使用;而反过来说,子类型的引用的表中有一些是父类所没有的,表项无法填满,故而出错。而父类转子类的那个特殊情况,可能是JVM给对象打了一个tag。

大体如下图所示:

这是向上转型:

这是一篇关于如何正确理解Java转型机制的文章

父类转子类:

这是一篇关于如何正确理解Java转型机制的文章

实体对象中有函数没有被表项指向无所谓,大不了不用这个函数;(实际也就是这么干的)

但是如果表项中有项目没有目标是不行的,表项中的东西是登记了给人用的,项目没有目标用个锤子?

引用中存放表项的方法是我为了简化理解想出来的,实际可能与此不用,建议读者查阅介绍JVM的书籍自行理解

!!!!!有一句话要记住,函数表是根据引用的类型调用的,但是实际运行的是实体对象的函数体

标了!!!!!的那句话极其重要

标了!!!!!的那句话极其重要

或者皮一点,儿子都想当老子,你让他当老子他屁颠屁颠就去了;(向上转型)

老子不想当儿子,除非他原来就是儿子,破格当了一会儿老子,现在要把他变回儿子,就要强制转成儿子(向下转型,只能强制转换,而且有条件)