22

Suppose i have the below class:

class Parent
{
    private int ID;
    private static int curID = 0;

    Parent()
    {
         ID = curID;
         curID++;
    }
}

and these two subclasses:

class Sub1 extends Parent
{
    //...
}

and

class Sub2 extends Parent
{
    //...
}

My problem is that these two subclasses are sharing the same static curID member from parent class, instead of having different ones.

So if i do this:

{
    Sub1 r1 = new Sub1(), r2 = new Sub1(), r3 = new Sub1();
    Sub2 t1 = new Sub2(), t2 = new Sub2(), t3 = new Sub2();
}

ID's of r1,r2,r3 will be 0,1,2 and of t1,t2,t3 will be 3,4,5. Instead of these i want t1,t2,t3 to have the values 0,1,2, ie use another copy of curID static variable.

Is this possible? And how?

Fr0stBit
  • 1,455
  • 1
  • 13
  • 22
  • Some more details in the discussion: http://stackoverflow.com/questions/9898097/what-are-the-rules-dictating-the-inheritance-of-static-variables-in-java – sidshu Jun 18 '13 at 14:58
  • Some more information http://stackoverflow.com/questions/9898097/what-are-the-rules-dictating-the-inheritance-of-static-variables-in-java – sidshu Jun 18 '13 at 14:59

9 Answers9

15

While static fields/methods are inherited, they cannot be overridden since they belong to the class that declares them, not to the object references. If you try to override one of those, what you'll be doing is hiding it.

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • 3
    JLS says something diferent: http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8 A class C inherits from its direct superclass all concrete methods m (both static and instance) of the superclass – MGorgon Sep 25 '16 at 16:43
  • @MGorgon JLS means that the subclasses will have this method but cannot be overridden since is static, which practically is the same as that the method is not inherited, it is more like the method is imposed. – Luiggi Mendoza Sep 25 '16 at 16:47
  • 1
    I agree with you, but formally JLS strictly specifies that static methods are inherited. It's somewhat confusing, but your answer in oracle certification would be wrong. – MGorgon Sep 25 '16 at 17:28
  • @MGorgon they're not inherited. In fact, you cannot override it, but you can hide it in subclasses. – Luiggi Mendoza Feb 08 '18 at 15:10
  • 'Cannot override' is not the same thing as 'not inherited'. – user207421 Apr 21 '18 at 03:05
  • 2
    @LuiggiMendoza this is wrong, they *are* inherited, but are *not* overridable – Eugene Apr 24 '18 at 13:31
  • @Eugene fixed... – Luiggi Mendoza Apr 24 '18 at 14:25
  • @LuiggiMendoza not very sure this *since they belong to the class that declares them* is correct, inheritance means that they belong to the class that inherits them... About the hiding, you could get away from that by declaring it `final` in the parent-class, but then the error from the compiler is just very weird – Eugene Apr 24 '18 at 19:29
13

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.

Andreas Fester
  • 36,091
  • 7
  • 95
  • 123
  • 3
    This it a good way to do what the OP needed doing, but I think it is worth mentioning that using static variables in this way is not thread safe. It might be a good idea to use singletons and factory methods here instead. – RudolphEst Jun 18 '13 at 15:02
  • @RudolphEst good point - running out of time now but will add this to my answer – Andreas Fester Jun 18 '13 at 15:03
2

It is possible, but not using a single counter. You'll need a counter per subtype. For example, something like the following:

private static Map<Class<?>, Integer> counters = new HashMap<>();

Parent() {
     Integer curID = counters.get(this.getClass());
     if (curID == null) {
         curID = 0;
     }
     ID = curID;
     curID++;
     counters.put(this.getClass(), curID);
}

Beware: the above is not thread-safe. But your initial code isn't either...

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
1

Statics are statics are statics. There is only a single instance of curID, period. So if you want separate counters for Sub1 and Sub2, you declare the static in each of those classes.

Lavie Tobey
  • 484
  • 1
  • 4
  • 12
1

Unlike what other answers said, there IS a solution to your problem, though it doesn't involve "static inheritance". You should have a per-class ID generator.

Here is a good example:

Java: Parent Methods accessing Subclasses' static variables?

Community
  • 1
  • 1
DVK
  • 126,886
  • 32
  • 213
  • 327
0

Static elements are not inherited at all.

There is not actually any such thing as Sub1.curID - this is a legal (yet confusing) way of referring to Persion.curID.

Unfortunately there isn't any way to do what you're after, with static references. They fundamentally do not and cannot work with inherentance - since they're statically resolved, they can't rely on dynamic dispatch and so cannot depend on runtime polymorphism. Given that the JVM/compiler treats static variables this way, I'm confident that there's no workaround you can come up with that would let you do what you want.

If the IDs truly need to be static, then you'll need to define distinct static variables in each of the subclasses.

Andrzej Doyle
  • 102,507
  • 33
  • 189
  • 228
  • 1
    JLS says something diferent: http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8 A class C inherits from its direct superclass all concrete methods m (both static and instance) of the superclass – MGorgon Sep 25 '16 at 16:44
  • @MGorgon It doesn't *really* inherit the methods - you can't override them, and since static references are resolved at compile time this wouldn't even be possible. It's more like an alias to the superclass' method (I agree that the JLS' language is misleading). Besides, the issue here isn't with methods but with fields - the behaviour is due to the fact that both subclasses refer to the same `curID` field. – Andrzej Doyle Sep 26 '16 at 10:25
  • 'Cannot override' is not the same thing as 'not inherited'. – user207421 Apr 21 '18 at 03:05
0

static members are part of the Parent.class object in the PermGen part of the JVM. All instances of that class share the same static variables.

Every subclass should have its own static curID.

darijan
  • 9,725
  • 25
  • 38
  • Ah, okay. Sorry for a hasty answer. – darijan Jun 18 '13 at 15:00
  • I didn't downvote, but it's not only the "instances of the class" that share the same static variable. It's simply all code that can access that variable. – Ingo Jun 18 '13 at 19:15
-1

static fields will not be inherited. every instance will use the same field. to accomplish what you want i would change the field into an instance field and either have one instance which internally increments this field or if you need to create three instances you could have a constructor where you pass the incremented value.

kukudas
  • 4,834
  • 5
  • 44
  • 65
-1

You are using a static variable

  • There are no copies of static variable for different objects,
  • There will be only on copy of static variable and it will be shared for all the instances

Regarding static variable inheritance, They are not inheritd at all

So even if you say

r1.curID;
t1.curID;

It will mean the same thing, i.e. Parent.curID

When you are changing a static variable from the instance of the class, and if another instance is accessing that variable, it will get the changed value as its a shared variable

Prasad Kharkar
  • 13,410
  • 5
  • 37
  • 56