2008-11-24 11 views
9

¿Cómo puedo hacer este modelo genérico de java?¿Cómo puedo hacer este modelo genérico de java?

public interface IField { 

} 


class Field implements IField { // package private class 

} 

public class Form { 
    private List<Field> fields; 


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

    } 

} 

La instrucción de retorno lanza un error de compilación (sé la razón - He leído el tutorial genéricos), pero sería muy útil para escribir dicho código.

Si declaré "campos" en una lista que necesitaría utilizar una gran cantidad de moldes de campo en otros métodos de una clase de formulario.

¿Puedo forzar a ese maldito compilador a doblar sus reglas y compilar esa declaración de devolución?

Gracias de antemano.

+0

Como nota al margen, this.fields se typoed como this.fiedls y yo no tienen un representante lo suficientemente alto como para editar los mensajes de otras personas. – Powerlord

+0

@R Bemrose - arreglado, gracias. –

Respuesta

17

Una solución mejor, la OMI, es cambiar la firma de su método para utilizar un comodín acotada:

public List<? extends IField> getFields() 

Esto permitirá que la persona que llama a tratar cualquier cosa que venga "fuera" de la lista como iField, pero no permitirá que la persona que llama agregue nada en la lista (sin casting ni advertencias), ya que no sabe cuál es el tipo "real" de la lista.

+1

La desventaja de este enfoque es que obliga a la persona que llama a manejar comodines. Como principio general, sugeriría (y los autores de genéricos de IIRC lo han sugerido) usar únicamente comodines en los parámetros del método y evitarlos en los tipos de devolución. – JodaStephen

+0

Depende del caso de uso, IMO. Si la idea es que esto realmente es solo una colección para leer, el comodín tiene sentido (y expresa exactamente lo que está disponible). Si también debe poder escribirse, claramente no funcionará, y de hecho no debería funcionar. –

+0

¿Podría ver esta pregunta? http://stackoverflow.com/questions/314203/overidin-methods-by-return-type-in-java –

12

Si llega el caso, se puede, porque los genéricos de Java se acaba de injertar, no forma parte del sistema de tipos.

Se puede hacer

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

porque todos List<T> objetos son del mismo tipo subyacente.

Tenga en cuenta que esto permite que cualquiera pueda poner cualquier tipo implementar IField en su lista, así que si su colección no es de sólo lectura, es posible que encuentre dificultades.

+0

Lo haré leer solo, por supuesto, gracias a U. –

0

La luz del sol es correcta, puedes simplemente echarla.

Otra solución es verificar dos veces que realmente necesita un List<Field>, o si puede cambiar su variable interna fields a List<IField>.

Siempre que solo utilice métodos en el contenido de la lista que están en la interfaz IField, debería poder realizar un cambio directo.

5

No lo hagas.

Un List<Field> no es un List<IField>. Puedes intentar obligar al compilador a aceptar (pensé que no era posible, desearía que no fuera posible), pero eso te meterá en problemas. El compilador le permitirá a un usuario introducir otro campo derivado de IField en la Lista dada rompiendo sus invariantes, y penetrando en el tipo de seguridad que proporcionan los genéricos. El uso posterior de List<Field> se interrumpirá a medida que la extracción del elemento extraño fallará en el lanzamiento implícito a Campo, donde no se espera que suceda.

Si necesita devolver un List<IField> en lugar de , le recomendaré generar una nueva lista con los mismos elementos. Si puede modificar su interfaz, vaya a la solución Jon Skeets.

2

Si la persona que llama no tiene que ser capaz de modificar la lista:

return Collections.<IField>unmodifiableList(this.fields); 
Cuestiones relacionadas