资讯专栏INFORMATION COLUMN

关于 static final method 的疑惑

jindong / 320人阅读

摘要:所以,本身在父类中声明为的方法,在子类中确实不可以,并且子类会隐藏掉父类中的这个方法,让自己的这个方法和父类的那个同名方法变成两个无关联的普通方法。

前言

在声明一个方法为 static final 时,IDEA 给出了一个 warning:

When a static method is overriden in a subclass it can still be accessed via the superclass making the final declaration not very necessary. Declaring a static method final does prevent subclasses from defining a static method with the same signature.

翻译过来大概是:将一个 static 方法声明为 final 不是非常必要的,因为即使声明为 final,这个 static 方法在子类中被 override 后,仍然可以通过父类访问这个方法。不过被声明为 final 确实可以阻止子类定义一个相同签名的 static 方法。

看来看去我还是觉得很奇怪,可能是因为英语的表达和我中文的思维不太一样?...

反正 static 真是 Java 的一个很让人迷惑的 feature =.=

还是要好好弄懂它。

static final 方法

首先,对于 static 方法,我们知道它是属于类的,而非对象,可以认为 static 方法是没有 this 隐式参数的,因此可以使用类名直接调用 static 方法,通常,在一些工具类中将方法声明为 static 使用起来会比较方便。

当然,通过对象也可以调用 static 方法,但是并不推荐这么做,因为通常一个方法被声明为 static 有两种原因:1. 这个方法不需要访问对象的状态 2. 这个方法只需要访问类的 static 域,所以如果是因为第一个原因声明的 static 方法,再用对象调用它时,容易造成混淆,因为这个对象可能和这个 static 方法毫无关系。

还有一点就是,static 方法是不能被 override 的

class SuperClass {
    public static void staticMethod() {
        System.out.println("static method in super class");
    }
}

class SubClass extends SuperClass {
    public static void staticMethod() {
        System.out.println("static method in sub class");
    }

    public static void main(String[] args) {
        staticMethod();
    }
}

这时会发现可以成功的调用 staticMethod(),并且输出: static method in sub class,说明调用的是子类中这个方法,那么为什么说 static 方法是不能被 override 的呢?

看下面的改动:

class SubClass extends SuperClass {
    @Override
    public static void staticMethod() {
        System.out.println("static method in sub class");
    }

    public static void main(String[] args) {
        staticMethod();
    }
}

当我们加上 @Override 注释时就会发现编译时就报错了:SubClass.java:2: 错误: 方法不会覆盖或实现超类型的方法,这就说明在子类中的这个 staticMethod 实际上不是对父类方法的 override,而是一个普普通通的子类中的方法,仅此而已。

为什么不能 override static 方法呢?我是这样理解的,因为 static 是和类关联的,所以无关对象状态,而 override 是多态的表现,多态是针对对象而言的,因此 static 方法是不能被 override 的。

这也给我们提了个醒,想要覆盖父类方法时最好加上 @Override 注释,因为它会帮助我们鉴别是否真的 override 了父类的方法~

下面,如果我们为这个方法加上 final 呢?

class SuperClass {
    public static final void staticMethod() {
        System.out.println("static method in super class");
    }
}

class SubClass extends SuperClass {
    //@Override
    public static void staticMethod() {
        System.out.println("static method in sub class");
    }

    public static void main(String[] args) {
        staticMethod();
    }
}

这时,即使注释掉 @Override,编译也会报错,错误信息是:SubClass 中的 staticMethod() 无法覆盖 SuperClass 中的 staticMethod(),从这里就可以说明 IDEA 给出的那个 warning 的下半句了

Declaring a static method final does prevent subclasses from defining a static method with the same signature.

被声明为 final 的 static 方法的确可以阻止子类定义一个相同签名的 static 方法。

在 Stack OverFlow 有一个类似的问题

Behaviour of final static method

作者的疑问是,本来 static 方法就是不能被 override 的,为什么在父类中加了 final 修饰符之后编译器还会报错。

高票的解释是

Static methods cannot be overridden but they can be hidden. The ts() method of B is not overriding(not subject to polymorphism) the ts() of A but it will hide it. If you call ts() in B (NOT A.ts() or B.ts() ... just ts()), the one of B will be called and not A. Since this is not subjected to polymorphism, the call ts() in A will never be redirected to the one in B.

The keyword final will disable the method from being hidden. So they cannot be hidden and an attempt to do so will result in a compiler error.

大概意思是: static 方法不能被 override 但是可以被 hide,子类中的 static 方法不是在 override 而是在隐藏,也就是说,如果在子类中直接调用该静态方法(不是通过类调用),那么调用的一定是子类自己的那个方法,而不是父类中的,因为子类把父类那个隐藏起来了。而 final 会阻止隐藏,所以在子类中父类的 static 方法 被隐藏 就和 final 的 阻止隐藏 冲突了,因此编译就会报错。

所以,本身在父类中声明为 static 的方法,在子类中确实不可以 override,并且子类会隐藏掉父类中的这个 static 方法,让自己的这个方法和父类的那个同名方法变成两个无关联的普通方法。如果在父类中的这个 static 方法加上了 final,那么子类中就不可以定义重名的方法了,因为子类的隐藏和 final 的阻止隐藏会发生冲突。

so,我觉得将父类的 static 方法声明为 final 还是有作用的,至少不会让子类定义一个让人迷惑的重名方法了嘛,所以最后还是取消了这个 warning 啦。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69714.html

相关文章

  • javap命令与Java Dcompiler工具、IDEA自带反编译器反编译结果差别及原因

    摘要:反汇编器与反编译器不同,反编译器的目标是高级语言而非汇编语言。反汇编器的反汇编输出通常格式化为适合人类阅读,而非用作汇编器的输入源,因此它主要是一个逆向工程工具。本文章参考了通过命令分析汇编指令反汇编器 问题描述 写这篇文章是为了记录我这几天遇到的一个疑惑,并且顺藤摸瓜的学习一下javap命令。遇到的疑惑是这样的:我在看使用枚举类型实现单列模式的博客时,发现一些博客中写到的枚举类型的反...

    张宪坤 评论0 收藏0
  • java修饰符使用指南

    摘要:应用在修饰类名,类成员,方法,参数,构造器中。接口修饰符构造器修饰符方法修饰符字段修饰符参数修饰符最基本的修饰符作用在类上当此修饰符修饰类。作用在构造器上在构造器上,只允许使用三种修饰符,。当此修饰符修饰构造器。 1、什么是修饰符? 指的是一种标识类型以及类型成员的访问范围的声明。 应用在修饰类名,类成员,方法,参数,构造器中。 2、修饰符的有几种? ...

    elva 评论0 收藏0
  • 【java并发编程实战6】AQS之独占锁ReentrantLock实现

    摘要:锁与很好的隔离使用者与实现者所需要关注的领域。那么这个就是包装线程并且放入到队列的过程实现的方法。也证实了就是获取锁的线程的节点。如果发生异常取消请求,也就是将当前节点重队列中移除。 前言 自从JDK1.5后,jdk新增一个并发工具包java.util.concurrent,提供了一系列的并发工具类。而今天我们需要学习的是java.util.concurrent.lock也就是它下面的...

    sixleaves 评论0 收藏0
  • Spring源码一(容器基本实现3)

    摘要:前言继续前一章,接下来解析标签的的属性信息及的注册。不过只不过是一个子类的实现,而大部分属性都是保存到了中去了。也就是函数中的代码的解析了。通过注册对于的注册,或许很多人认为的方式就是将直接放入中就好了,使用作为。 前言:继续前一章,接下来解析Bean标签的的属性信息及bean的注册。 1. 解析当前bean标签的内容 当我们创建了bean信息的承载实例之后, 便可以进行bean信息的...

    qylost 评论0 收藏0
  • 几行代码实现RPC框架

    摘要:前言昨天看了一篇关于用几行代码实现框架的博客,收获很大,于是我想在这篇博客的基础上理一理思路,尽可能的多加一点注释,进一步降低学习框架原理的门槛。 前言 昨天看了一篇关于用几行代码实现RPC框架的博客[http://javatar.iteye.com/blog...](),收获很大,于是我想在这篇博客的基础上理一理思路,尽可能的多加一点注释,进一步降低学习RPC框架原理的门槛。 原理图...

    Caicloud 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<