2

I need to have some sort of data structure that can contain heterogenous subclasses of the same superclass, all of which I have implemented myself.

So far, I am attempting to have an ArrayList<SuperClass> list = new ArrayList<SuperClass>(); and then, I am assuming I will be able to cast each slot of list into either of the subclasses, but this is not working out so well.

I need an efficient way to do the aforementioned.

Thanks!

George K.
  • 2,867
  • 4
  • 19
  • 28

1 Answers1

5

You can do it with any data structure that exists, I would recommend a List or a Set. For instance:

Collection<Super> supers = new ArrayList<Super>();  

Now when you say this:

I am assuming I will be able to cast each slot of list into either of the subclasses,

That is an invalid assumption. The collection will hold any object that extends Super however you cannot arbitrarily cast each element into whatever you want. You would need to do an instanceof test on each element if you are looking for that type of functionality, example follows:

for(Super currentSuper : supers)  
{  
    if(currentSuper instanceof SubA)  
    {  
         SubA subA = (Suba) currentSuper);  
         // do stuff with subA
    }  
    else if(currentSuper instanceof SubB)  
    {  
         SubB subB = (SubB) currentSuper);  
         // do stuff with subB
    } 
}  

Scope as need be.

Now on the point of Vlad:

and much better design would be not to test what the actual class is, but just to call a virtual method, which will do the right thing in any case

If you can guarantee the functionality of all potential sub-classes and have no issues with people overriding your classes (in the event you haven't marked them final) you do not need to do the instance of test. Instead your code could be as simple as:

for(Super currentSuper : supers)  
{  
    currentSuper.doSomethingNifty();
}  
Woot4Moo
  • 23,987
  • 16
  • 94
  • 151
  • 3
    ... and much better design would be not to test what the actual class is, but just to call a virtual method, which will do the right thing in any case. – Vlad Nov 04 '12 at 22:08
  • @Vlad Do you mean like in `C#` where you can declare a function `virtual` or is this something different? – Woot4Moo Nov 04 '12 at 22:09
  • Yes. BTW, in Java the methods are virtual by default, in contrast to C#. – Vlad Nov 04 '12 at 22:10
  • @Woot4Moo in Java, [every non static method are virtual by default](http://stackoverflow.com/a/4547462/1065197) – Luiggi Mendoza Nov 04 '12 at 22:11
  • Good to know about the virtual. Now on a different note the `instanceof` test is explicity being used (in this case) if there is something special that needs to be done with the object. For instance imagine the scenario where you want to throw an `IllegalArgumentException` during processing if someone snuck a `MyDangerousSubclass` in there. That would be very handy, specifically in instances where you wanted to prevent unknown subclasses from executing. – Woot4Moo Nov 04 '12 at 22:13
  • @Vlad wouldn't your first comment give rise to a great answer to this issue? – mkl Nov 04 '12 at 22:13
  • @mkl his comment fails to address the need for `instanceof` – Woot4Moo Nov 04 '12 at 22:14
  • @mkl: well, the original question just asks if it's possible to pack the objects into a container, not about how to work with them. So the comment is more to the example at the end of this answer. – Vlad Nov 04 '12 at 22:15
  • I have updated my answer to provide the other example that vlad has suggested. – Woot4Moo Nov 04 '12 at 22:17
  • I think in a good design you need `instanceof` very rarely. Example: if your loop is applying different drawing procedures for each of the object types, why not pack the appropriate code into a virtual method `Draw`, so that your loop looks like `for(Super s : supers) s.Draw();`? (Well, this comment is covered by your last update to the answer.) – Vlad Nov 04 '12 at 22:17
  • @Vlad: To address this - I need to both be able to pack the different objects into a container, and also be able to work with each of the different object's specific properties/methods – George K. Nov 04 '12 at 22:19
  • @Vlad agree. However, what about the scenario where you have a shared API that people can extend your `Super` class and you have a `white list` of known `Super`s . What would the design flaw in that case be? I ask because I am curious. The restriction is `Super` has to be able to be extended at will and it can be extended to be malicious. – Woot4Moo Nov 04 '12 at 22:20
  • This has got the answer to the question. But regarding the use of `instanceof` and cast, I totally agree with @Vlad. – Bhesh Gurung Nov 04 '12 at 22:20
  • @George: well, why do you want "low-level" access to the properties? Maybe you need to pack the functionality into virtual methods? – Vlad Nov 04 '12 at 22:20
  • @Woot4Moo: about malicious extenders, well, I would prefer to design in such a way that the list contains only "trusted" objects (check during insertion + don't allow the others to modify my list), so that I don't need to recheck every time when I am using the list. – Vlad Nov 04 '12 at 22:22
  • @Vlad - I stand corrected: I only need regular access to each of the subclass's specific methods – George K. Nov 04 '12 at 22:24
  • @Vlad I understand the crux of the issue, so what about the validation code pre-addition to the list. That is the code I am most interested in irrespective of what part of the API it falls into. – Woot4Moo Nov 04 '12 at 22:24
  • @Woot4Moo: Well, I would do the following: derive a non-public `TrustedSuper extends Super`, so you can actually declare `supers` a list of `TrustedSuper`s, not just `Super`s. As `TrustedSuper` is not public, no other packages can derive from it. – Vlad Nov 04 '12 at 22:33
  • 1
    @Woot4Moo Obviously Vlad would have had to spend some words on that, but his hint essentially is the answer to the questions that **should** have been asked. With the exception of the security reasons mentioned (and in that case a design not including any subclasses would be even better) explicit casts should be avoided. – mkl Nov 04 '12 at 22:40