2

I would like to instantiate an array of type T as such:

items = new T[maxQue];

Here is my code so far, I believe a non-reflective approach:

interface MyFactory<T>
{
   T[] newObject();
}

public class Queue< T extends Comparable<T> > {

   private int front;
   private int rear;
   private T[] items;
   private int maxQue;
   private static final int MAX_ITEMS = 1000;

   public Queue(MyFactory<T> factory) {
      maxQue = MAX_ITEMS + 1;
      front = maxQue - 1;
      rear = maxQue - 1;

      items = factory.newObject();
      items = new T[maxQue];
   }
}

The { items = factory.newObject(); } works and resolves the compiler error but I do not know how to set the size of the array to maxQue using the MyFactory interface.

  • How can I declare this array with a size of maxQue?

On a side note, while I know the definition of reflection in Java, can anyone please put it and/or the concept of factories in layman terms?

Edit: Found a decent description of reflection here: What is reflection and why is it useful?

I am still a bit unclear on when reflection should be avoided and whether it would be appropriate for creating an array.

Boris
  • 566
  • 5
  • 21
  • 1
    A factory is just a fancy word for "an object that makes objects". – user253751 Jul 17 '15 at 23:45
  • You're already getting the array from the factory. There's no need for _How can I declare this array with a size of maxQue?_ – Sotirios Delimanolis Jul 17 '15 at 23:46
  • @SotiriosDelimanolis I see that the factory provides an array but that is where I get a bit lost. There is no explicit setting of the size of the array. It just returns "an" array but how do I either a) know it's size or b) set its size explicitly to maxQue? From what I understand, I get back an array of type T and assign it to items. But I do not see a way to set the size to maxQue. Thanks! – Boris Jul 17 '15 at 23:49
  • 1
    You don't. An array is fixed size. If you need to, change your interface's `newObject` method to accept a max length and return an array of that size. – Sotirios Delimanolis Jul 17 '15 at 23:51
  • Why did you step away from `items = new T[maxQue];` and go to a factory in first place? Seems odd to do so just to make an empty array (assumption). – weston Jul 17 '15 at 23:54
  • @SotiriosDelimanolis Ok, that makes sense. I understand an array is fixed size, that is what confused me as in the code above, newObject did not take a size and just returned an array of, I believe, unknown size. If I understand correctly, adding a parameter to newObject(int size) will create an array with "size" as the size? – Boris Jul 17 '15 at 23:54
  • @weston the compiler returns an error: "Type parameter 'T' cannot be instantiated directly." and I was not able to compile/test the code. – Boris Jul 17 '15 at 23:55
  • _adding a parameter to newObject(int size) will create an array with "size" as the size_ No. You've defined an interface. The implementation can do whatever it wants as long as it returns a value of the type bound to `T`. – Sotirios Delimanolis Jul 17 '15 at 23:56
  • `items = new T[maxQue];` gave that error? – weston Jul 17 '15 at 23:56
  • @weston yes, that was the line. – Boris Jul 17 '15 at 23:58
  • I see, ignore my answer, I'm clearly in c# mode from work. – weston Jul 18 '15 at 00:01
  • @weston Wait, did you delete your response where T[] newObject(int size); and items = factory.newObject(maxQue); ? I believe that was actually correct, please see Sotirios' comment where he says: "If you need to, change your interface's newObject method to accept a max length and return an array of that size." I tried that approach and it compiles/runs but will need to do more thorough testing before i can accept. It seems right though and avoids using reflection. – Boris Jul 18 '15 at 00:04
  • I deleted because it never helped you create the generic array. – weston Jul 18 '15 at 00:06
  • Could you please tell me a bit more about this, I am not sure I understand why it would not create generic array of size maxQue? – Boris Jul 18 '15 at 00:08
  • It would work, but I didn't give an implementation for that factory, so I just move the problem elsewhere without solving it. You'd need to use a combination of the additional parameter and either a factory for each type you want to queue or a solution like immibis's. I prefer my updated answer. – weston Jul 18 '15 at 00:10

2 Answers2

3

You can never use new T in Java if T is a type parameter, because of the way they chose to implement generics. However, there are ways around it using reflection.

Since you have an object of type T[] already, you can use reflection to get its type and then create a new array of that type.

items.getClass().getComponentType() will give you T's Class. You could create a new array of this size with items = (T[])Array.newInstance(items.getClass().getComponentType(), maxQue).

user253751
  • 57,427
  • 7
  • 48
  • 90
  • Note: I've answered the specific question you asked (how to use reflection to create an array here), but there's probably an easier way to achieve your goal, without having to use reflection to create an array. – user253751 Jul 17 '15 at 23:52
  • What would be the benefit vs drawback of using reflection? I've heard and read that it may be preferable to avoid it in this scenario but I am not sure I understand why. – Boris Jul 17 '15 at 23:57
  • Tried this and it appears to work; the compiler shows an unchecked cast warning. – Boris Jul 18 '15 at 00:07
  • 1
    @62696e617279 You could do `items.getClass().cast(Array.newInstance(...))` to avoid the cast warning. The main drawback of using reflection is that it's more complicated. – user253751 Jul 18 '15 at 00:10
  • Getting a NullPtrException with this method when I put the reflection code in the constructor. – Boris Jul 18 '15 at 00:32
  • @62696e617279 is `items` null? – user253751 Jul 18 '15 at 00:36
  • I am not sure; items should not be null as I thought the point of using reflection is to create an array of size maxQue called items. But when reflection looks at items, it is null (in the constructor). – Boris Jul 18 '15 at 00:42
2

You can create an array of a type that T extends, so it may or may not be suitable for you to use the extended type (Comparable), or just Object:

public class Queue<T extends Comparable<T> > {

    private int front;
    private int rear;
    private Comparable[] items;
    private int maxQue;
    private static final int MAX_ITEMS = 1000;

    public Queue() {
        maxQue = MAX_ITEMS + 1;
        front = maxQue - 1;
        rear = maxQue - 1;

        items = new Comparable[maxQue];
    }
}

When dequeuing or otherwise needing a T, just cast to T

@SuppressWarnings("unchecked")
public T dequeue(){
    return (T)items[0];
}

Both solutions of mine and immibis' are covered here: https://stackoverflow.com/a/530289/360211

Community
  • 1
  • 1
weston
  • 54,145
  • 21
  • 145
  • 203
  • I would like to do T deQueued = items[front % MAX_ITEMS]; but I get the error: Required T, found java.lang.Comparable<>. I also get an "Annotations are not allowed here" – Boris Jul 18 '15 at 00:37
  • note I am casting `T deQueued = (T)items[front % MAX_ITEMS];` I've moved annotation – weston Jul 18 '15 at 00:41
  • This seems like the right answer, the problem is it extends Comparable and I am using Queue in a Binary Tree, where the TreeNode is a generic type and does not implement Comparable. Thus I get an error and am forced to implement Comparable with my TreeNode class. Not sure how to compare (T, T). Thank you all for your help though! – Boris Jul 18 '15 at 00:52
  • 1
    `Comparable` was from your question, but you can always use `Object`. – weston Jul 18 '15 at 00:54
  • Ah, yes I see that now; pardon the oversight. Object worked as well! Tested it with return (T) items[front % MAX_ITEMS]; for dequeueing and it works. This is a valid solution. Thank you! – Boris Jul 18 '15 at 01:01