简体   繁体   中英

How to initialize a protected final variable in a child class of an abstract parent in Java?

I tried this:

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();
  }
}

But I got this error:

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

How to work around this problem?

Some people suggested here to use a constructor but this works only in some cases. It works for most objects but it is not possible to reference the object itself from within the constructor.

  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); }
  }

This is the error:

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

One could argue that it does not make much sense to store this kind of reference, because this exists already. That is right but this is a general problem which occurs with any use of this in the constructor. It is not possible to pass this to any other object to store it in the final variable.

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

So how can I write an abstract class, which forces all child classes to have a final member which gets initialized in the child?

You have to initialize Aa in its constructor. Subclasses will use super() to pass initializer to Aa .

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();
    }
}

You cannot use this until superclass constructors were called, because at this stage the object is not initialized, even Object constructor hasn't run at this point, therefore calling any instance methods would lead to unpredictable results.

In your case, you have to resolve circular reference with Z class in another way:

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

Either use a non-final field or change class hierarchy. Your workaround with instance method super(new Any(a())); would not work for the same reason: you cannot call instance methods until superclass constructors were run.

In my personal oppinion, your problems hints towards a flaw in design. But to answer your question. If absolutly necessary, you can change final fields in java using reflection .

And if everything fails, you can still utilize sun.misc.unsafe .

But I strongly discourage you from doing so, since it potentially kills your vm.

My work around so far is to use methods instead of final members:

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());
  }
}

But I would like to use final members, because I think accessing a final member is faster than calling a method. Is there any chance to implement it with final members?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM