5

I'm trying to use java class BitSet as a field for a customized class. And I want the class to use a default BitSet with all bits set.

import java.util.BitSet;

public class MyClass {
    private BitSet mask;

    public MyClass() {
        this(new BitSet(4));
        // want to set all bits first
        // something like 
        // this( new BitSet(4).set(0,3) );
    }

    public MyClass(BitSet mask) {
        this.mask = mask;
    }    
}

By default BitSet constructor unsets all bits. So before I send it as an anonymous object, I would like call set(int, int) method to set all bits. I know that I could simply initialize the field mask to a new BitSet and then call set(int, int) method from there.

However, in general I'm wondering is it possible to access an instance method at time of object instantiation?

Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90
D Lee
  • 59
  • 5

3 Answers3

3

Why not writing a separate constructor that allows for the BitSet initialization? Using Java 8, this could look like something like this:

public class MyClass {
  private BitSet mask;
  public MyClass() {
    this(new BitSet(4),(m)->m.set(0,3));
  }
  public MyClass(BitSet mask,Consumer<BitSet> initializer) {
    initializer.accept(mask);
    this.mask = mask;
  }
}

You can even make that more generic by introducing a static method with type parameters:

public static <T> T initialize(T t,Consumer<T> initializer) {
  initializer.accept(t);
  return t;
} 

In that case, the earlier MyClass would look as follows:

public class MyClass {
  private BitSet mask;
  public MyClass() {
    this(initialize(new BitSet(4),(m)->m.set(0,3)));
  }
  public MyClass(BitSet mask) {
    this.mask = mask;
  }
}

UPDATE

And there is one more way, without introducing new methods or constructors:

public class MyClass {
  private BitSet mask;
  public MyClass() {
    this(new BitSet(4) {{ set(0,3); }});
  }
  public MyClass(BitSet mask) {
    this.mask = mask;
  }
}

An anonymous class is being instantiated by extending BitSet and adding an instance initialization block, hence the double curly braces.

Community
  • 1
  • 1
YoYo
  • 9,157
  • 8
  • 57
  • 74
  • I'm very weak in generics. But above is exactly what I'm looking for. It's concise and also allows me to use `this` operator. Then I can have common initialization code in the non-default constructor. Thanks! – D Lee Apr 23 '16 at 12:15
  • The third option that you added. What is the term for this approach, if any? – D Lee Apr 23 '16 at 16:57
  • It is an 'Instance Initializer Block', but as it appears within the body of an anonymous class, it looks as if it is some special syntax (it's not). For that reason, people often refer to it as [the 'Double Braces' idiom](http://stackoverflow.com/questions/1958636/what-is-double-brace-initialization-in-java). It is often described in [anti-patterns](https://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/) for nested collection initialization. However, the way it is introduced here should be ok. – YoYo Apr 23 '16 at 17:25
2

BitSet does not have a fluent interface, so something like new BitSet(4).set(0,3) doesn't work for BitSets. There are only the static BitSet.valueOf() methods, but those are somewhat awkward to use. However, if you want a static configuration you could just instantiate a BitSet with the desired value, use BitSet.toLongArray(), print the array values and instantiate your BitSet with it. In your specific example the default constructor could be:

public MyClass() {
    this(BitSet.valueOf(new long[]{7}));
}

As for the general part of the question: It would only work if you have a "setter" that returns the current object, that would allow you to chain the calls. So for your own classes you could do something like this:

public class A {
    private int num;

    public int getNum() {
        return num;
    }
    public void setNum(int num) {
        this.num = num;
    }
    public A withNum(int num) {
       setNum(num);
       return this;
   }
}

If you used that in a constructor like with the BitSet you can do this(new A().withNum(4));

Fluent interfaces are pretty popular (e.g. the AWS SDK has that everywhere), just the JDK objects don't have them usually.

Volker Kueffel
  • 145
  • 1
  • 13
0

No; that would have to be done as a separate call, which will be executed after the object's construction has finished. The only way to do it in one line in your situation is if the method's return type had been BitSet and the method had returned the instance it was invoked on, in which case you could have done

this(new BitSet(4).set(0, 1)); // Doesn't actually work

Unfortunately, set() is void, so you can't do this.

Aasmund Eldhuset
  • 37,289
  • 4
  • 68
  • 81