Ionuț-Claudiu Herciu
Ionuț-Claudiu Herciu

Reputation: 159

Generating unique auto-incrementing instance IDs

I have been trying to generate unique IDs for class instances starting from 1, like so:

public abstract class foo {
    static int ID = 0;
    final int id;

    public foo() { this.id = ++ID; }
}

I then realised that I have several classes that require this behaviour, and so I tried to make an abstract class from which to inherit, but I found that static fields can't really be inherited.

Is there any way I can reuse this common behaviour in Java?

Edit:
I did not make it clear, but I need the indexes for each subclass to be not only unique, but also consecutive.

For example, if I have bar and baz inheriting from foo:

bar b1 = new bar();
baz b2 = new baz();
bar b3 = new bar();

b2 should have id == 1, and b3 should have id == 2.

Upvotes: 3

Views: 4109

Answers (3)

clay
clay

Reputation: 20370

One option, use UUIDs (http://docs.oracle.com/javase/7/docs/api/java/util/UUID.html)

UUID.randomUUID();

A second option is to just use AtomicInteger for this:

    AtomicInteger idGen = new AtomicInteger();
    System.out.println(String.format("First is %d", idGen.getAndIncrement()));
    System.out.println(String.format("Second is %d", idGen.getAndIncrement()));

I would not use abstract classes or inheritance or even custom classes for this issue.

EDIT: Here is a full example that supports the initial code. I don't see how you could make this simpler:

public static class foo {
    final public int id;

    foo(int id) { this.id = id; }
}

public static class bar extends foo {
    static final AtomicInteger idGen = new AtomicInteger(1);

    public bar() {
        super(idGen.getAndIncrement());
    }
}

public static class baz extends foo {
    static final AtomicInteger idGen = new AtomicInteger(1);

    public baz() {
        super(idGen.getAndIncrement());
    }
}

public static void main(String[] args) {
    bar b1 = new bar();
    baz b2 = new baz();
    bar b3 = new bar();

    System.out.println(String.format("b1.id = %d", b1.id));
    System.out.println(String.format("b2.id = %d", b2.id));
    System.out.println(String.format("b3.id = %d", b3.id));
}

Upvotes: 0

chiastic-security
chiastic-security

Reputation: 20520

Not really! There are a couple of things you might try:

  1. Have a single IDGenerator class with a static method to generate a new ID for a specific class. The .generate() method would take a Class<?> parameter, and would maintain a HashMap mapping classes to most recently given out identifiers. This would put all the logic into one class, but wouldn't really simplify things.
  2. Have a static reference to a new instance of an IDGenerator class inside each class that wants to use this kind of behaviour. In this case, the IDGenerator class wouldn't need a Class<?> parameter because there would be one instance for each class using it. Its .generate() method would be a no-arg method. Again, I'm not sure this makes things much simpler.
  3. Abandon the requirement for consecutive IDs. That way, you could have a class IDGenerator with a static no-arg .generate() method that would just dish out the next unused identifier. Your identifiers would then be unique across your application, and not consecutive within a class.

What you've got is pretty fool-proof and slimline.

One more minor note: you say you want your IDs to start from 0, but the way you've written it, they'll start from 1. You want this.id = ID++ rather than this.id = ++ID.

Upvotes: 1

Oliver Dain
Oliver Dain

Reputation: 9953

As others have noted, this may not be a good idea. However, if you want to do it just increment the counter in the base class constructor:

abstract class foo {
    static int globalId = 0;
    final int id;
    foo() {
        id = globalId;
        ++globalId;
    }
}

Use an AtomicInteger if thread safety is a concern.

Upvotes: 1

Related Questions