2 Replies Latest reply: Apr 19, 2010 8:52 PM by 843793 RSS

    abstract generic class with same type array inherited by two diff... HELP!

    843793
      This is a conceptual presentation of my problem. It is significantly more complicated in terms of irrelevant issues, so please don't bother commenting on the algorithms (I just used some short ones for brevity's sake). Essentially, I have two classes that have a similar set of methods. It is then sensible to use generics/abstractions to reduce my total workload.

      Class A and class B are essentially the same. The only ways they differ are in comparison methodology and that each has an array with references to the other class type within it. IE- A has a data type B[] and B has data type A[].

      Each class has a 'compare' method that, in the example, uses a string. In implementation, they both use a series of local variables to determine comparisons (for brevity sake). This is mostly a hypothetical/syntax/style question, so I am using as simple a code I can to outline all of my hypothetical issues.
      class A
      {
           String name;
           B[] internal;
      
           private int compare(A c)
           {
                return(name.compareTo(c.name));
           }
           private void add(B c)
           {
                B[] temp = new B[internal.length+1];
                System.arraycopy(internal,0,temp,0,internal.length);
                temp[internal.length] = B;
                internal = temp;
                sort();
           }
           private void sort()
           {
                int pos = 0;
                while(pos < internal.length)
                     if(pos==0 || internal[pos-1].compare(internal[pos]) <= 0)
                          pos++;          
                     else
                     {
                          B temp = internal[pos];
                          internal[pos] = internal[pos - 1];
                          internal[--pos] = temp;          
                     }
           }
      }
      
      class B
      {
           String ref;
           A[] internal;
      
           private int compare(B c)
           {
                return(ref.compareTo(c.ref));          
           }
           private void add(A c)
           {
                A[] temp = new A[internal.length+1];
                System.arraycopy(internal,0,temp,0,internal.length);
                temp[internal.length] = A;
                internal = temp;
                sort();
           }
           private void sort()
           {
                int pos = 0;
                while(pos < internal.length)
                     if(pos==0 || internal[pos-1].compare(internal[pos]) <= 0)
                          pos++;          
                     else
                     {
                          A temp = internal[pos];
                          internal[pos] = internal[pos - 1];
                          internal[--pos] = temp;          
                     }
           }
      }
      Notice how A and B are basically the same? I would most definitely prefer to do something like the following. Obviously, When A extends C, it will have an array of type B. And when B extends C it will have an array of type A. This code certainly doesn't work at all-- but just to give you an idea....
      abstract class C
      {
           C[] internal;
      
           protected abstract int compare(C c);
           private void add(C c)
           {
                C[] temp = new C[internal.length+1];
                System.arraycopy(internal,0,temp,0,internal.length);
                temp[internal.length] = C;
                internal = temp;
                sort();
           }
           private void sort()
           {
                int pos = 0;
                while(pos < internal.length)
                     if(pos==0 || internal[pos-1].compare(internal[pos]) <= 0)
                          pos++;          
                     else
                     {
                          C temp = internal[pos];
                          internal[pos] = internal[pos - 1];
                          internal[--pos] = temp;          
                     }
           }
      }
      
      class A extends C
      {
           String name;
           private int compare(A c)
           {
                return(name.compareTo(c.name));
           }
      
      }
      
      class B extends C
      {
           String ref;
           private int compare(B c)
           {
                return(ref.compareTo(c.ref));          
           }
      }
      So, a few basic issues-

      1. I can't use temporary variables to swap my array to increase it's size (since I can't allocate new memory to a generic) if I need to when using a generic (I could fix this by using a linked list or a set, but I'd rather extend my knowledge of java by trying to get it to work with a raw-er array-- I don't actually have to be using temps if there is another good way to do it...). I guess I'm still a little old school in that I prefer using an array buffered with deadspace that just gets swapped out to a bigger size whenever that buffer is reached (so to outline that condition in my problem I excluded any buffer handling).

      2. I want my method header for compare in class C to have a parameter that will satisfy implementations in both A and B, so that internal functions within C (such as sort) don't have to be overridden by A or B. Type casting is fine, I don't mind that- I'm just not really too clear on the best way to get this to work.

      3. I also need a method such as add to work with the opposite class type as a parameter. So A can add type B to it's array, and vice versa (I know I can check for class mismatching etc and what not, so essentially the problem is the same as number 2). The main issue is just understanding the most appropriate way to implement generics for conditions like this.

      I don't want to have to use extra wrapper classes to make this work. Is there some dirty/elegant way I can make this happen? It's just a little strange to be having an abstract class have an array of itself, and then having a sorting algorithm dependent upon an abstract comparison method that will need generics...
        • 1. Re: abstract generic class with same type array inherited by two diff... HELP!
          843793
          Hello spinsane,

          you should consider the self type pattern:
          public abstract class C<S extends C<S>> {
              protected abstract int compare(S other);
              
              /* ... */
          }
          public class A extends C<A> { /* ... */ }
          public class B extends C<B> { /* ... */ }
          Also: Don't use arrays unless you absolutetly need to (which is almost never).

          With kind regards
          Ben
          • 2. Re: abstract generic class with same type array inherited by two diff... HE
            843793
            Ahh- in all honesty that was exactly the approach I had taken, but I had issues making all the functions work only for the proper class type. The main purpose for attempting all of this is to avoid writing two functions that were going to do exactly the same thing. Abstract stubs would then be pretty useless (though many were used in other places for private functions that needed different conditional cases etc).

            class C <T extends C<T,O>,O extends C<O,T>>
            {
                 protected LinkedList<O> internal;
                 protected int ID;     
            
                 protected <U extends C<T,O>> void add(U p)
                 {
                      if(p.compare(internal.peek()) != 0)
                      {
                           internal.add((O)p);
                           p.add(this);
                      }
                 }
                 public <u extends C<O,T>> int compare(U p)
                 {
                      if(ID == p.ID)
                           return 0;
                 }
            }
            
            class A extends <A,B>{ /*...*/ }
            class B extends <B,A> { /*... */}
            Generic T for this class type, O for other class type, and U for either or. This was my comprehensive solution, but it requires type casting in a few cases (I also don't have my code in front of me at the moment, so I'm not sure for what methods I crossed the O and T).

            This allows me to call add and compare, for either type in any function anywhere.

            Now I'm wondering if this is really the most elegant way to do this. I think there is something simpler I can do, but for now I'm satisfied with having one abstract class with the bulk of method bodies.