Java generics - returning subtype of declared type from method?

Declare getComponents() as: public List getComponents().

Expressions in return values because it requires callers to follow suit. That is, this doesn't compile: List foo = obj.getComponents(). – Jason Cohen Oct 21 '08 at 22:09 Instead the caller also has to declare his list as List and so on.

Yukky. – Jason Cohen Oct 21 '08 at 22:10 See my alternate answer. – Jason Cohen Oct 21 '08 at 22:13 2 "Instead the caller also has to declare his list as List and so on.

Yukky. " But it is good practice for the caller to have done that anyway. Since the caller is not adding any elements to the list (the OP said it is meant as read-only), the caller shouldn't care about the actual parameter of the list, just as long as it extends JComponent.

For abstraction, the caller should have used the least restrictive type that he/she requires. – newacct Oct 21 '08 at 6:13 Using wildcard is the correct solution. Speaking of yukky - returning JComponent and JButton will give the sought covariance, but it is otherwise degenerate.

– Yardena Oct 21 '08 at 14:13.

I think I've found the answer which I'm looking for... return Collections. UnmodifiableList(buttons); I had previously tried: return Collections. UnmodifiableList(buttons); but this was being type-inferenced to List.

Putting in the explicit type parameter allows the List to be treated as a List, which is allowed by unmodifiableList(). I'm happy now ;-) and I've learned something thanks to the discussion. Calum.

This is only what you want if it is acceptible that the list returned is unmodifiable. Of course, returning a List is also a list which is unmodifiable (well, you can't add anything to it, without reverting to raw types, anyway) – oxbow_lakes Oct 21 '08 at 22:38 Yes - my original question was regarding returning a read-only (or unmodifiable) list, in which case I think this solution works. – Tim Sullivan Oct 21 '08 at 22:47 I think that they are changing the type-inference rules in JDK7 to infer things like this (that is, "return Collections.

UnmodifiableList(l)" will be inferred from the assignment, in this case the return-type of the method, so you won't have to add the bit in the future – oxbow_lakes Oct 21 '08 at 22:49.

I don't think you can do what you want without changing either the super-class method signature or the sub-class list declaration. The super-class is rigidly defining the return type to be JComponent. There's no way to make your return type anything but JComponent.

If it's read-only, I'd do something like: public class SubClass extends SuperClass { private List buttons = new ArrayList(); public void addButton(JButton button) { buttons. Add(button); } public List getComponents() { return Collections. UnmodifiableList(buttons); } } If you can modify the super-class, you could try something like: public abstract class SuperClass { public abstract List getComponents(); } public class SubClass extends SuperClass { private List buttons = new ArrayList(); public List getComponents() { return Collections.

UnmodifiableList(buttons); } }.

I don't understand how this answer isn't accepted as the correct one since it does answer the original question, without the wildtype clutter. Anyone care to elaborate please? – Cue Aug 12 '09 at 13:11.

To do this you need to widen the generics thingy. :) public abstract class SuperClass { public abstract List getComponents(); } public class SubClass extends SuperClass { private List buttons; public List getComponents() { return buttons; } }.

Hmm, not sure The usual way to set that up would be to have the super look like public abstract class SuperClass { public abstract List getComponents(); } Not sure how to do it without changing that around.

Thanks for all the answers, regarding using wildcards in the super-class. I know about that option, but I'm trying to avoid it, as I'm writing an API for non-expert Java users; this would force them to declare their variables using wildcards, which might scare them away... If the scenario was that the super-class was from a third-party library, so I couldn't change it, then what would be my options? Would it be possible to have a List field in my sub-class, or would I have to resort to having a List field, and casting where required to JButton internally?

Remember that the List is externally read-only, so it should be "conceptually" possible; except that the compiler doesn't know this. Thanks again, Calum.

Jason: thanks for the follow-up. I can't use @SuppressWarnings, as it's a compiler error. I also came up with using new ArrayList, and agree that the performance penalty is probably small.

However, I want to be able to modify my list internally, and provide an unmodifiable view of it externally (as List). My use of "read-only" was probably a bit loose... So new ArrayList wouldn't track any changes in the internal list. Thanks, Calum.

The whole point of generics is to provide compile-time type-safety fo things such as the "type" of a collection. Unfortunately for you, a List is not a sub-type of a List. The reason for this is simple and is as follows: List jc; List jb = new ArrayList(); //if List was a sublcass of List then this is a valid assignment jc = jb; jc.

Add(new JCheckBox()); //valid, as jc accepts any JComponent JButton be = jb. Get(0); //this will throw a ClassCastException, rendering Generic type-safety pointless Generics are contra-variant in this manner, your original desire might as well have been to override a method which returned a String with one which returned a Float I think it's a good general rule to be very careful when designing a generic class. Do you really need generics?

How will it get used? Some generic designs end up with awful structures and mean users have to revert to the raw version. JTable's filtering mechanism is an excellent case in point: when you want to implement a filter-chain (which you certainly will!), the whole thing falls apart.

The fact is; in this case, generics were added at a cost and with practically no benefit.

It's a read-only copy of the view which is being returned. So conceptually, a read-only List should suffice as a read-only List, as trying to add a JCheckBox would cause an exception to be thrown. – Tim Sullivan Oct 21 '08 at 22:41 Then at least returning a List would explicitly (i.e.At compile-time) be a read-only view of the collection.

In an API, a method as you have declared it is only found out to be read-only at run-time! – oxbow_lakes Oct 21 '08 at 22:45.

Returning a generic type with wildcard is not a good idea as it forces the client to think aoubt what's being returned ... It'll also make the client code more cumbersome and difficult to read.

You could do the cast with @SuppressWarnings. I believe that would be appropriate in this case, just make sure you document why in a comment. Alternately, do the following: public List getComponents() { return new ArrayList( buttons ); } Yes I know this makes a copy and the list is already read-only.

But until the profiler tells you otherwise, I would assume the penalty is small. @Calum: I agree that using? -expressions in return types is bad form because calling code is unable to do this for example: List list = obj.getComponents().

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions