2

我试过这个:

class protectedfinal
{
  static abstract class A 
  {
    protected final Object a;
  }

  static class B extends A
  {
    { a = new Integer(42); }
  }

  public static void main (String[] args)
  {
    B b = new B();
  }
}

但我得到了这个错误:

protectedfinal.java:12: error: cannot assign a value to final variable a
    { a = new Integer(42); }
      ^
1 error

如何解决这个问题?

有些人在这里建议使用构造函数,但这仅在某些情况下有效。它适用于大多数对象,但无法从构造函数中引用对象本身。

  static abstract class X
  {
    protected final Object x;
    X (Object x) { this.x = x; }
  }

  static class Y extends X
  {
    Y () { super (new Integer(42)); }
  }

  static class Z extends X
  {
    Z () { super (this); }
  }

这是错误:

protectedfinal.java:28: error: cannot reference this before supertype constructor has been called
    Z () { super (this); }
                  ^

有人可能会争辩说,存储这种引用没有多大意义,因为this已经存在。没错,但这是this在构造函数中使用的任何使用都会出现的一般问题。无法传递this给任何其他对象以将其存储在最终变量中。

  static class Z extends X
  {
    Z () { super (new Any (this)); }
  }

那么如何编写一个抽象类,强制所有子类都有一个最终成员,该成员在子类中初始化?

4

3 回答 3

6

A.a您必须在其构造函数中进行初始化。子类将用于super()将初始化程序传递给A.a.

class protectedfinal {
    static abstract class A {
        protected final Object a;

        protected A(Object a) {
            this.a = a;
        }
    }

    static class B extends A {
        B() {
            super(new Integer(42));
        }
    }

    public static void main (String[] args) {
        B b = new B();
    }
}

在调用超类构造函数之前不能使用this,因为在这个阶段对象没有初始化,甚至Object构造函数此时还没有运行,因此调用任何实例方法都会导致不可预知的结果。

Z在您的情况下,您必须以另一种方式使用类解决循环引用:

Z () { super (new Any (this)); }

使用非最终字段或更改类层次结构。由于同样的原因,您使用实例方法的解决方法super(new Any(a()));将不起作用:在运行超类构造函数之前,您不能调用实例方法。

于 2013-10-02T11:41:05.550 回答
2

在我个人看来,你的问题暗示了设计上的缺陷。但是要回答你的问题。如果绝对必要,您可以使用反射更改 java 中的最终字段

如果一切都失败了,您仍然可以使用sun.misc.unsafe

但我强烈建议您不要这样做,因为它可能会杀死您的虚拟机。

于 2013-10-02T11:47:56.717 回答
0

到目前为止,我的工作是使用方法而不是最终成员:

class protectedfinal
{

  static abstract class AA
  {
    protected abstract Object a();
  }

  static class BB extends AA
  {
    @Override
    protected Object a() { return this; }
  }

  public static void main (String[] args)
  {
    AA a = new BB();
    System.out.println (a.a());
  }
}

但我想使用最终成员,因为我认为访问最终成员比调用方法更快。是否有机会与最终成员一起实施?

于 2013-10-02T11:53:43.890 回答