2011-11-19 26 views
8

Widziałem tutaj podobne pytanie, ale jest jedna wielka różnica.Dynamiczny typ zwracania w metodzie Java

W pozostałych pytaniach typ zwrotu należy określić za pomocą parametru. Co chcę/trzeba zrobić, to określić typ zwrotu przez przeanalizowaną wartość byte[]. Z tego co ja zebrane dodaje mógł pracować:

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; 
} 

po prostu chcę się upewnić, że to ma szansę na pracę, zanim cokolwiek się wkręcić. Z góry dziękuję.

+1

Nie możesz ** zwrócić 'float' lub' boolean' z metody z sygnaturą, która mówi, że zwraca 'porównywalne' (które naprawdę powinno być' porównywalne 'przy okazji). Możesz tylko zwrócić 'Float' lub' Boolean', itd. –

+0

Być może lepszym pytaniem dla mojej sytuacji jest "Czy istnieje sposób na wyrzucenie typu zwrotu, aby można było wywołać metodę bez wrzucania do zmiennej?" – Jon

+0

Nie w czystej Javie. (IIRC, można to zrobić w bajtowym kodzie Java, ale mogę się mylić z MSIL.) –

Odpowiedz

10

Nie możesz tego zrobić. Typy zwracane Java muszą być stałym typem podstawowym: lub klasą obiektu. Jestem prawie pewien, że najlepiej jest zwrócić zwinięty typ , który ma metody pobierania różnych możliwych typów wartości oraz wewnętrzne wyliczenie , które określa, który z nich jest poprawny.

--- edytuj --- po korekcie Danietha!

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 
} 

nadal ponosić kary za niektóre przedmioty bokserskie i wpisz sprawdzanie zwróconych wartości, oraz, oczywiście, jeśli połączenie nie jest zgodny z co implementacje getParam faktycznie, dostaniesz klasę rzucić wyjątek.

+0

+1, to jest poprawna odpowiedź. –

+0

możesz podać przykład? Lub wskazać mnie w kierunku jednego? Rozumiem, co chcesz zrobić, ale byłoby o wiele łatwiej spojrzeć na kod. – Jon

+0

public class genericvalue {String returnStringvalue() {} int returnIntvalue() {}} i tak dalej, gdzie każda metoda robi wszystko, aby uzyskać wartość pożądanego typu. – ddyer

1

Jeśli naprawdę zwracasz tylko boolean lub float, najlepszą możliwą czynnością jest Object.

Jeśli zwracasz obiekty zmienne, musisz wybrać typ zwracania z najmniej popularną nadklasą. Prymitywy nie mają superklasy, ale zostaną zapakowane w reprezentacje obiektów (np. Boolean i Float), które mają wspólną nadklasę Object.

+1

Prawie wznowiłem, ale mówisz, że 'Object' jest pospolitą nadklasą prymitywów. To nie jest prawdą w Javie. Prymitywy nie mają wspólnej nadklasy, chociaż mogą być * w pudełku * na równoważne typy odniesienia. –

+1

Masz rację, że prymitywy nie są obiektami, ale zostaną automatycznie umieszczone w tych obiektach. Aktualizuję moją odpowiedź, aby to odzwierciedlić. – Kane

11

Nie wiem, o czym ci ludzie mówią. Tracisz typu bezpieczeństwa, co jest problemem, ale można łatwo osiągnąć to z rodzajowych ... coś jak:

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

lub

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

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

Ta ostatnia sprzyja możliwość wystąpienia strategy pattern. Przekaż bajty do strategii, pozwól jej wykonać i pobrać dane wyjściowe. Można by mieć strategię Byte, Boolean strategię itd

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

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

    protected abstract T execute(); 
} 

następnie

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

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

} 

Twój przykład kod jest zły przypadek użycia chociaż i ja nie polecam go. Twoja metoda nie ma większego sensu.

+0

Myślę, że jesteś na dobrej drodze, ale nie podążam za tym, co proponujesz. W pytaniu Jon ma 'byte []' i chce przekazać ciąg znaków i odzyskać wartość, którą może przypisać prymitywu bez rzutowania. Nie sądzę, żeby to było możliwe. Masz rację, jeśli zamiast przekazywać ciąg, przekazujesz bardziej złożony obiekt, możesz użyć generycznych, by odzyskać właściwą wartość. –

+2

Z drugiej strony, nie ma sposobu, aby zaimplementować swoją metodę 'T getSomething()' bez co najmniej niezaznaczonej obsady, więc potencjalnie zawiodłeś w czasie wykonywania, jeśli jest ona używana niepoprawnie (np. 'Boolean foo = getSomething (" someFloatParam "); '). W tym momencie prawdopodobnie lepiej będzie, jeśli użyjesz wyraźnej obsady, ponieważ wtedy jasne jest, że w tym momencie możesz uzyskać "ClassCastException". –

18

Ten CAN należy wykonać. Poniższy kod zadziała:

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; 
    } 
} 

Używając standardowego dla typu zwracanego, dowolna metoda Java może dynamicznie zwracać dowolny typ obiektów lub prymitywów. Możesz nadać nazwę rodzajową, co chcesz, iw tym przypadku nazwałem ją "Any". Użycie tego kodu zapobiega rzutowaniu typu zwracanego po wywołaniu metody.Można by użyć metody tak:

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

Najlepiej można to zrobić bez tej sztuczki jest ręcznie oddające obiektu:

float f = (float)getParam(data); 

Java typy dynamiczny powrotne może zmniejszyć kod szablonowe. Oto quick example napisałem w języku Java 8.

Powiązane problemy