What Are the Rules Dictating the Inheritance of Static Variables in Java

What are the rules dictating the inheritance of static variables in Java?

I don't understand why the contents of foo vary depending on what class you're accessing it from.

Basically it's a matter of type initialization. The value of foo is set to "bar" when Sub is initialized. However, in your Testing class, the reference to Sub.foo is actually compiled into a reference to Super.foo, so it doesn't end up initializing Sub, so foo never becomes "bar".

If you change your Testing code to:

public class Testing {
public static void main (String[] args) {
Sub.main(args);
System.out.println(Super.foo);
System.out.println(Sub.foo);
System.out.println(Super.foo);
}
}

Then it would print out "bar" four times, because the first statement would force Sub to be initialized, which would change the value of foo. It's not a matter of where it's accessed from at all.

Note that this isn't just about class loading - it's about class initialization. Classes can be loaded without being initialized. For example:

public class Testing {
public static void main (String[] args) {
System.out.println(Super.foo);
System.out.println(Sub.class);
System.out.println(Super.foo);
}
}

That still prints "foo" twice, showing that Sub isn't initialized - but it's definitely loaded, and the program will fail if you delete the Sub.class file before running it, for example.

Static variables in Java

From JLS

A class or interface type T will be initialized immediately before the
first occurrence of any one of the following:

  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).
  • T is a top-level class, and an assert statement (§14.10) lexically nested within T is executed.

In the First case(first set of print staments), you have access only the sName variable only, and it's belong to Parent Class, so the child class was not initialized.

In the second set of print statements, You have access the sName1 variable, which belongs to Child class, so at this time, Child class was initialized.

It doesn't matter, even you have accessed the Child.sName, it actually refers the Parent.sName, so it won't load the Child class.

Java and inherited static members

As others already wrote, static members are bound to the class, so you need to track the id on a class level, e.g. like this:

abstract class Parent {
private int ID;

Parent() {
ID = nextId();
}

abstract protected int nextId();
}

class Sub1 extends Parent {
private static int curID = 0;

protected int nextId() {
return curID++;
}

//...
}

class Sub2 extends Parent {
private static int curID = 0;

protected int nextId() {
return curID++;
}

//...
}

Note that this approach is not thread safe - but neither was the code in the question. You must not create new objects from the same sub class concurrently from different threads.

Java static variable in method overriding

Static variables are not inherited in java. You varibale static String a is static which associates it to a class. Java inheritance doesn't work with static variables.

If you absolutely want the superclass variable you could use:

System.out.println(super.a);

Here is the inheritance what you probably wish to see:

abstract class A {
String a = "superclass";

abstract void test();
}

class B extends A {
void test() {
System.out.println(a); // Output superclass
}
}

I remove the static identifier and removed the subclass's implementation of variable a. If you run this you'll get superclass as output.

How fields are added from interface to class in Java?

As JLS says about static fields:

If a field is declared static, there exists exactly one incarnation of
the field, no matter how many instances (possibly zero) of the class
may eventually be created.

About fields inheritance:

A class inherits from its direct superclass and direct superinterfaces
all the non-private fields of the superclass and superinterfaces that
are both accessible to code in the class and not hidden by a
declaration in the class.

There is no special case about static fields inheritance, so they have to be inherited too.

We cannot write a good representative code sample with an interface, because of its variables are implicitly declared as static final. So, let's write a sample with superclass. Say we have:

class Base {
static int x = 15;
}

class A extends Base {}

class B extends Base {}

The x variable is shared part of Base class. If we think about inheritance in terms of IS-A relationship, then A (or B) is Base. Then x is shared part of A, B and Base. And simple demo:

public class DemoApplication {

public static void main(String[] args) {
System.out.println(A.x++);
System.out.println(B.x);
}
}

Output:

15
16

As you can see, superclass shares a static variable with subclasses. And with an interface actually nothing changes.

Multiple inheritance quagmire - which class is instantiated?

To answer your three questions...

  1. An instance of the _Foo in D will be returned from new C._Foo().
  2. No, it isn't; the _Foos are "members" of the classes they are declared in, so they are inherited much like variables. (In this case, like static variables.) [Spec] (https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2). (This is the best documentation I could muster up.)
  3. The order is determined by what is immediately inherited by class C. Since C extends D, C will inherit whatever D has (i.e. D._Foo). If D didn't declare a class called _Foo, then D would inherit B's _Foo, and then C would inherit that.

Hope this helps. :)

How to provide static field to subclasses?

Does each subclass hold its own static normalizingConstants?

No, there is only one normalizingConstants (Operation.normalizingConstants). static fields are tied to the class where they are declared.

If I call AddOp.normalizingConstants[0] and MinusOp.normalizingConstant[0] I want different results. How can this be achieved?

If you need different normalizingConstants arrays, you need to declare another static variable in your sub classes, like

class MinusOp extends Operation {

private static double[] normalizingConstants;
...

Note that your normalizingConstants fields are only accessible from within the delaring classes since they are declared private.

Also, you should not initialize your static array in the constructor - use a static initializer instead. Otherwise, the array is re-initialized each time you create a new instance of your class (or any sub class).

Access property/constant in extended classes

Static members are resolved at compile-time, and adding an ExtendedTest.x does not affect the also-existing BaseTest.x, which is what the BaseTest#out() method is linked to.

To accomplish what you're wanting, you need an overridden method:

public class BaseTest {
public String x() {
return "base";
}

public final void out() {
System.out.println(x());
}
}

public class ExtendedTest extends BaseTest {
@Override
public String x() {
return "extended";
}
}

This pattern is commonly used with an abstract method in the base class or interface to require the subclass to define an attribute such as a name or a key.



Related Topics



Leave a reply



Submit