1

So I'm working on an implementation of a Grid class for a small, personal utilities library. After much work, I'm tidying up the Grid class and adding some functionality. One of the key pieces of functionality that I wish to use with my Grid class is to be able to take a single, 2D array of any given type as an argument to the constructor.

This worked fine until I realized that I can't compile any code that attempts to pass in any array of primitives to the constructor. Since autoboxing doesn't happen on primitive arrays, this presents a design problem to me in the form of code reuse. The method for initializing the Grid is the same regardless of the type of array passed in, even if they are primitives, but it appears that I need to write a separate constructor for all the different types of primitives. Which leaves me with 9 different constructors assuming I just use my base constructor (and I had planned to have constructors with different arguments for things such as grid-wrapping options).

Am I right in assuming that there is no way to avoid all this code duplication?

12
  • I'm confused on what you mean by autoboxing doesn't happen on primitive arrays; any array is an object, and can be used for a generic type. Mind showing your code? I'm not sure if I'm understanding you correctly Commented Dec 31, 2014 at 3:11
  • You could use the builder pattern to get away from the telescoping constructors. Commented Dec 31, 2014 at 3:11
  • @Vince Emigh Autoboxing doesn't occur on an array of primitives in such that an array of type int[] could not be interpreted by the compiler as an array of type Object[]. Since int, double, char, boolean, etc. are all primitives, they don't extend Object. As an array, the values don't all get automatically converted to their Value Object counterparts, like Integer or Character, as they do when passing only a single primitive value. Commented Dec 31, 2014 at 3:13
  • But couldn't you do <T> Constructor(T array) then call new Constructor(new int[5])? Commented Dec 31, 2014 at 3:15
  • 1
    @Eddie B I hadn't thought of using the Builder pattern for the telescoping. Still learning all the design patterns myself. Thank you for the tip! Commented Dec 31, 2014 at 3:20

1 Answer 1

4

You can avoid (most of) the duplication by using Array class. But it's not pretty: your constructor parameter would have do be of type Object, and you'd have to just trust your caller to pass the actual array there, and not a Socket or a Properties.

For example, you could do your own boxing like this:

<T> public T[][] boxArray(Class<T> clazz, Object array) {
    int height = Array.getLength(array);
    int width = height == 0 ? 0 : Array.getLength(Array.get(array, 0));
    T[][] result = (T[][]) Array.newInstance(clazz, height, width);
    for(int i = 0; i < height; i ++) {
        Object a = Array.get(array, i);
        for(int j = 0; j < width; j++) {
            result[i][j] = (T) Array.get(a, j); 
        }
    }
    return result;
}
Sign up to request clarification or add additional context in comments.

3 Comments

I had no idea Array.get existed. I wouldn't recommend the OP actually doing this (his class should clearly be generic), but +1 for the ingenuity of this.
That can work for now. Thank you! But once I release it to a more public audience (once I open-source my library), I'll have to switch back to multiple constructors. For an open project, I'll take code duplication of the lesser of two evils when it comes to type-safety. For personal projects, though, this can work.
You can make it kinda type safe, by having multiple public one-line constructors taking primitive arrays, that all end up calling the same private one, containing common logic that operates on Array. That's how I would do it anyway. (For the record, I strongly disagree, that code duplication is a "lesser evil" to type (un)safety).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.