java - type - cuestión de genéricos y herencia
java generics bounded wildcards (4)
Cuando instancia un tipo genérico con diferentes argumentos de tipo, las dos instancias no son compatibles con el tipo. Las diferentes instancias de un tipo genérico no son de tipo equivalente en la forma en que una clase que hereda de otra clase es de tipo equivalente a esa clase, incluso cuando los propios argumentos de tipo pueden estar relacionados por herencia. Genericity y polimorfismo son dos características separadas del lenguaje.
Tu código es equivalente a lo siguiente:
// Java defaults unspecified type arguments to Object.
fileHandler<Object, Object> file;
if (...) {
// Error: fileHandler<String, String> is not equivalent to fileHandler<Object, Object>
file = new fileHandler<String, String>();
} else {
// Error: fileHandler<String, String[]> is not equivalent to fileHandler<Object, Object>
file = new fileHandler<String, String[]>();
}
Si realmente desea aislar una interfaz polimórfica que sea independiente de los tipos utilizados para crear una instancia de su clase fileHandler, le sugiero que utilice una interfaz:
interface IFileHandler
{
// If this interface needs to talk about keys and values, it
// does so using only java.lang.Object.
}
public class fileHandler<Key extends Object, Value extends Object>
implements IFileHandler
{
// ...
}
public class A extends fileHandler<String, String>
{
// ...
}
public class B extends fileHandler<String, String[]>
{
// ...
}
IFileHandler file;
if (...) {
file = new A();
} else {
file = new B();
}
Tengo tres clases:
public abstract class fileHandler<Key extends Object, Value extends Object> {
}
public A extends fileHandler<String, String[]> {
}
public B extends fileHandler<String, String> {
}
Ahora en mi función principal hago algo como esto:
fileHandler file= null;
If (<condition>) {
fileHandler = new A();
} else
fileHandler = new B():
}
Pero esto da 2 errores de tiempo de compilación:
- No se puede convertir A en fileHandler
- No se puede convertir B en fileHandler
¿Cómo puedo deshacerme de estos errores ya que no obtengo este error si la clase base no es genérica?
Actualizar:
Mi jerarquía de clase es:
-
class fileHandler<Key, Value> { }
-
class A extends fileHandler<String, String[]> { }
-
class B extends fileHandler<String, String> { }
- clase C que llama a la función
gen(object of A)
o - clase D que llama a la función
gen(object of B)
. - tanto C como D se derivan de la clase abstracta E.
Ahora, ¿cómo debería definir estas funciones en C, D y E?
Di lo siguiente:
MI:
public abstract void gen (fileHandler A) throws exception;
DO:
void gen (fileHandler A) throws exception;
RE:
void gen (fileHandler A) throws exception;
C, D y E dan error fileHandler es tipo raw. Se debe parametrizar la referencia al tipo genérico fileHandler (Key, Value).
El problema es que estás tratando de asignar una instancia al nombre de la clase. Deberías estar diciendo
if (condition) {
file = new A();
} else {
file = new B();
}
"archivo" es la referencia aquí "fileHandler" es el nombre de la clase.
Aclamaciones.
La forma en que decida corregir esta advertencia realmente depende de lo que está tratando de hacer y de cuán estrictamente desea restringir los tipos permitidos para el parámetro de gen()
.
Ejemplo 1
Muy flojo
abstract class E {
public abstract void gen(fileHandler<?,?> A) throws Exception;
}
class C extends E {
@Override
public void gen(fileHandler<?,?> A) throws Exception {}
}
Ejemplo 2
Restringir genérico Key
para ser una String
abstract class E {
public abstract void gen(fileHandler<String,?> A) throws Exception;
}
class C extends E {
@Override
public void gen(fileHandler<String,?> A) throws Exception {}
}
Ejemplo 3
Probablemente desee nombrar el tipo no restringido para que pueda consultarlo.
abstract class E {
public abstract <Value> void gen(fileHandler<String,Value> A) throws Exception;
}
class C extends E {
@Override
public <Value> void gen(fileHandler<String,Value> A) throws Exception {}
}
No obtengo ningún error de compilación ... si soluciono todo el error en el código provisto
class fileHandler<Key, Value> {
}
class A extends fileHandler<String, String[]> {
}
class B extends fileHandler<String, String> {
}
entonces
fileHandler file= null;
if (/* condition */)
{
file = new A();
}
else
{
file = new B();
}