• 面向的对象编程的小猫腻


        首先纪念一下这是第五十篇博客了,也不知道朕的草庐有多少人会光顾,就当做是写给自己看看自己这些年来做的事吧。之前写的博客大多是算法相关的或者是开源框架相关的,大体来说不是笔记就是解题答案,并不能算是“博客”吧。今天从一道面试题里面,探究一下面向对象会坑人的一些地方。

    • 追本溯源

        一天,笔者来到一家公司,丢给我一份笔试,看了一眼,有道题十分特别。

    public class ClassA{
        public ClassA(){
              method();            
        }
        public void method(){
              System.out.println("in class A");
        }          
    }
    
    public class ClassB extends ClassA{public void method(){
               System.out.println("in class B");
        }
       public static void main(String[] args){
           new ClassB();
      } }

        问最后会输出什么?

        笔者思考了一下,好像被触碰到了知识的禁区......我随便一想,构造函数好像不会继承吧,然后就写了不输出。

        回来自己写了一段代码,输出了重写方法的内容……瞬间觉得自己是不是基础被人击穿了……

        后来查了资料了解到,新建子类对象首先会新建父类对象,新建父类对象的时候调用构造方法,里面调用了被重写的method,所以输出了“in class B”。

    • 山穷水复

        浅尝辄止是人类的共性,工程师是反人类特性的征服者,学习Java的人肯定听过自动转型这个东西吧,新建子类对象的时候引用父类对象。范式:父类 变量 = new 子类();它和直接引用子类创建对象一样么?有什么区别。

        从输出上看,依然是新建了父类对象之后再新建子类对象。然而,有些父类没有的方法,子类扩展的,调用的子类方法就会编译出错。而且如果子类对象和父类对象的变量命一致,调用的返回的是父类的对象。

        编译出错了,因为在引用为父类的对象中,搜索不到子类的扩展方法,在调用的时候,会调用父类的方法并检查是否被子类重写。

       输出了父类的变量,如果我把引用改成子类 b = new 子类()这样,他就会输出子类的变量,因为变量被继承了,但是如果重新赋值的话,它按照的还是顶级引用搜索变量。

       每一个对象,都会有Class属性,各位觉得,这个引用了父类的变量,Class是指向哪一个类的呢?

        我这样理解,因为他的引用是父类对象,但是新建在堆内存的对象是子类,所以对象的Class应该是和堆内存中的子类对应的。

        依然有变量的强制转型,那类也可以强制转型,我们从数学上理解是这样的,如果A是B的子集,那么A一定能推断出B,那么B可能推断得出A,这样一个逻辑关系。那么对应父类和子类,那么子类是大的一方,父类是小的一方,所以从父类转型到子类是必然成功的,为什么?因为子类可以产生基因突变,而且子类会继承父类的基因。。。这样的歪理可以接受么。子类可以扩展方法,所以从多态性来讲,子类属于大的一方。

    test9 demo = (test9)new test9F();
    test9F demo = (test9F)new test9();

        然而事实上,第一行代码会抛出异常,类型转换异常。为啥?这就算是面向对象的猫腻了吧,我也无法解释,待我寻找一下答案。

        所有的类是不是都继承自Object?那转换成Object为什么会正常。

        笔者并不能找到能完我集合论说法的解释,无疾而终。

    • 蓦然回首

        整天在讨论多态,静态方法有没有多态?

            test9F demo = new test9();
            demo.methodStatic();
            test9 demo = new test9();
            demo.methodStatic();

        上述两段代码,哪个顶级引用就会调用哪个引用的静态方法。第一个引用的是父类,第二个引用的是子类。会划小黄线的原因,就是无论你调用对象还是调用类它的静态方法都是不变的,编译器的规范是类调用。

        而且两个类使用共同名字的静态方法,IDE也没有重写的字样,所以静态方法并不会被重写 so do 构造方法。

        

  • 相关阅读:
    C# 给Word每一页设置不同图片水印 E
    C#/VB.NET 将XML转为PDF E
    Java 替换PDF中的字体 E
    C# 读取txt文件生成Word文档 E
    AVL Tree
    Kafdrop
    Python递归遍历目录并删除文件中的前N行
    canal
    中医考研必背针灸歌诀
    nginx(https)代理问题
  • 原文地址:https://www.cnblogs.com/chentingk/p/6629564.html
Copyright © 2020-2023  润新知