【问题标题】:Unexpected Behavior wrt the final modifier最终修饰符的意外行为
【发布时间】:2011-10-15 08:49:14
【问题描述】:

这是我的代码

package alpha ;

class A1
{
    static class A11
    {
        private
            final // WHAT IS THE EFFECT OF THIS MODIFIER?
            void fun ( String caller )
            {
                System . out . println ( "A11:\t" + caller ) ;
            }
    }

    static class A12 extends A11
    {
        private void fun ( String caller )
        {
            super . fun ( caller + caller ) ;
        }
    }

    public static void main ( String [ ] args )
    {
        A12 a12 = new A12 ( ) ;
        a12 . fun ( "Hello" ) ;
    }
}

我发现无论有没有 A1.A11 中的最终 mdifer,程序都能编译并运行。

我可以理解,如果没有 final 修饰符,A1.A12 可以看到并因此覆盖 fun 方法。它是私有的,但它们属于同一类,因此不存在可见性问题。

我不明白为什么它与 final 修饰符一起工作。不应该禁止 A1.A12 中的覆盖吗?

这是带有最终修饰符的程序的输出

java alpha/A1
A11:    HelloHello

如果只是忽略其他有趣的方法,那么

  1. 编译器不会抱怨超级引用
  2. A11 不会在输出中

【问题讨论】:

  • 你确定吗?也许你的编译器表现得很奇怪。 final 使变量不可修改并防止子类化。不确定它如何影响方法。
  • @Ryan 它可以防止覆盖。
  • @Etienne 好的,这就是我的想法……但是 OP 很奇怪。您使用的是哪个 IDE 和哪个 JDK?
  • @Ryan 我没有使用 IDE。我正在使用 javac 1.6.0_20

标签: java private final modifiers


【解决方案1】:

对于publicprotected 和包私有/默认访问方法,final 确实可以防止方法被覆盖。

但是,所有private 方法都是“非虚拟的”,因此实际上是最终的。超类中的private 方法对派生类没有影响。你没有覆盖,只是基类中的方法被忽略了。

JVM 所基于的第一版 Java 语言规范没有内部或嵌套类,因此可以特别处理 private 方法。该语言的更高版本围绕 JVM。

在字节码方面,private 方法是用invokespecial 而不是invokevirtual 调用的。

不同包中的默认访问/包私有final方法也是相互独立的。在同一个包中可以相互覆盖,final 会有所作为。在不同的包中,匹配的方法不会相互覆盖。

【讨论】:

    【解决方案2】:

    您的方法是私有的

    将它们的可见性更改为受保护以查看预期的行为,即只有当方法受到保护时,公共或默认可见性,甚至存在覆盖的概念

    做这样的事情--

    class A1
    {
        static class A11
        {
            public
                final // WHAT IS THE EFFECT OF THIS MODIFIER?
                void fun ( String caller )
                {
                    System . out . println ( "A11:\t" + caller ) ;
                }
        }
    
        static class A12 extends A11
        {
            public void fun ( String caller )
            {
                super . fun ( caller + caller ) ;
            }
        }
    
        public static void main ( String [ ] args )
        {
            A12 a12 = new A12 ( ) ;
            a12 . fun ( "Hello" ) ;
        }
    }
    

    现在将抛出编译时异常

    fun(java.lang.String) in A1.A12 cannot override fun(java.lang.String) in A1.A11; overridden method is final
    

    【讨论】:

    • “包私有”方法也可以覆盖同一包中的类。这与同一外部类中的private 方法的情况类似。 Java 的行为确实很奇怪。
    • 我接受私有方法不存在覆盖的概念。嵌套在同一个顶级类中的类的私有方法彼此可见。因此子类方法可以看到超类方法(通过super)。看起来好像有覆盖但没有。
    • @Kai。 “彼此可见” = A11 中的私有方法可以在 A12 中调用。它们不仅在同一个文件中,而且在同一个类中。这是我的理解。
    • @emory -- 你是对的。我将把你链接到关于这个主题的另一个关于 SO 的讨论。stackoverflow.com/questions/663059/…
    • @Kai Thnx 4 链接。这确实是一种奇怪的行为,但我认为这是合法的,并且是规范所要求的。
    猜你喜欢
    • 1970-01-01
    • 2012-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    • 1970-01-01
    相关资源
    最近更新 更多