静态方法能否被重写放碟能否是四个小时

今天在梳理梳理知识点的时候无意间看到一个问题:
子类是否可以继承父类的的static方法?
子类是否可以重写父类的静态方法而呈现多态特性?

对象数据共享 ->被static修饰的数据不仅可以被对象访问,还可以被类名访问

  • static是一个修饰符,用于修饰成员,(成员变量,成员函数)
  • static优先于对象存在,因为static的成员随着类的加载就已经存在
  • static修饰的成员多了一种调用方式,可以被类名调用(类名.静态成员)
  • static修饰的数据是共享数据,对象中的存储是特有数据

父类的method静态方法

-打印结果是“父类的静态方法 ”,可以看出子类不可以重写父类的静态方法show(),因此依旧表现出父类方法的行为特征,而没有表现出子类方法的行为特征,因此没有表现出多态性。
2.子类和父类中同名的static变量和方法都是相互独立的,并不存在任何的重写的关系

子类可以继承父类静态属性和静态方法,但是不可以重写父类的静态方法而表现多态性
PS:前提是父类的静态方法对子类是可见的。eg,父类方法不被private休息

}

父类的普通方法可以被继承和重写,不多作解释,如果子类继承父类,而且子类没有重写父类的方法,但是子类会有从父类继承过来的方法。

静态的方法可以被继承,但是不能重写。如果父类中有一个静态的方法,子类也有一个与其方法名,参数类型,参数个数都一样的方法,并且也有static关键字修饰,那么该子类的方法会把原来继承过来的父类的方法隐藏,而不是重写。通俗的讲就是父类的方法和子类的方法是两个没有关系的方法,具体调用哪一个方法是看是哪个对象的引用;这种父子类方法也不在存在多态的性质。《Java编程思想》中这样提到“只有普通的方法调用可以是多态的”。下面代码为例:

上面执行的结果是“M”,也就是是M类型的引用调用的,如果修改main方法中的代码:

那么执行的结果是“N”,也就是N类型的引用调用的。

静态的方法不能覆写,也不能被重写。总之,静态的没有重写!!!

}

几年前你可能会遇到这样一个面试题:“重写和重载的区别”、而现在随着科技的更迭、面试的问题越来越高级、面试官的问题也越来越深入、此文是上述面试题的一个延伸、让你从简单的重写规则中更加深入的理解其软件工程面向对象的思想。

    访问修饰符的限制一定要不小于被重写方法的访问修饰符

重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同。

返回值类型必须完全一致的情况下、才不会出现编译错误(即为该方法为强制重写方法)。如果以上条件中参数列表不同,且返回值类型不同这样编译并不会出现错误(这个方法为在子类的新方法,且不是重写方法)。// 19:44 bluetata 追記标注補足1(下接博文后追記)

    C-1補足2当子类的方法重写或实现父类的方法时, 方法的后置条件(即方法的返回值)要比父类更严格。[参照2]//           即:如果重写方法的参数列表和方法名相同,且其他条件满足的情况下,方法的返回值为父类的子类,那么该方法也为重写方法

// C-1補足2の例を挙げります:
 

    重写方法不能抛出新的异常或者比被重写方法声明的检查异常更广的检查异常。但是可以抛出更少,更有限或者不抛出异常。

    举个简单的例子:父类异常好比父亲偷盗抢掠、那么儿子不能比父亲更坏、要学好、自然异常就要少。虽然举得例子与社会主义核心价值观有冲突、但是比较形象。// 10:55 bluetata 追記 add

这个方法不会被改动(声明一个final方法的主要目的是防止方法的内容被修改)。

   《JAVA编程思想》中多次的提到:方法是静态的、他的行为就不具有多态性。静态方法是与类、而非单个对象相关联的。

   父类的普通方法可以被继承和重写,不多作解释,如果子类继承父类,而且子类没有重写父类的方法,但是子类会有从父类继承过来的方法。静态的方法可以被继承,但是不能重写。如果父类中有一个静态的方法,子类也有一个与其方法名,参数类型,参数个数都一样的方法,并且也有static关键字修饰,那么该子类的方法会把原来继承过来的父类的方法隐藏,而不是重写。通俗的讲就是父类的方法和子类的方法是两个没有关系的方法,具体调用哪一个方法是看是哪个对象的引用;这种父子类方法也不在存在多态的性质。《JAVA编程思想》:只有普通的方法调用可以是多态的,静态方法是与类而不是与某个对象相关联。

   補足1:父类的静态方法不能被子类覆盖为非静态方法

       子类可以定义于父类的静态方法同名的静态方法、以便在子类中隐藏父类的静态方法(满足覆盖约束)、而且Java虚拟机把静态方法和所属的类绑定、而把实例方法和所属的实例绑定。

   補足2父类的非静态方法不能被子类覆盖为静态方法。

   補足3:面试可能会遇到的此处相关问题(与静态相关)

static方法可以被类直接调用(抽象方法需要被实例才能被调用, 这里说的实例是实现的意思,也就是重写后实现其方法), 这样注定了static方法一定有方法体, 不能是没有方法体的抽象方法(被abstract修饰)  // 18:17 bluetata

可以参看上面从java编程思想摘出的话、另外在总结下:覆盖依赖于类的实例,而静态方法和类实例并没有什么关系。而且静态方法在编译时就已经确定,而方法覆盖是在运行时确定的(动态绑定)(也可以说是java多态体现在运行时、而static在编译时、与之相悖)。

不能、构造方法是隐式的static方法、同问题2。其实这个问题回答切入点很多、首先构造方法无返回值、方法名必须和所在类名相同、这一点就必杀了子类无法重写父类构造方法。另外多态方面、重写是多态的一种提现方式、假设在子类重写了构造方法是成立的、那么子类何谈实例成父类。另外重要得一点、子类可以使用super()调用父类的构造方法、且必须放在子类构造方法内的第一行。

还是引用下《JAVA编程思想》:静态方法是与类而不是与某个对象相关联  用static修饰的成员属于类, 非static修饰的成员属于实例对象, 也就是类可以直接调用静态成员, 这样假设如果类直接调用了静态成员, 而静态成员调用了非静态变量或方法, 这样在内存中是找不到该非静态变量方法的, 在这里加载解析阶段都是JVM进行主导,而在初始化阶段才是真正java执行代码的阶段. static成员在初始化阶段之前会被加载到方法区中, 并且进行初始化赋值等操作,并且分配内存, 而非static成员确是在加载后解析后的初始化阶段才会被"加载"分配内存, 也就是代码中使用new进行创建实例的时候, 这样也就验证了 类可以直接调用static成员没有问题, 而直接调用非static的成员就会出问题, 因为违背了java加载初始化的逻辑.

XX01重写规则補足

   補足1:父类的抽象方法可以被子类通过两种途径覆盖(即实现和覆盖)

補足2の例を挙げります:

以上规则更加详细的说明请参看另一篇博文:

举例(来源于OCJP题库):

Explanation:继承关系后,子类重写父类的方法时,修饰符作用域不能小于父类被重写方法,所以A正确,B不正确。选项CEFG均不满足重写规则,不是重写方法(在子类的普通方法)。选项D即为不满足C-1补足。

里氏替换原则(リスコフの置換原則(りすこふのちかんげんそく)、英:Liskov Substitution Principle)

    这项原则最早是在1987年、由麻省理工学院的由芭芭拉·利斯科夫(Barbara Liskov)在一次会议上名为“数据的抽象与层次”的演说中首先提出。

    里氏替换原则的内容可以描述为: “派生类(子类)对象能够替换其基类(超类)对象被使用。” 以上内容并非利斯科夫的原文,而是译自罗伯特·马丁(Robert Martin)对原文的解读。其原文为:

    严格的定义:如果对每一个类型为T1的对象o1、都有类型为T2的对象o2、使得以T1定义的所有程序P在所有的对象o1都换成o2时、程序P的行为没有变化、那么类型T2是类型T1的子类型。

    通俗的定义:所有引用基类的地方必须能透明地使用其子类的对象。

    更通俗的定义:子类可以扩展父类的功能,但不能改变父类原有的功能。

       1、子类可以实现父类的抽象方法、但是不能[1]覆盖父类的非抽象方法。(核心)[参照1]

        在我们做系统设计时、经常会设计接口或抽象类、然后由子类来实现抽象方法、这里使用的其实就是里氏替换原则。子类可以实现父类的抽象方法很好理解、事实上子类也必须完全实现父类的抽象方法、哪怕写一个空方法、否则会编译报错。

        里氏替换原则的关键点在于不能覆盖父类的非抽象方法。父类中凡是已经实现好的方法、实际上是在设定一系列的规范和契约、虽然它不强制要求所有的子类必须遵从这些规范、但是如果子类对这些非抽象方法任意修改、就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。

        [1]处的说明:该处的不建议原则、并不是硬性规定无法不能的含义。增加新功能时、尽量添加新方法实现、而不是(不建议)去重写父类的方法、也不建议重载父类的方法。// 15:33

       3、当子类重写或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。

       4、当子类的方法重写或实现父类的方法时,方法的后置条件(即方法的返回值)要比父类更严格。[参照2]

    里氏替换原则的核心是抽象,抽象又依赖于继承这个特性,在OOP当中,继承的优缺点都相当的明显。

       ①、代码重用,减少创建的成本,每个子类拥有父类的方法和属性。

       ③、提高代码的可扩展性,实现父类的方法就可以了,很多开源框架的扩展接口都是通过继承父类完成的。

       ①、继承是侵入性的,只要继承就必须拥有父类的所有属性和方法。

       ②、可能造成子类代码冗余、灵活性降低,因为子类必须拥有父类的属性和方法。

      ③、增强了耦合性。当父类的常量、变量和方法被修改时,必须考虑子类的修改,而且在缺乏规范的环境下,这种修好可能带来非常
糟糕的结果:大片的代码需要重构。

}

我要回帖

更多关于 静态方法能否被重写 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信