tags:

views:

3164

answers:

5

How can I make this java generic cast ?

public interface IField {

}


class Field implements IField { // package private class

}

public class Form {
  private List<Field> fields;


  public List<IField> getFields() {
    return this.fields;

  }

}

The return statement throws a compiler error (I know the reason - I read the generics tutorial) but it would be very handy to write such code.

If I declared "fields" as List I would need to use a lot of casts to Field in other methods of a Form class .

Can I force that damn compiler to bend it's rules and compile that return statement ?

Thanks in advance.

+6  A: 

As it happens, you can, because Java generics are just grafted on, not part of the type system.

You can do

return (List<IField>)(Object)this.fields;

because all List<T> objects are the same underlying type.

Bear in mind that this allows anyone to put any type implementing IField in your list, so if your collection is not read-only, you may run into difficulties.

Sunlight
I'll make it read only of course - thank U.
lbownik
A: 

Sunlight is right, you can just cast it.

Another fix is to double-check that you really need a List<Field>, or whether you can change your internal fields variable to List<IField>.

As long as you only ever use methods on the contents of the list that are on the IField interface, you should be able to do a strightforward swap.

Dan Vinton
+8  A: 

A better solution, IMO, is to change the signature of your method to use a bounded wildcard:

public List<? extends IField> getFields()

This will let the caller treat anything coming "out" of the list as an IField, but it won't let the caller add anything into the list (without casting or warnings), as they don't know what the "real" type of the list is.

Jon Skeet
The downside of this approach is that it forces the caller to handle wildcards. As a general principle I would suggest (and IIRC generics authors have suggested) only using wildcards on method parameters, and avoiding them on return types.
JodaStephen
It depends on the use case, IMO. If the idea is that this really is just a collection to read from, the wildcard makes sense (and exactly expresses what's available). If it's meant to be writable as well, it clearly won't work - and indeed shouldn't.
Jon Skeet
could U look ad this question ?http://stackoverflow.com/questions/314203/overidin-methods-by-return-type-in-java
lbownik
+4  A: 

Don't do it.

A List<Field> is not a List<IField>. You can try to force the compiler into accepting (I thought it was not possible, I wish it was not possible), but that will get you into trouble. The compiler will allow a user to introduce AnotherField deriving from IField into the given List breaking your invariants, and breaking into the type safety that generics provide. Later use of the List<Field> will break as extraction of the strange element will fail the implicit cast to Field where you will not expect it to happen.

If you do need to return a List<IField> instead of List<Field>, then I will recommend generating a new list filled with the same elements. If you can modify your interface go for Jon Skeets solution.

David Rodríguez - dribeas
+2  A: 

If the caller does not need to be able to modify the list:

return Collections.<IField>unmodifiableList(this.fields);
Nicolas Barbier