面向的对象编程的小猫腻

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

  • 追本溯源

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

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 构造方法。

    

 

posted @ 2017-03-28 00:00  天目山电鳗  阅读(195)  评论(0编辑  收藏  举报