2011-11-19 17 views
8

He visto una pregunta similar aquí varias veces, pero hay una gran diferencia.Tipo de devolución dinámica en el método Java

En las otras preguntas, el tipo de devolución debe ser determinado por el parámetro. Lo que quiero/necesito hacer es determinar el tipo de devolución por el valor analizado de byte[]. De lo que he reunido, la siguiente podría funcionar:

public Comparable getParam(String param, byte[] data) { 
    if(param.equals("some boolean variable") 
     return data[0] != 0; 
    else(param.equals("some float variable") { 
     //create a new float, f, from some 4 bytes in data 
     return f; 
    } 
    return null; 
} 

Sólo quiero para asegurarse de que esto no tiene la oportunidad de trabajar antes de que la pata nada. Gracias por adelantado.

+1

Usted ** no puede ** devolver 'float' o' boolean' de un método con una firma que dice que devuelve 'Comparable' (que realmente debería ser' Comparable ', por cierto). Solo puede devolver 'Float' o' Boolean', etc. –

+0

quizás una mejor pregunta para mi situación es "¿Hay alguna forma de convertir el tipo de devolución para que el método se pueda invocar sin tener que convertirlo en una variable?" – Jon

+0

No en Java puro. (IIRC, se puede hacer en bytecode de Java, pero podría confundirme con MSIL). –

Respuesta

10

No puede hacerlo. Los tipos de retorno de Java tienen que ser un tipo fundamental fijo o una clase de objeto. Estoy bastante seguro de que lo mejor que puede hacer es devolver un tipo de contenedor que tiene métodos para buscar varios tipos posibles de valores, y una enumeración interna que indica cuál es válida.

--- edit --- ¡después de la corrección de Danieth!

public <Any> Any getParam(boolean b){ 
return((Any)((Boolean)(!b))); 
} 
public <Any> Any getParam(float a) { 
return((Any)((Float)(a+1))); 
} 
public <Any> Any getParam(Object b) { 
return((Any)b); 
} 
public void test(){ 
    boolean foo = getParam(true); 
    float bar = getParam(1.0f); 
    float mumble = getParam(this); // will get a class cast exception 
} 

Todavía se incurre en algunas sanciones para artículos de boxeo y la comprobación de tipos los valores, claro devueltos si su llamada no es consistente con lo que las implementaciones de getParam realmente hacen, obtendrá una clase excepción de lanzamiento

+0

+1, esta es la respuesta correcta. –

+0

¿podría darme un ejemplo? ¿O apuntarme hacia uno? Entiendo lo que dices que debes hacer, pero sería mucho más fácil mirar el código. – Jon

+0

public class genericvalue {String returnStringvalue() {} int returnIntvalue() {}} y así sucesivamente, donde cada método hace lo que sea necesario para producir un valor del tipo deseado. – ddyer

1

Si realmente solo devuelve boolean o float, entonces lo mejor que puede hacer es Object.

Si devuelve objetos variables, debe elegir un tipo de devolución con la superclase menos común. Los primitivos no tienen una superclase, pero se incluirán en representaciones de objeto (como Boolean y Float) que tienen una superclase común de Object.

+1

Casi subí de categoría, pero dices que 'Object' es la superclase común de primitivas. Eso no es cierto en Java. Las primitivas no tienen una superclase común, aunque pueden ser * encasilladas * en equivalentes de tipo de referencia que sí lo hacen. –

+1

Tiene razón en que las primitivas no son Objetos, sino que se incluirán en ellas automáticamente. Estoy actualizando mi respuesta para reflejar esto. – Kane

11

No sé de qué están hablando estas personas. Se pierde la seguridad de tipos, lo cual es una preocupación, pero fácilmente se podría lograr esto con los genéricos ... algo así como:

public <T> T getSomething(...) { } 

o

interface Wrapper<T> { T getObject(); } 

public <T> Wrapper<T> getSomething(...) { } 

Este último promueve la posibilidad de una strategy pattern. Pase los bytes a la estrategia, permita que se ejecute y recupere la salida. Se podría tener una estrategia de bytes, la estrategia de Boole, etc.

abstract class Strategy<T> { 
    final byte[] bytes; 

    Strategy(byte[] bytes) { this.bytes = bytes; } 

    protected abstract T execute(); 
} 

continuación

class BooleanStrategy extends Strategy<Boolean> { 
    public BooleanStrategy(byte[] bytes) { super(bytes); } 

    @Override 
    public Boolean execute() { 
     return bytes[0] != 0; 
    } 

} 

Su código de ejemplo es un caso de uso malo sin embargo y yo no lo recomendaría. Tu método no tiene mucho sentido.

+0

Creo que estás en el buen camino, pero no acabo de entender lo que propones. En la pregunta, Jon tiene un 'byte []' y quiere pasar un String y recuperar un valor que puede asignar a un primitivo sin lanzar. No creo que eso sea realmente posible. Tienes razón, si en lugar de pasar un String, pasas algún objeto más complejo, puedes utilizar genéricos para recuperar el tipo correcto de valor. –

+2

Por otro lado, no hay forma de que pueda implementar su método 'T getSomething()' sin al menos un molde sin verificar, por lo que puede fallar en tiempo de ejecución si se usa incorrectamente (por ejemplo 'Boolean foo = getSomething (" someFloatParam "); '). En ese punto, probablemente sea mejor que solo uses un molde explícito, ya que entonces está claro que podrías obtener una 'ClassCastException' en ese punto. –

18

Esto CAN hacerse. El siguiente código funcionará:

public byte BOOLEAN = 1; 
public byte FLOAT = 2; 
public static <Any> Any getParam(byte[] data) { 
    if (data[0] == BOOLEAN) { 
     return (Any)((Boolean)(boolean)(data[1] != 0)); 
    } else if (data[0] == FLOAT) { 
     return (Any)((Float)(float)data[1]); 
    } else { 
     return null; 
    } 
} 

Mediante el uso de un genérico para el tipo de retorno de cualquier método Java de forma dinámica puede devolver cualquier objeto o tipos primitivos. Puedes nombrar el genérico como quieras, y en este caso lo llamé 'Cualquiera'. Al usar este código evita lanzar el tipo de devolución cuando se llama al método.Se podría utilizar el método de este modo:

byte[] data = new byte[] { 1, 5 }; 
boolean b = getParam(data); 
data = new byte[] { 2, 5 }; 
float f = getParam(data); 

Lo mejor que puede hacer sin este truco está lanzando un objeto de forma manual:

float f = (float)getParam(data); 

Java tipos de retorno dinámico pueden reducir código repetitivo. Aquí está un quick example que escribí en Java 8.

Cuestiones relacionadas