3

I have a class FirstClass<O> and a class SecondClass<O>, and I want to make an O[] in SecondClass<O> inside a routine which is called from FirstClass<O>, where O is a generic class parameter. I fail to find how to do this.

I need an O[] specifically (and not ArrayList<O> or similar) because I need to get elements from it very often inside the body of a loop, and it matters for the execution time of my algorithm.

So I would want something along these lines.

public class FirstClass<O> {
    void someRoutine(n and other params) {
        //Do some stuff
        SecondClass<O> = new SecondClass(n, possibly_other_params);
        //Do some stuff
    }
}

and

public class SecondClass<O> {
    O[] myArray;
    SecondClass<O>(int n, possibly_other_params) {
        //Here the constructor that creates an O[n]
    }
}

Some methods I found on the web, but do not work for my case:

  • Use O[] array = (O[]) new Object[n]; but that doesn't compile.
  • Use Object[] array = new Object[n]; and do an (O) cast every time I request something from the array, but this is way too slow
  • Use Array.newInstance(Class<O> type, int n);, with O o; and type=o.class but it complains that type is now of type Class<CAP#1> instead of type Class<O>, whatever CAP#1 means...

How should I do this properly in Java, with optimal execution speed in mind?

3
  • 5
    Have you actually profiled this? Is the casting actually what is causing your performance concerns? Given that generics in Java are erased at runtime, I don't see an easy work-around here to get it working as you're expecting. I think you'll be better off trying to re-visit your expected API, then trying to get Java's generics to work they way you want. Commented Sep 8, 2012 at 4:38
  • Just use ArrayList, sheesh. Commented Sep 8, 2012 at 4:39
  • The problem with ArrayList is that I constantly need to change one element in the array, and this basically all that this inner loop does and hence is the most expensive part of the algorithm. Repeatedly doing a[i]=a[j] to obtain some permutation is quite a bit cheaper than doing list.set(i,list.get(j)) all the time. Putting a fixed array type makes it indeed faster, but then I need to make copy-paste the code for each of the 25 possible types O can be, and that's not really good style. :/ Well, if it's not possible then it's not possible of course. Thanks for the input anyway. Commented Sep 8, 2012 at 4:48

4 Answers 4

3

Java's handling of generics is in pretty rough shape but you can accomplish something close to what you want if you are prepared to make small adjustments. Please see:

public class FirstClass<O> {
    Class<O> type;

    public static <O> FirstClass<O> create(Class<O> type) {
        return new FirstClass<O>(type);
    }

    public FirstClass(Class<O> type) {
        this.type = type;
    }

    public void routine(int size /*, other params */ ) {
        SecondClass<O> instance = new SecondClass<O>(type, size);
    }
}

public class SecondClass<O> {
    public O[] array;

    @SuppressWarnings("unchecked")
    public SecondClass(Class<O> type,int size) {
        array = (O[])Array.newInstance(type,size);
    }
}

And a use case:

FirstClass<Integer> instance = FirstClass.create(Integer.class);
instance.routine(110);

This is just a rough example although I am sure you could accomplish something similar without having to use this approach.

Sign up to request clarification or add additional context in comments.

3 Comments

Use a factory method to infer the type, it can simplify the code! static <T> FirstClass<T> create(final Class<T> type) { ... } and instance = FirstClass.create(Integer.class);
Not to mention you're wrong about not being able to use primitives... see Integer.TYPE, or, equivalently, int.class.
@oldrinb I think he meant the use of generics precluded primitives, not the Array.newInstance call itself.
1

Use O[] array = (O[]) new Object[n]; but this requires an (O) cast every time I request something from the array, so this is way too slow

What? The whole point of type O[] is that you don't need an (O) cast when getting things out of it

3 Comments

Sorry, apparently I missed there. It is corrected now: using O[] array = (O[]) new Object[n]; is impossible as these types are inconvertible, the thing that requires (O) casting every time is Object[] array = new Object[n];.
@user1111929: "is impossible as these types are inconvertible" Not really. O is type-erased to Object. As long as the array does not escape the scope of O, it won't cause any problems.
You are correct, my apologies. It's not the same speed as a native O[], but it works and it's much cleaner than the (O[])Array.newInstance(type,size) solution. Thanks!
0

Repeating my comment from above to hopefully mark this question as answered:

Have you actually profiled this? Is the casting actually what is causing your performance concerns? Given that generics in Java are erased at runtime, I don't see an easy work-around here to get it working as you're expecting. I think you'll be better off trying to re-visit your expected API, then trying to get Java's generics to work they way you want.

3 Comments

I created for you a simplified version of my algorithm, with approprioate time measuring: pastebin.com/QeCW0W1R As you can verify on your computer, the casting causes a 35%-50% delay. This is not something minor. In my more involved final version it is only 15-20% delay, but still, it's not something to just forget about if there are any alternatives.
Actually, your benchmark is noticeably flawed, and doesn't leave the time for the JIT to warm up or anything. I wouldn't trust its results to be accurate. Try using a tool like Caliper that knows how to do proper benchmarking in Java.
Depends on how you use it. I ran the benchmark 5 times in this order and 5 times with the order of the tests reversed, the results were always the same. Still noticeably flawed if used in that way?
0

Here is the source code for ArrayList.set:

public E set(int index, E element) {
    rangeCheck(index);

    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

Granted, it does an additional lookup to get the old element, which you don't care about, but this is random access we're talking about (read: O(1) time). Just use ArrayList unless you have hard numbers to show it's slowing you down.

8 Comments

I created for you a simplified version of my algorithm, with approprioate time measuring: pastebin.com/NUj90ZPv As you can verify on your computer, there is always a factor 4 difference between using None[] and ArrayList<None> for this algorithm.
@user1111929 Well, I can't argue with that. Try Jordan White's solution - that should work assuming creation of the array itself is rare.
I don't see a direct way to test it, but out of curiosity, why would the creation of the array in his solution be more expensive than creating an ArrayList<O>? Doesn't that create a new O[] internally in pretty much the same way?
Array.newInstance uses reflection/native magic to create the dynamically typed array, making it slightly slower. The difference is probably negligible even for your requirements though.
Actually, your benchmark is noticeably flawed, and doesn't leave the time for the JIT to warm up or anything. I wouldn't trust its results to be accurate. Try using a tool like Caliper that knows how to do proper benchmarking in Java.
|

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.