代码之家  ›  专栏  ›  技术社区  ›  Steve B.

最终Java分配规则

  •  2
  • Steve B.  · 技术社区  · 14 年前

    我在最后变量的赋值中遇到了一些奇怪的行为。您可以在构造函数中指定一个最终变量来初始化它,这是有意义的。但是,即使最终变量是子类的成员,也不能在子类中执行相同的操作。-

    public class FinalTest {
        public final String name;
    
        public FinalTest()
        {
            name = "FinalTest";
        }
    
        public static class FinalTestSubclass extends FinalTest {
            public FinalTestSubclass()
            {
                name = "FinalTestSubclass"; //<---- this won't compile, assignment to final variable.
            }
        }
    }
    

    有人能想出一个很好的理由,为什么这样做会奏效吗?

    5 回复  |  直到 14 年前
        1
  •  11
  •   erickson    14 年前

    子类的每个构造函数必须调用超类的构造函数作为其第一个操作。在构造函数完成之前,必须初始化每个最终成员变量。最后一个变量只能分配一次。根据这些规则,子类构造函数不可能直接将值赋给 final 超类成员。

    例外会增加复杂性并创建“gotchas”,以换取有限的额外效用。

    一个实际的解决方案是提供一个超类构造函数,它接受一个值分配给最终成员。这可以 protected 如果需要,也可以打包为私有。如果超类超出了您的控制范围,那么允许派生类打破其成员最终性的假设很可能会导致其他问题。

        2
  •  6
  •   matt b    14 年前

    如果允许您将值赋给 name 在里面 FinalTestSubClass 这意味着 FinalTest 不是最终值。

    如果您的示例是有效的,那么这意味着 名称 可能具有不同的值(基于实例化的类),使 final 修饰符相当多余。

    一个更好的问题是,为什么 应该 你希望被允许的行为?

        3
  •  3
  •   irreputable    14 年前

    非正式地,最终字段应该在构造函数完成时初始化。

    在子类构造函数中,super()已被隐式调用,父类的构造函数已完成,不应修改父类中的最后字段。

    您可能需要这样做:

    class A
        final String s;
        A(String s){ this.s = s; }
        A() { this("default"); }
    
    class B extends A
        B(){ super("B's default"); }
    
        4
  •  1
  •   Damian Leszczyński - Vash    14 年前

    这是Java中的标准行为。

    关键字final可以通过多种方式使用,对于类关闭从中继承的可能性,对于方法重写它,对于变量只允许在简单的单词中分配一次。

    对于您的案例,这个变量已经在超级类中分配好了,

    你能做的就是

    public class FinalTest {
        public final String  name = "FinalTest";
    
        public FinalTest()
        {
    
        }
    
        public static class FinalTestSubclass extends FinalTest {
    
            public final String  name = "FinalTestSubclass";
    
            public FinalTestSubclass()
            {
    
            }
        }
    }
    

    Read more about final variables

        5
  •  0
  •   rsp    14 年前

    作为对Matt答案的回应,您可以通过在构造函数中传递常量来确定子类中的常量:

    public class FinalTest {
        public final String name;
    
        public FinalTest()
        {
            this("FinalTest");
        }
    
        protected FinalTest(String nameConstant)
        {
            name = nameConstant;
        }
    
        public static class FinalTestSubclass extends FinalTest {
            public FinalTestSubclass()
            {
                super("FinalTestSubclass");
            }
        }
    }