Правильный синтаксис универсального метода с несколькими подстановочными знаками? - PullRequest
1 голос
/ 09 марта 2011

У меня проблемы с получением правильного синтаксиса для универсального метода с несколькими подстановочными знаками

Прежде всего, мне нужны два разных подстановочных знака, потому что (хотя я видел, что «?» Можно использовать для обозначения двух разных типов), как компилятор узнает, когда я использую «?» неоднозначно в методе.

Итак, ниже у меня есть очень недопустимая версия, где я использую '*' в качестве второго подстановочного знака (есть ли какой-нибудь другой подстановочный знак, который я могу использовать ???)

Может показаться, что в методе есть ошибка программирования, но я могу создать тип 'T' из типа '*' (у меня есть конструкторы для этого - в основном, берется буфер протокола Google и создается «полноценный объект»). "из этого)

private <T, ? extends Database<*>, * extends GeneratedMessage> T getItem(String key, ? db, Hashtable<String, T> table, String message) throws GadsDataException {
    T returnValue = table.get(key);
    if (returnValue == null) {
        * temp = null;
        try {
            temp = db.get(key);
        }
        catch  (InvalidProtocolBufferException e) {
            throw new GadsDataException( message + key + " and hit: ", e);
        }
        if (temp != null) {
            returnValue = new T(temp);
            table.put(key, returnValue);
        }
    }
    return returnValue;
}

В отчаянии я попробовал версию без каких-либо подстановочных знаков (мне она не нравится, так как она не сохраняет отношения типов, как это делали первые). Но компилятор не слишком заинтересован в этом. Думаю, мне стоит взглянуть на «Трансформер», о котором упоминал другой плакат.

private <T, D, G> T getItem(String key, D db, Hashtable<String, T> table, String message) throws GadsDataException {
        T returnValue = table.get(key);
        if (returnValue == null) {
            G temp = null;
            try {
                temp = db.get(key);
            }
            catch  (InvalidProtocolBufferException e) {
                throw new GadsDataException( message + key + " and hit: ", e);
            }
            if (temp != null) {
                returnValue = new T(temp);
                table.put(key, returnValue);
            }
        }
        return returnValue;
    }

Так что я все еще застрял на конструкторе (как указывали другие авторы). Я попытался сделать компилятор счастливым, создав «искусственный» базовый класс

/**
 * This is created as a base class for all objects that can
 * construct themselves from a Google Protocol Buffer with one
 * parameter.
 * 
 * This is just done for the sake of templatizing the methods
 * inside of the GadsLite API
 *
 */
public class ConstructorOneParameter {

    ConstructorOneParameter(GeneratedMessage G) {
        // don't actually do anything... the derived
        // class does all the work
        // We're doing this just to templatize the GadsLite methods
    }
}

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

private <T extends ConstructorOneParameter, D extends Database<G>, G extends GeneratedMessage> T 
        getItem(String key, D db, Hashtable<String, T> table, String message) throws GadsDataException {
    T returnValue = table.get(key);
    if (returnValue == null) {
        G temp = null;
        try {
            temp = db.get(key);
        }
        catch  (InvalidProtocolBufferException e) {
            throw new GadsDataException( message + key + " and hit: ", e);
        }
        if (temp != null) {
            returnValue = new T(temp);
            table.put(key, returnValue);
        }
    }
    return returnValue;
}

Несколько человек предложили фабрику, поэтому я изменил строку «returnValue = new T (temp);» в "returnValue = MessageObjectFactory create (temp);" Тогда для завода у меня есть:

public class MessageObjectFactory {

    public static <G extends GeneratedMessage, R extends Object> R create(G message) {
        R returnValue = null;
        if (message instanceof ArtccData.Artcc) {
            returnValue = new Artcc((ArtccData.Artcc)message);
        }
        return returnValue;
    }

}

Я просто делаю один тип сейчас в качестве доказательства концепции. К сожалению, несмотря на то, что все является подклассом Object, компилятор недоволен «returnValue = new Artcc (...« строка жаловаться »не может преобразовать Artcc в R.». Есть ли конкретный пример «Transformer Factory»?

Ответы [ 3 ]

1 голос
/ 09 марта 2011

Сначала вы должны найти лучший путь, чем

new T(...)

так как это не разрешено

1 голос
/ 09 марта 2011

Поскольку все мои типы T имеют конструктор вида T(G), я не понимаю, почему я не могу сделать new T(temp).Также я отредактировал свой исходный вопрос, чтобы отобразить проваленный хак, описанный в предыдущем комментарии.

Обобщения Java - это инструмент, гарантирующий безопасность типов, а не создание другого кода в зависимости от параметра.Компилятор удаляет большинства переменных типа, поэтому во время выполнения фактический тип T вообще не известен - таким образом, мы не можем вызвать ни один из его конструкторов (или, кстати, создать массивы этого типа),Таким образом, мы можем использовать универсальный метод (или класс) с типами, которых еще не было при создании метода.

И на самом деле, компилятор не может гарантировать, что все возможные классы имеют такие конструкторы, так как всегдамогут быть более поздние подклассы без.

Итак, в вашем случае вам следует подумать об использовании какого-либо фабричного объекта, который принимает G и возвращает правильный T объект (например, Transformer<G, T> типа, как предложил Анджей.)

1 голос
/ 09 марта 2011

Во-первых, Абсолютно нулевая точка в объявлении подстановочного знака (?) в разделе общих параметров. Этот раздел предназначен для объявления переменных типа, на которые вы будете ссылаться в сигнатуре и теле фактического метода. Если вы поместите здесь подстановочный знак, вы, очевидно, не сможете ссылаться на них - и если вы не обращаетесь к ним, они не входят в общие параметры (поскольку ваш метод не будет меняться в зависимости от их значений).

Вы спрашиваете

как компилятор узнает, когда я использую '?' неоднозначно в методе.

, что я считаю довольно запутанным. Совершенно очевидно, что этого не произойдет, поэтому именно поэтому вы даете имена типов в универсальном блоке параметров!

Итак, учитывая, что вы пытаетесь сделать с подстановочными знаками в первом примере? Почему это не сработает, если вы замените ? на U, а * на V (очевидно, что настоящие буквы - это произвольные имена), как в:

private <T, V extends GeneratedMessage, U extends Database<V>> T getItem(String key, U db, Hashtable<String, T> table, String message) throws GadsDataException {
    ...
    V temp = null;
    ...
}

(Вы можете заметить, что я изменил порядок последних двух параметров - прямые ссылки не допускаются, поэтому V должен появляться перед U, который зависит от него).

Это похоже на ваш второй пример, за исключением того, что он поддерживает ограничения на базу данных и типы параметров сообщения. Что не понравилось компилятору в вашей версии?

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