简体   繁体   English

将java遗留代码转换为泛型 - 如何用类型替换Object?

[英]Convert java legacy code to generic - how to replace Object with type?

// legacy code //遗留代码

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

// so I want to use generic for "type safety" //所以我想使用通用的“类型安全”

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

// then, here comes the trouble //然后,麻烦来了

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

// This is what I what to achieve in my clean calling code: //这就是我在干净的调用代码中要实现的目标:

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

} }

So, what is the correct way of doing this? 那么,这样做的正确方法是什么?

That's indeed not possible. 这确实不可能。 You'll need to pass the "concrete" T somehow as method argument so that the actual type is known during runtime. 您需要以某种方式将“具体” T作为方法参数传递,以便在运行时期间知道实际类型。 Commonly used approach is passing it as Class<T> , so that you can make use of Class#cast() : 常用的方法是将它作为Class<T>传递,这样就可以使用Class#cast()

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

You can use it as follows: 您可以按如下方式使用它:

Double value = getCacheValue("x", Double.class);

Map generics support a type on all values of the map, not a different type for specific values. Map泛型支持地图的所有值上的类型,而不是特定值的不同类型。 You can see how to fake it here . 你可以在这里看到如何伪造它。 Basically the idea is you have to have the type safety on the key, where the key has a generic type on it which exists simply to associate with the value. 基本上,这个想法是你必须在密钥上具有类型安全性,其中密钥上有一个泛型类型,它只是为了与值相关联而存在。

At the end of the day you won't be able to do it without an unsafe cast, but you can do it in a way that makes it extremely unlikely that there is a problem with a cast and in a way which is typesafe to the users of your class. 在一天结束时,如果没有不安全的演员阵容,你将无法做到这一点,但你可以这样做,使得演员阵容的问题极不可能,并且对于你班级的用户。

Actually that compiles, too: 实际上也编译:

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

It is kind of pointless (maybe if you add a typecheck) but I found it interesting to know. 这有点毫无意义(也许你添加了一个类型检查),但我发现它很有趣。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM