Тип динамического возврата в Java-методе - PullRequest
12 голосов
/ 19 ноября 2011

Я видел вопрос, похожий на этот, несколько раз здесь, но есть одно большое отличие.

В остальных вопросах тип возвращаемого значения определяется параметром. Что я хочу / нужно сделать, это определить тип возвращаемого значения по проанализированному значению byte[]. Из того, что я собрал, могло сработать следующее:

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

Я просто хочу убедиться, что у этого есть шанс сработать, прежде чем что-то напортачить. Заранее спасибо.

Ответы [ 5 ]

20 голосов
/ 28 августа 2013

Это МОЖЕТ быть сделано.Будет работать следующий код:

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

Используя универсальный тип для возвращаемого типа, любой метод Java может динамически возвращать любой объект или примитивные типы.Вы можете назвать дженерик как угодно, и в этом случае я назвал его «Любой».Используя этот код, вы избегаете приведения типа возврата при вызове метода.Вы можете использовать метод следующим образом:

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

Лучшее, что вы можете сделать без этого трюка, - это приведение объекта вручную:

float f = (float)getParam(data);

Динамические типы возврата Java могут уменьшить шаблон кода.

18 голосов
/ 19 ноября 2011

Я не знаю, о чем говорят эти люди.Вы теряете безопасность типов, что вызывает беспокойство, но вы можете легко сделать это с помощью дженериков ... что-то вроде:

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

или

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

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

Последнее способствует возможности шаблон стратегии .Передайте байты в стратегию, дайте ей исполниться и получите результат.У вас будет байт-стратегия, логическая стратегия и т. Д.

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

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

    protected abstract T execute();
}

затем

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

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

}

Ваш пример кода является плохим вариантом использования, и я бы не рекомендовал его.Ваш метод не имеет особого смысла.

13 голосов
/ 19 ноября 2011

Вы не можете сделать это.Возвращаемые типы Java должны быть либо фиксированным фундаментальным типом, либо классом объекта.Я почти уверен, что лучшее, что вы можете сделать, это вернуть тип-обертку, у которого есть методы для извлечения различных возможных типов значений, и внутреннее перечисление, в котором указано, какое из них допустимо.

--- edit ---после исправления Даниэта!

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
}

Вы по-прежнему будете подвергаться некоторым штрафам за упаковку предметов и проверку типов возвращаемых значений, и, конечно, если ваш вызов не соответствует тому, что фактически делают реализации getParam, вы будетеполучить исключение приведения класса.

1 голос
/ 20 ноября 2018

Мои 2 цента с примером с клиентом Google HTTP:

static public <Any> Any getJson(final String url, final Class<Any> parseAs) throws IOException {
        HttpRequestFactory requestFactory
                = HTTP_TRANSPORT.createRequestFactory(
                (HttpRequest request) -> {
                    request.setParser(new JsonObjectParser(JSON_FACTORY));
                });

        HttpRequest request = requestFactory.buildRequest(HttpMethods.GET, new GenericUrl(url), null);

        return request.execute().parseAs(parseAs);
    }

Можно использовать так:

HashMap<String, Object> out = HttpUtils.getJson( "https://api.qwant.com", HashMap.class);
1 голос
/ 19 ноября 2011

Если вы действительно только возвращаете boolean или float, то лучшее, что вы можете сделать, это Object.

Если вы возвращаете переменные объекты, вы должны выбрать тип возвратас наименее распространенным суперклассом.Примитивы не имеют суперкласса, но они будут упакованы в представления объектов (например, Boolean и Float), которые имеют общий суперкласс Object.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...