Danial Alihosseini
Danial Alihosseini

Reputation: 101

initialize static final variable in child class(sub class) in java

I have a class like this:

public abstract class A {
    public static final int FIELD;
    // some methods
}

and I want to initialize the variable FIELD in a child class. I mean something like this:

public class B extends A {
    FIELD = 5;
}

EDIT actually I have multiple classes that extends A and all of them have the variable FIELD but with different values; so the way I found was to refactor the variable FIELD and declare it in super class. is there any other solutions? is it possible to have something like that? thank you for helping.

Upvotes: 5

Views: 6919

Answers (8)

Kanagavelu Sugumar
Kanagavelu Sugumar

Reputation: 19260

Irrespective of final keyword the single static variable won't work for multiple sub class due to single static variable get reassigned whenever new subclass is instantiated. Also the order of instantiation will still confuse further on what value lastly updated statically.

jshell> public abstract class A { public static String STATIC_SUPER_VAR = "A"; }
|  created class A


jshell> public class B extends A { public B() { STATIC_SUPER_VAR = "B"; } }
|  created class B

jshell> B.STATIC_SUPER_VAR
$3 ==> "A"    

jshell> A.STATIC_SUPER_VAR
$4 ==> "A"

jshell> new B()
$3 ==> B@685cb137

jshell> B.STATIC_SUPER_VAR
$4 ==> "B"

jshell> A.STATIC_SUPER_VAR
$5 ==> "B"

jshell> public class C extends A { public C() { STATIC_SUPER_VAR = "C";} }
|  created class C

jshell> new C()
$7 ==> C@5f2108b5

jshell> A.STATIC_SUPER_VAR
$8 ==> "C"

jshell> B.STATIC_SUPER_VAR
$9 ==> "C"

jshell> C.STATIC_SUPER_VAR
$10 ==> "C"

Solution

We can use static Map instead of single static variable.

jshell> public abstract class A {
   ...>
   ...>      private static Map<Class<? extends A>, Integer> CLASS_FIELD_HOLDER = new HashMap<>();
   ...>
   ...>      public A (int classSpecificInteger) {
   ...>
   ...>            CLASS_FIELD_HOLDER.put(getClass(), classSpecificInteger);
   ...>      }
   ...>
   ...>
   ...>      public static int getClassSpecificInteger(Class<? extends A> clazz) {
   ...>
   ...>                  return CLASS_FIELD_HOLDER.get(clazz);
   ...>      }
   ...> }
|  created class A

jshell> public class B extends A {
   ...>
   ...>  public B (int classSpecificInteger) {
   ...>
   ...>         super(classSpecificInteger);
   ...>  }
   ...> }
|  created class B

jshell> public class C extends A {
   ...>
   ...>  public C (int classSpecificInteger) {
   ...>
   ...>         super(classSpecificInteger);
   ...>  }
   ...> }
|  created class C

Ensure sub class is initialised, I mean Static Map is updated before access, Else NPE

jshell> B.getClassSpecificInteger(B.class)
|  Exception java.lang.NullPointerException
|        at A.getClassSpecificInteger (#5:13)
|        at (#7:1)

Initialised now:

jshell> new B(10);
$8 ==> B@610694f1

jshell> new C(20)
$9 ==> C@50b494a6

Access it now statically, without having FIELD in the subclass:

jshell> B.getClassSpecificInteger(B.class)
$10 ==> 10

jshell> A.getClassSpecificInteger(B.class)
$11 ==> 10

jshell> B.getClassSpecificInteger(C.class)
$12 ==> 20

Upvotes: 0

OwlPlusPlus
OwlPlusPlus

Reputation: 75

When you create a new B object, at first, a new A object will be created automatically and its final variables has been initialized in its default constructor; so you can no more modify their values.

Upvotes: 1

Ravindra babu
Ravindra babu

Reputation: 38910

You can not have static final variables in final class if you want to change them in derived classes.

1) Remove final keyword for FIELD attribute

2) Change the code as follows

import java.io.*;
import java.util.*;

class A {
    public static int FIELD = 4;
}
class B extends A {
    public B(){
        this.FIELD  = 5;
    }
}
public class Test {

    public static void main(String args[]) throws Exception {
    B b = new B();
        System.out.println("B value:"+b.FIELD);
    }

}

Output is:

B value:5

Upvotes: 0

Danial Alihosseini
Danial Alihosseini

Reputation: 101

The point is that child classes of a super class don't have a copy of a static field declared in super class and the super class shares that between them; So there is no way to have a static variable with different values in different child classes. Therefore I will declare the variable FIELD in all of the child classes.
I got all of them from @LenceJava in the comments. Thank you @LanceJava.

Upvotes: 5

Gaur93
Gaur93

Reputation: 695

This should work.

public class A {
public final int FIELD;
A(int a){
this.FIELD=a;
}
}
public class B extends A {
B(int a){
super(a);
}
}

Upvotes: -2

hermit
hermit

Reputation: 1107

final variables are initialized at the time of declaration and they cannot be re initialized or modified later in the child class. final in java means constants. Trying to modify their values causes compilation error.

Upvotes: 0

Suresh Atta
Suresh Atta

Reputation: 121998

Since it is static and final, at the time of initialization and or in static block you can assign value to that variable. Just no other place.

Upvotes: 1

Jens Schauder
Jens Schauder

Reputation: 81862

No this is not possible (at least not without some seriously dirty tricks)

The field has to be initialized when A gets initialized. A gets initialized before B gets initialized. Anything in B gets only executed when or after B gets initialized.

If this would be possible, what should happen when A.FIELD gets used, before B gets loaded?

What you could do is make the field private and not static, and provide a setter that allows only a single call to it and call it from B.

In most cases like this there is a much cleaner solution to the real problem, but since you didn't mention the real problem you try to solve we can't help on that front.

Upvotes: 1

Related Questions