Преобразовать унаследованный код Java в универсальный - как заменить объект типом? - PullRequest
3 голосов
/ 06 мая 2010

// унаследованный код

void setCacheValue(String name, Object value){
    getServletContext().setAttribute(name, value);
}
Object getCacheValue(String name){
    return getServletContext().getAttribute(name);
}

// поэтому я хочу использовать generic для "безопасности типов"

// first, set method seems working perfectly
<T> void setCacheObject(String name, T value){
    getServletContext().setAttribute(name, value);
}

// тогда возникает проблема

<T> T getCacheValue(String name){    
    // of course, I cannot change servlet class - it returns Object type
    Object value = getServletContext().getAttribute(name);
    // would this work:     
    return  (T) value;
    // this cast is meaningless... but how should I do it?
}

// Это то, чего я хочу достичь в моем clean коде вызова:

{
    double x = 1.2;
    setCacheValue("x", x);
    //...
    // later
    Double value = getCacheValue("x");
    // too bad cannot use primitive type - it cannot handle null

}

Итак, каков правильный путьделать это?

Ответы [ 3 ]

3 голосов
/ 06 мая 2010

Это действительно невозможно. Вам нужно как-то передать «конкретный» T в качестве аргумента метода, чтобы фактический тип был известен во время выполнения. Обычно используемый подход передает его как Class<T>, так что вы можете использовать Class#cast():

<T> T getCacheValue(String name, Class<T> type) {
    return type.cast(getServletContext().getAttribute(name));
}

Вы можете использовать его следующим образом:

Double value = getCacheValue("x", Double.class);
0 голосов
/ 06 мая 2010

На самом деле это тоже компилируется:

public class Test
{
    <T> T getCacheValue(String name){    
        // of course, I cannot change servlet class - it returns Object type
        Object value = getServletContext().getAttribute(name);
        // would this work:     
        return  (T) value;
        // this cast is meaningless... but how should I do it?
    }

    public static void main(String... args)
    {
        Test t = new Test();
        Double double = t.<Double>getCacheValue("Double");
    }
}

Это бессмысленно (возможно, если вы добавите проверку типов), но мне было интересно узнать.

0 голосов
/ 06 мая 2010

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

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

...